From 1c487a278183200c05a61f0f84e7776eef349892 Mon Sep 17 00:00:00 2001 From: logonoff Date: Mon, 7 Jul 2025 15:37:50 -0400 Subject: [PATCH 1/7] CONSOLE-4657: Refactor `edit-yaml` to TypeScript --- .../console-shared/src/utils/sample-utils.ts | 2 +- .../{edit-yaml.jsx => edit-yaml.tsx} | 33 ++++++++++--------- frontend/public/reducers/ols.ts | 1 + 3 files changed, 20 insertions(+), 16 deletions(-) rename frontend/public/components/{edit-yaml.jsx => edit-yaml.tsx} (97%) diff --git a/frontend/packages/console-shared/src/utils/sample-utils.ts b/frontend/packages/console-shared/src/utils/sample-utils.ts index 6d0c5656f49..87900f456e9 100644 --- a/frontend/packages/console-shared/src/utils/sample-utils.ts +++ b/frontend/packages/console-shared/src/utils/sample-utils.ts @@ -382,7 +382,7 @@ export const getResourceSidebarSamples = ( ? yamlSamplesData.map((sample: K8sResourceKind) => { return { id: sample.metadata.uid, - ...sample.spec, + ...(sample.spec as Exclude), }; }) : []; diff --git a/frontend/public/components/edit-yaml.jsx b/frontend/public/components/edit-yaml.tsx similarity index 97% rename from frontend/public/components/edit-yaml.jsx rename to frontend/public/components/edit-yaml.tsx index 70d936b6c63..92db1c94cdb 100644 --- a/frontend/public/components/edit-yaml.jsx +++ b/frontend/public/components/edit-yaml.tsx @@ -1,4 +1,3 @@ -/* eslint-disable tsdoc/syntax */ import * as _ from 'lodash-es'; import * as React from 'react'; import { css } from '@patternfly/react-styles'; @@ -22,12 +21,12 @@ import { useUserSettingsCompatibility, } from '@console/shared'; import PageBody from '@console/shared/src/components/layout/PageBody'; - +import type { editor } from 'monaco-editor/esm/vs/editor/editor.api'; import CodeEditor from '@console/shared/src/components/editor/CodeEditor'; import CodeEditorSidebar from '@console/shared/src/components/editor/CodeEditorSidebar'; import { fold } from '@console/shared/src/components/editor/yaml-editor-utils'; import { downloadYaml } from '@console/shared/src/components/editor/yaml-download-utils'; -import { isYAMLTemplate, getImpersonate } from '@console/dynamic-plugin-sdk'; +import { isYAMLTemplate, getImpersonate, YAMLTemplate } from '@console/dynamic-plugin-sdk'; import { useResolvedExtensions } from '@console/dynamic-plugin-sdk/src/api/useResolvedExtensions'; import { connectToFlags } from '../reducers/connectToFlags'; import { errorModal, managedResourceSaveModal } from './modals'; @@ -48,6 +47,8 @@ import { k8sList, referenceFor, groupVersionFor, + AccessReviewResourceAttributes, + CodeEditorRef, } from '../module/k8s'; import { ConsoleYAMLSampleModel } from '../models'; import { getYAMLTemplates } from '../models/yaml-templates'; @@ -73,8 +74,11 @@ const stateToProps = (state) => ({ const WithYamlTemplates = (Component) => function Comp(props) { const kind = props?.obj?.kind; - const [templateExtensions, resolvedTemplates] = useResolvedExtensions( - React.useCallback((e) => isYAMLTemplate(e) && e.properties.model.kind === kind, [kind]), + const [templateExtensions, resolvedTemplates] = useResolvedExtensions( + React.useCallback( + (e): e is YAMLTemplate => isYAMLTemplate(e) && e.properties.model.kind === kind, + [kind], + ), ); const [showTooltips, setShowTooltips] = useUserSettingsCompatibility( SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY, @@ -121,14 +125,14 @@ const EditYAMLInner = (props) => { const navigate = useNavigate(); const fireTelemetryEvent = useTelemetry(); const [errors, setErrors] = React.useState(null); - const [success, setSuccess] = React.useState(null); + const [success, setSuccess] = React.useState(null); const [initialized, setInitialized] = React.useState(false); const [stale, setStale] = React.useState(false); const [sampleObj, setSampleObj] = React.useState(props.sampleObj); const [showSidebar, setShowSidebar] = React.useState(!!create); const [owner, setOwner] = React.useState(null); - const [notAllowed, setNotAllowed] = React.useState(); - const [displayResults, setDisplayResults] = React.useState(); + const [notAllowed, setNotAllowed] = React.useState(); + const [displayResults, setDisplayResults] = React.useState(); const [resourceObjects, setResourceObjects] = React.useState(); const [editorMounted, setEditorMounted] = React.useState(false); @@ -140,16 +144,16 @@ const EditYAMLInner = (props) => { const closeOLS = () => action(ActionType.CloseOLS); const dispatch = useDispatch(); - const monacoRef = React.useRef(); + const monacoRef = React.useRef(); const editor = React.useRef(); const buttons = React.useRef(); const { t } = useTranslation(); - /** @return {import('monaco-editor').editor.IStandaloneCodeEditor | null} */ - const getEditor = () => { - return monacoRef.current?.editor; - }; + const getEditor = (): editor.IStandaloneCodeEditor | undefined => + monacoRef?.current && 'editor' in monacoRef.current + ? (monacoRef.current as any).editor + : undefined; const getModel = React.useCallback( (obj) => { @@ -215,7 +219,7 @@ const EditYAMLInner = (props) => { } const { name, namespace } = obj.metadata; - const resourceAttributes = { + const resourceAttributes: AccessReviewResourceAttributes = { group: model.apiGroup, resource: model.plural, verb: 'update', @@ -744,7 +748,6 @@ const EditYAMLInner = (props) => { createResources={createResources} displayResults={setDisplayResults} importResources={resourceObjects} - models={models} retryFailed={onRetry} /> ); diff --git a/frontend/public/reducers/ols.ts b/frontend/public/reducers/ols.ts index d9d559908fb..f538ff2db68 100644 --- a/frontend/public/reducers/ols.ts +++ b/frontend/public/reducers/ols.ts @@ -8,6 +8,7 @@ export enum ActionType { type CodeBlock = { id: string; value: string; + triggeredFrom?: any; }; /* Note: Using Reducer and Selector from OLS plugin */ From 26adf84bc491bfd80876829b9b0572f2616e4b9c Mon Sep 17 00:00:00 2001 From: logonoff Date: Mon, 7 Jul 2025 15:40:20 -0400 Subject: [PATCH 2/7] CONSOLE-4654: Add "Copy to clipboard" button for YAML --- frontend/public/components/edit-yaml.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/public/components/edit-yaml.tsx b/frontend/public/components/edit-yaml.tsx index 92db1c94cdb..42c3424012e 100644 --- a/frontend/public/components/edit-yaml.tsx +++ b/frontend/public/components/edit-yaml.tsx @@ -822,6 +822,7 @@ const EditYAMLInner = (props) => {
{showReplaceCodeModal && } Date: Mon, 7 Jul 2025 16:50:27 -0400 Subject: [PATCH 3/7] CONSOLE-4499: Add option to toggle sticky headers --- .../components/editor/CodeEditorToolbar.tsx | 17 +- .../console-shared/src/constants/common.ts | 2 + frontend/public/components/edit-yaml.tsx | 86 +++++---- .../modals/edit-yaml-settings-modal.tsx | 172 ++++++++++++++++++ 4 files changed, 225 insertions(+), 52 deletions(-) create mode 100644 frontend/public/components/modals/edit-yaml-settings-modal.tsx diff --git a/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx b/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx index 3d91ef5a26f..6d530d09847 100644 --- a/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx +++ b/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Button, Flex, FlexItem } from '@patternfly/react-core'; +import { Button, Flex } from '@patternfly/react-core'; import { MagicIcon } from '@patternfly/react-icons'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; @@ -37,13 +37,14 @@ export const CodeEditorToolbar: React.FC = ({ <> - - {toolbarLinks && - toolbarLinks.map((link, index) => ( - // eslint-disable-next-line react/no-array-index-key - {link} - ))} - + {toolbarLinks && ( + + {toolbarLinks} + + )} ); }; diff --git a/frontend/packages/console-shared/src/constants/common.ts b/frontend/packages/console-shared/src/constants/common.ts index 4cf60625252..b5184f0dccb 100644 --- a/frontend/packages/console-shared/src/constants/common.ts +++ b/frontend/packages/console-shared/src/constants/common.ts @@ -48,6 +48,8 @@ export const COLUMN_MANAGEMENT_LOCAL_STORAGE_KEY = `${STORAGE_PREFIX}/table-colu export const LOG_WRAP_LINES_USERSETTINGS_KEY = `${USERSETTINGS_PREFIX}.log.wrapLines`; export const SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY = `${USERSETTINGS_PREFIX}.showYAMLEditorTooltips`; export const SHOW_YAML_EDITOR_TOOLTIPS_LOCAL_STORAGE_KEY = `${STORAGE_PREFIX}/showYAMLEditorTooltips`; +export const SHOW_YAML_EDITOR_STICKY_SCROLL_USER_SETTING_KEY = `${USERSETTINGS_PREFIX}.showYAMLEditorStickyScroll`; +export const SHOW_YAML_EDITOR_STICKY_SCROLL_LOCAL_STORAGE_KEY = `${STORAGE_PREFIX}/showYAMLEditorStickyScroll`; export const SHOW_FULL_LOG_USERSETTINGS_KEY = `${USERSETTINGS_PREFIX}.show.full.log`; // Bootstrap user for OpenShift 4.0 clusters (kube:admin) export const KUBE_ADMIN_USERNAMES = ['kube:admin']; diff --git a/frontend/public/components/edit-yaml.tsx b/frontend/public/components/edit-yaml.tsx index 42c3424012e..eb371445dc3 100644 --- a/frontend/public/components/edit-yaml.tsx +++ b/frontend/public/components/edit-yaml.tsx @@ -15,11 +15,15 @@ import { getBadgeFromType, withPostFormSubmissionCallback, getResourceSidebarSamples, - SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY, - SHOW_YAML_EDITOR_TOOLTIPS_LOCAL_STORAGE_KEY, useTelemetry, useUserSettingsCompatibility, } from '@console/shared'; +import { + SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY, + SHOW_YAML_EDITOR_TOOLTIPS_LOCAL_STORAGE_KEY, + SHOW_YAML_EDITOR_STICKY_SCROLL_USER_SETTING_KEY, + SHOW_YAML_EDITOR_STICKY_SCROLL_LOCAL_STORAGE_KEY, +} from '@console/shared/src/constants/common'; import PageBody from '@console/shared/src/components/layout/PageBody'; import type { editor } from 'monaco-editor/esm/vs/editor/editor.api'; import CodeEditor from '@console/shared/src/components/editor/CodeEditor'; @@ -56,6 +60,7 @@ import { findOwner } from '../module/k8s/managed-by'; import { ClusterServiceVersionModel } from '@console/operator-lifecycle-manager/src/models'; import { definitionFor } from '../module/k8s/swagger'; import { ImportYAMLResults } from './import-yaml-results'; +import { EditYamlSettingsModal } from './modals/edit-yaml-settings-modal'; const generateObjToLoad = (templateExtensions, kind, id, yaml, namespace = 'default') => { const sampleObj = safeLoad(yaml ? yaml : getYAMLTemplates(templateExtensions).getIn([kind, id])); @@ -80,22 +85,11 @@ const WithYamlTemplates = (Component) => [kind], ), ); - const [showTooltips, setShowTooltips] = useUserSettingsCompatibility( - SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY, - SHOW_YAML_EDITOR_TOOLTIPS_LOCAL_STORAGE_KEY, - true, - true, - ); return !resolvedTemplates ? ( ) : ( - + ); }; @@ -110,7 +104,6 @@ const EditYAMLInner = (props) => { customClass, onChange = () => null, models, - showTooltips, download: canDownload = true, header, genericYAML = false, @@ -136,6 +129,20 @@ const EditYAMLInner = (props) => { const [resourceObjects, setResourceObjects] = React.useState(); const [editorMounted, setEditorMounted] = React.useState(false); + const [showTooltips] = useUserSettingsCompatibility( + SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY, + SHOW_YAML_EDITOR_TOOLTIPS_LOCAL_STORAGE_KEY, + true, + true, + ); + + const [stickyScrollEnabled] = useUserSettingsCompatibility( + SHOW_YAML_EDITOR_STICKY_SCROLL_USER_SETTING_KEY, + SHOW_YAML_EDITOR_STICKY_SCROLL_LOCAL_STORAGE_KEY, + true, + true, + ); + const [callbackCommand, setCallbackCommand] = React.useState(''); const [showReplaceCodeModal, setShowReplaceCodeModal] = React.useState(false); const [olsCode, setOLSCode] = React.useState(''); @@ -719,10 +726,6 @@ const EditYAMLInner = (props) => { window.dispatchEvent(new Event('sidebar_toggle')); }; - const toggleShowTooltips = (event, checked) => { - props.setShowTooltips(checked); - }; - const sanitizeYamlContent = (id, yaml, kind) => { const contentObj = getYamlContent_(id, yaml, kind); const sanitizedYaml = convertObjToYAMLString(contentObj); @@ -732,16 +735,13 @@ const EditYAMLInner = (props) => { React.useEffect(() => { editorMounted && getEditor()?.updateOptions({ hover: { enabled: showTooltips } }); - }, [showTooltips, editorMounted]); + editorMounted && getEditor()?.updateOptions({ stickyScroll: { enabled: stickyScrollEnabled } }); + }, [showTooltips, stickyScrollEnabled, editorMounted]); if (!create && !props.obj) { return ; } - const klass = css('co-file-dropzone-container', { - 'co-file-dropzone--drop-over': isOver, - }); - if (displayResults) { return ( { const showSchema = definition && !_.isEmpty(definition.properties); const hasSidebarContent = showSchema || (create && !_.isEmpty(samples)) || !_.isEmpty(snippets); const sidebarSwitch = hasSidebarContent && ( - + <> +
+ + ); - const tooltipSwitch = ( - - ); + const settingsModal = ; const editYamlComponent = (
{canDrop && ( -
+

{t('public~Drop file here')}

)} @@ -826,7 +824,7 @@ const EditYAMLInner = (props) => { ref={monacoRef} options={options} showShortcuts={!genericYAML} - toolbarLinks={sidebarSwitch ? [tooltipSwitch, sidebarSwitch] : [tooltipSwitch]} + toolbarLinks={sidebarSwitch ? [settingsModal, sidebarSwitch] : [settingsModal]} onChange={onChange} onSave={() => (allowMultiple ? saveAll() : save())} onEditorDidMount={() => setEditorMounted(true)} diff --git a/frontend/public/components/modals/edit-yaml-settings-modal.tsx b/frontend/public/components/modals/edit-yaml-settings-modal.tsx new file mode 100644 index 00000000000..53c5713d912 --- /dev/null +++ b/frontend/public/components/modals/edit-yaml-settings-modal.tsx @@ -0,0 +1,172 @@ +import { CodeEditorControl } from '@patternfly/react-code-editor'; +import { createIcon } from '@patternfly/react-icons/dist/esm/createIcon'; +import { useUserSettingsCompatibility } from '@console/shared/src/hooks/useUserSettingsCompatibility'; +import { + Content, + Flex, + FlexItem, + Modal, + ModalBody, + ModalHeader, + Split, + SplitItem, + Switch, +} from '@patternfly/react-core'; +import { CogIcon } from '@patternfly/react-icons'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY, + SHOW_YAML_EDITOR_TOOLTIPS_LOCAL_STORAGE_KEY, + SHOW_YAML_EDITOR_STICKY_SCROLL_USER_SETTING_KEY, + SHOW_YAML_EDITOR_STICKY_SCROLL_LOCAL_STORAGE_KEY, +} from '@console/shared/src/constants/common'; + +/**! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free + * Copyright 2025 Fonticons, Inc. + */ +const IBeamCursorIcon = createIcon({ + name: 'IBeamCursorIcon', + width: 256, + height: 512, + svgPath: + 'M.1 29.3C-1.4 47 11.7 62.4 29.3 63.9l8 .7C70.5 67.3 96 95 96 128.3L96 224l-32 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l32 0 0 95.7c0 33.3-25.5 61-58.7 63.8l-8 .7C11.7 449.6-1.4 465 .1 482.7s16.9 30.7 34.5 29.2l8-.7c34.1-2.8 64.2-18.9 85.4-42.9c21.2 24 51.2 40 85.4 42.9l8 .7c17.6 1.5 33.1-11.6 34.5-29.2s-11.6-33.1-29.2-34.5l-8-.7C185.5 444.7 160 417 160 383.7l0-95.7 32 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-32 0 0-95.7c0-33.3 25.5-61 58.7-63.8l8-.7c17.6-1.5 30.7-16.9 29.2-34.5S239-1.4 221.3 .1l-8 .7C179.2 3.6 149.2 19.7 128 43.7c-21.2-24-51.2-40-85.4-42.9l-8-.7C17-1.4 1.6 11.7 .1 29.3z', +}); + +/**! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free + * Copyright 2025 Fonticons, Inc. + */ +const ComputerMouseIcon = createIcon({ + name: 'ComputerMouseIcon', + width: 384, + height: 512, + svgPath: + 'M0 192l176 0L176 0 160 0C71.6 0 0 71.6 0 160l0 32zm0 32L0 352c0 88.4 71.6 160 160 160l64 0c88.4 0 160-71.6 160-160l0-128-192 0L0 224zm384-32l0-32C384 71.6 312.4 0 224 0L208 0l0 192 176 0z', +}); + +interface ConfigModalItemProps { + title: string; + description: string; + checked?: boolean; + setChecked: (checked: boolean) => void; + Icon?: React.ComponentType; +} + +const ConfigModalItem: React.FCC = ({ + title, + description, + checked, + setChecked, + Icon = CogIcon, +}) => { + const { t } = useTranslation('public'); + + return ( + + + + + + + + {title} + {description} + + + + + { + setChecked(c); + }} + aria-label={title} + className="pf-v6-u-mt-sm" + isChecked={checked} + /> + + + ); +}; + +const TooltipConfigItem = () => { + const { t } = useTranslation('public'); + const [showTooltips, setShowTooltips] = useUserSettingsCompatibility( + SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY, + SHOW_YAML_EDITOR_TOOLTIPS_LOCAL_STORAGE_KEY, + true, + ); + + return ( + + ); +}; + +const StickyScrollConfigItem = () => { + const { t } = useTranslation('public'); + const [showStickyScroll, setShowStickyScroll] = useUserSettingsCompatibility( + SHOW_YAML_EDITOR_STICKY_SCROLL_USER_SETTING_KEY, + SHOW_YAML_EDITOR_STICKY_SCROLL_LOCAL_STORAGE_KEY, + true, + ); + + return ( + + ); +}; + +const EDIT_YAML_SETTINGS_MODAL_ID = 'edit-yaml-settings-modal'; + +export const EditYamlSettingsModal: React.FCC = () => { + const { t } = useTranslation('public'); + const [isModalOpen, setIsModalOpen] = React.useState(false); + + return ( + <> + setIsModalOpen(!isModalOpen)} + ouiaId={EDIT_YAML_SETTINGS_MODAL_ID} + variant="small" + aria-labelledby={`${EDIT_YAML_SETTINGS_MODAL_ID}-title`} + aria-describedby={`${EDIT_YAML_SETTINGS_MODAL_ID}-body`} + > + + + + + + + + + } + aria-label={t('Editor settings')} + tooltipProps={{ content: t('Editor settings') }} + onClick={() => setIsModalOpen(true)} + /> + + ); +}; From 47cc8c11bbeae15c1c2b0a253e0a1fdc131dc923 Mon Sep 17 00:00:00 2001 From: logonoff Date: Mon, 7 Jul 2025 17:07:57 -0400 Subject: [PATCH 4/7] CONSOLE-4656: Add fullscreen EditYaml Update edit-yaml.tsx --- .../components/editor/CodeEditorToolbar.tsx | 1 + frontend/public/components/_edit-yaml.scss | 4 +++ frontend/public/components/edit-yaml.tsx | 36 ++++++++++++++++--- .../modals/edit-yaml-settings-modal.tsx | 7 +++- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx b/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx index 6d530d09847..9aaa7e49c49 100644 --- a/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx +++ b/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx @@ -40,6 +40,7 @@ export const CodeEditorToolbar: React.FC = ({ {toolbarLinks && ( {toolbarLinks} diff --git a/frontend/public/components/_edit-yaml.scss b/frontend/public/components/_edit-yaml.scss index 84aeca368a8..4530b105fa1 100644 --- a/frontend/public/components/_edit-yaml.scss +++ b/frontend/public/components/_edit-yaml.scss @@ -7,6 +7,10 @@ position: relative; } +.yaml-editor__fullscreen { + background-color: var(--pf-t--global--background--color--secondary--default); +} + .yaml-editor__buttons { padding-top: $pf-v6-global-gutter-y; } diff --git a/frontend/public/components/edit-yaml.tsx b/frontend/public/components/edit-yaml.tsx index eb371445dc3..642c72ece19 100644 --- a/frontend/public/components/edit-yaml.tsx +++ b/frontend/public/components/edit-yaml.tsx @@ -30,6 +30,7 @@ import CodeEditor from '@console/shared/src/components/editor/CodeEditor'; import CodeEditorSidebar from '@console/shared/src/components/editor/CodeEditorSidebar'; import { fold } from '@console/shared/src/components/editor/yaml-editor-utils'; import { downloadYaml } from '@console/shared/src/components/editor/yaml-download-utils'; +import { useFullscreen } from '@console/shared/src/hooks/useFullscreen'; import { isYAMLTemplate, getImpersonate, YAMLTemplate } from '@console/dynamic-plugin-sdk'; import { useResolvedExtensions } from '@console/dynamic-plugin-sdk/src/api/useResolvedExtensions'; import { connectToFlags } from '../reducers/connectToFlags'; @@ -61,6 +62,9 @@ import { ClusterServiceVersionModel } from '@console/operator-lifecycle-manager/ import { definitionFor } from '../module/k8s/swagger'; import { ImportYAMLResults } from './import-yaml-results'; import { EditYamlSettingsModal } from './modals/edit-yaml-settings-modal'; +import { CodeEditorControl } from '@patternfly/react-code-editor'; +import { CompressIcon } from '@patternfly/react-icons/dist/js/icons/compress-icon'; +import { ExpandIcon } from '@patternfly/react-icons/dist/js/icons/expand-icon'; const generateObjToLoad = (templateExtensions, kind, id, yaml, namespace = 'default') => { const sampleObj = safeLoad(yaml ? yaml : getYAMLTemplates(templateExtensions).getIn([kind, id])); @@ -128,6 +132,7 @@ const EditYAMLInner = (props) => { const [displayResults, setDisplayResults] = React.useState(); const [resourceObjects, setResourceObjects] = React.useState(); const [editorMounted, setEditorMounted] = React.useState(false); + const [fullscreenRef, toggleFullscreen, isFullscreen, canUseFullScreen] = useFullscreen(); const [showTooltips] = useUserSettingsCompatibility( SHOW_YAML_EDITOR_TOOLTIPS_USER_SETTING_KEY, @@ -776,7 +781,23 @@ const EditYAMLInner = (props) => { ); - const settingsModal = ; + const settingsModal = ( + { + return isFullscreen ? fullscreenRef.current : document.body; + }} + /> + ); + + const fullscreenButton = ( + : } + /> + ); const editYamlComponent = (
@@ -811,7 +832,10 @@ const EditYAMLInner = (props) => { )} -
+
{ isCopyEnabled={canDownload} ref={monacoRef} options={options} - showShortcuts={!genericYAML} - toolbarLinks={sidebarSwitch ? [settingsModal, sidebarSwitch] : [settingsModal]} + showShortcuts={!genericYAML && !isFullscreen} + toolbarLinks={ + sidebarSwitch + ? [settingsModal, fullscreenButton, sidebarSwitch] + : [settingsModal, fullscreenButton] + } onChange={onChange} onSave={() => (allowMultiple ? saveAll() : save())} onEditorDidMount={() => setEditorMounted(true)} diff --git a/frontend/public/components/modals/edit-yaml-settings-modal.tsx b/frontend/public/components/modals/edit-yaml-settings-modal.tsx index 53c5713d912..7d3c78915e9 100644 --- a/frontend/public/components/modals/edit-yaml-settings-modal.tsx +++ b/frontend/public/components/modals/edit-yaml-settings-modal.tsx @@ -136,7 +136,11 @@ const StickyScrollConfigItem = () => { const EDIT_YAML_SETTINGS_MODAL_ID = 'edit-yaml-settings-modal'; -export const EditYamlSettingsModal: React.FCC = () => { +interface EditYamlSettingsModalProps { + appendTo?: React.ComponentProps['appendTo']; +} + +export const EditYamlSettingsModal: React.FCC = ({ appendTo }) => { const { t } = useTranslation('public'); const [isModalOpen, setIsModalOpen] = React.useState(false); @@ -147,6 +151,7 @@ export const EditYamlSettingsModal: React.FCC = () => { onClose={() => setIsModalOpen(!isModalOpen)} ouiaId={EDIT_YAML_SETTINGS_MODAL_ID} variant="small" + appendTo={appendTo} aria-labelledby={`${EDIT_YAML_SETTINGS_MODAL_ID}-title`} aria-describedby={`${EDIT_YAML_SETTINGS_MODAL_ID}-body`} > From 664a8be517fa76aee98867822b63e0d275b36db2 Mon Sep 17 00:00:00 2001 From: logonoff Date: Tue, 8 Jul 2025 11:09:21 -0400 Subject: [PATCH 5/7] CONSOLE-4499: Change toolbar switches to buttons --- .../src/extensions/console-types.ts | 4 +- .../locales/en/console-shared.json | 2 + .../src/components/editor/CodeEditor.tsx | 4 +- .../components/editor/CodeEditorToolbar.tsx | 47 +++++++--------- .../components/editor/ShortcutsPopover.tsx | 53 ++++++++++--------- .../components/editor/ToggleSidebarButton.tsx | 48 +++++++++++++++++ .../__tests__/CodeEditorToolbar.spec.tsx | 27 +++++----- .../formik-fields/CodeEditorField.tsx | 14 ++--- .../console-shared/src/hooks/useFullscreen.ts | 33 +++++++----- frontend/public/components/edit-yaml.tsx | 23 ++++---- frontend/public/locales/en/public.json | 10 +++- 11 files changed, 161 insertions(+), 104 deletions(-) create mode 100644 frontend/packages/console-shared/src/components/editor/ToggleSidebarButton.tsx diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/extensions/console-types.ts b/frontend/packages/console-dynamic-plugin-sdk/src/extensions/console-types.ts index 2e1f3decbd9..32900b5367b 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/extensions/console-types.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/extensions/console-types.ts @@ -659,8 +659,10 @@ export type CodeEditorToolbarProps = { // Omit the ref as we have our own ref type, which is completely different export type BasicCodeEditorProps = Partial>; -export type CodeEditorProps = Omit & +export type CodeEditorProps = Omit & CodeEditorToolbarProps & { + /** Additional props to override the default popover properties */ + shortcutsPopoverProps?: Partial; /** Code displayed in code editor. */ value?: string; /** Minimum editor height in valid CSS height values. */ diff --git a/frontend/packages/console-shared/locales/en/console-shared.json b/frontend/packages/console-shared/locales/en/console-shared.json index 0a720d3fe7c..37237ca57e4 100644 --- a/frontend/packages/console-shared/locales/en/console-shared.json +++ b/frontend/packages/console-shared/locales/en/console-shared.json @@ -124,6 +124,8 @@ "View document outline": "View document outline", "View property descriptions": "View property descriptions", "Save": "Save", + "Hide sidebar": "Hide sidebar", + "Show sidebar": "Show sidebar", "Restricted access": "Restricted access", "You don't have access to this section due to cluster policy": "You don't have access to this section due to cluster policy", "Error details": "Error details", diff --git a/frontend/packages/console-shared/src/components/editor/CodeEditor.tsx b/frontend/packages/console-shared/src/components/editor/CodeEditor.tsx index 29015c0ee4e..c588bdba5be 100644 --- a/frontend/packages/console-shared/src/components/editor/CodeEditor.tsx +++ b/frontend/packages/console-shared/src/components/editor/CodeEditor.tsx @@ -15,7 +15,7 @@ const CodeEditor = React.forwardRef((props, ref) const [monacoRef, setMonacoRef] = React.useState(null); const [usesValue] = React.useState(value !== undefined); - const shortcutPopover = useShortcutPopover(); + const shortcutPopover = useShortcutPopover(props?.shortcutsPopoverProps); const editorDidMount: EditorDidMount = React.useCallback( (editor, monaco) => { @@ -55,7 +55,7 @@ const CodeEditor = React.forwardRef((props, ref) // do not render toolbar if the component is null const ToolbarLinks = React.useMemo(() => { return showShortcuts || toolbarLinks?.length ? ( - + ) : undefined; }, [toolbarLinks, showShortcuts]); diff --git a/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx b/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx index 9aaa7e49c49..b2e7549bdb3 100644 --- a/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx +++ b/frontend/packages/console-shared/src/components/editor/CodeEditorToolbar.tsx @@ -1,51 +1,40 @@ -import * as React from 'react'; -import { Button, Flex } from '@patternfly/react-core'; +import { Button, Tooltip } from '@patternfly/react-core'; import { MagicIcon } from '@patternfly/react-icons'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; import { action } from 'typesafe-actions'; import { CodeEditorToolbarProps } from '@console/dynamic-plugin-sdk'; import { ActionType } from '@console/internal/reducers/ols'; -import { useOLSConfig } from '../../hooks/ols-hook'; +import { useOLSConfig } from '@console/shared/src/hooks/ols-hook'; +import { useIsFullscreen } from '@console/shared/src/hooks/useFullscreen'; -export const AskOpenShiftLightspeedButton: React.FC = () => { +export const AskOpenShiftLightspeedButton: React.FCC = () => { const { t } = useTranslation('console-shared'); const openOLS = () => action(ActionType.OpenOLS); const showLightspeedButton = useOLSConfig(); const dispatch = useDispatch(); + const isFullscreen = useIsFullscreen(); return showLightspeedButton ? ( - + +