Skip to content

Commit

Permalink
Merge pull request #1141 from upalatucci/editor-highlight
Browse files Browse the repository at this point in the history
Bug 2167608: highlight parts
  • Loading branch information
openshift-merge-robot committed Mar 29, 2023
2 parents c3c77a3 + d5ab3e0 commit 223de4f
Show file tree
Hide file tree
Showing 17 changed files with 201 additions and 13 deletions.
7 changes: 6 additions & 1 deletion src/utils/components/EnvironmentEditor/EnvironmentForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useImmer } from 'use-immer';

import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { Button, Form } from '@patternfly/react-core';
import { PlusCircleIcon } from '@patternfly/react-icons';

Expand Down Expand Up @@ -60,7 +61,11 @@ const EnvironmentForm: FC<EnvironmentFormProps> = ({ vm, onEditChange, updateVM
if (!loaded) return <EnvironmentFormSkeleton />;

return (
<SidebarEditor<V1VirtualMachine> resource={temporaryVM} onChange={setTemporaryVM}>
<SidebarEditor<V1VirtualMachine>
resource={temporaryVM}
onChange={setTemporaryVM}
pathsToHighlight={PATHS_TO_HIGHLIGHT.ENV_TAB}
>
<EnvironmentFormTitle />
<Form className="environment-form__form">
{environments.length !== 0 && (
Expand Down
6 changes: 6 additions & 0 deletions src/utils/components/SidebarEditor/SidebarEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { ReactNode, Suspense, useContext, useMemo, useState } from 'react';
import { dump } from 'js-yaml';

import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { K8sResourceCommon, YAMLEditor } from '@openshift-console/dynamic-plugin-sdk';
import {
Alert,
Expand All @@ -20,6 +21,7 @@ import {
import Loading from '../Loading/Loading';

import { SidebarEditorContext } from './SidebarEditorContext';
import { useEditorHighlighter } from './useEditorHighlighter';
import { safeLoad } from './utils';

import './sidebar-editor.scss';
Expand All @@ -29,13 +31,15 @@ type SidebarEditorProps<Resource> = {
onResourceUpdate?: (newResource: Resource) => Promise<Resource | void>;
children: ReactNode | ReactNode[] | ((resource: Resource) => ReactNode);
onChange?: (resource: Resource) => void;
pathsToHighlight?: string[];
};

const SidebarEditor = <Resource extends K8sResourceCommon>({
children,
resource,
onResourceUpdate,
onChange,
pathsToHighlight = PATHS_TO_HIGHLIGHT.DEFAULT,
}: SidebarEditorProps<Resource>): JSX.Element => {
const [editableYAML, setEditableYAML] = useState('');
const [loading, setLoading] = useState(false);
Expand All @@ -50,6 +54,7 @@ const SidebarEditor = <Resource extends K8sResourceCommon>({

const { showEditor, isEditable } = useContext(SidebarEditorContext);
const editedResource = safeLoad<Resource>(editableYAML);
const editorRef = useEditorHighlighter(editableYAML, pathsToHighlight, showEditor);

const changeResource = (newValue: string) => {
setEditableYAML(newValue);
Expand Down Expand Up @@ -95,6 +100,7 @@ const SidebarEditor = <Resource extends K8sResourceCommon>({
onChange={changeResource}
onSave={() => onUpdate(editedResource)}
options={{ readOnly: !isEditable }}
ref={editorRef}
/>
</Suspense>
</StackItem>
Expand Down
39 changes: 39 additions & 0 deletions src/utils/components/SidebarEditor/useEditorHighlighter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useEffect, useRef, useState } from 'react';

import { YAMLEditorRef } from '@openshift-console/dynamic-plugin-sdk';

import { createSelection, getLinesToHighlight } from './utils';

export const useEditorHighlighter = (
editableYAML: string,
pathsToHighlight: string[],
showEditor: boolean,
) => {
const [editor, setEditor] = useState<YAMLEditorRef['editor']>();
const isHighlighed = useRef(false);

useEffect(() => {
isHighlighed.current = false;
}, [pathsToHighlight, showEditor]);

useEffect(() => {
const highlightPaths = async () => {
if (editor && editableYAML && pathsToHighlight && !isHighlighed.current) {
isHighlighed.current = true;
const ranges = getLinesToHighlight(editableYAML, pathsToHighlight);

await editor.getAction('editor.foldAll').run();

const selections = ranges.map((range) => createSelection(range));

editor.setSelections(selections);
await editor.getAction('editor.unfoldRecursively').run();
setTimeout(() => editor.revealLineInCenter(ranges.at(-1).start), 500);
}
};

highlightPaths();
}, [editableYAML, editor, pathsToHighlight]);

return (ref: YAMLEditorRef) => setEditor(ref?.editor);
};
61 changes: 61 additions & 0 deletions src/utils/components/SidebarEditor/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,64 @@ export const safeLoad = <Resource>(value: string): Resource | undefined => {
return;
}
};

export type LineRange = { start: number; end: number };

const getLineFromPath = (resourceYAML: string, path): LineRange => {
const yamlLines = resourceYAML.split('\n');
const range = { start: 0, end: yamlLines.length - 1 };

const properties = path.split('.');

for (const propertyDepth in properties) {
const property = properties[propertyDepth];

// at every iteration, go one level deeper, remove initial indentation for that range.
const replaceIndentationRegex = new RegExp(`^[ ]{${2 * parseInt(propertyDepth)}}`);

const rangeLines = yamlLines
.slice(range.start + 1, range.end)
.map((line) => line.replace(replaceIndentationRegex, ''));

// find the property
const startPropertyRange = rangeLines.findIndex((line) => line.startsWith(`${property}:`));

// find next property at same depth level
let rangeLength = rangeLines
.slice(startPropertyRange + 1)
.findIndex((line) => line.match(/^[A-z]+:/g));

if (rangeLength === -1) rangeLength = rangeLines.length - startPropertyRange;

// property not found
if (startPropertyRange === -1) return undefined;

range.start += startPropertyRange + 1;

range.end = range.start + rangeLength;
}

// editor lines starts from 1, array starts from 0
range.start += 1;
range.end += 1;
return range;
};

export const getLinesToHighlight = (
resourceYAML: string,
pathsToHighlight: string[],
): LineRange[] =>
pathsToHighlight
.map((path) => getLineFromPath(resourceYAML, path))
.filter((highlightLine) => !!highlightLine);

export const createSelection = (range: LineRange) => ({
startLineNumber: range.start,
startColumn: 0,
endLineNumber: range.end + 1,
endColumn: 0,
selectionStartLineNumber: range.start,
selectionStartColumn: 0,
positionLineNumber: range.end + 1,
positionColumn: 0,
});
22 changes: 22 additions & 0 deletions src/utils/resources/vm/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
export const NO_DATA_DASH = '-';

export const MILLISECONDS_TO_SECONDS_MULTIPLIER = 1000;

export const PATHS_TO_HIGHLIGHT = {
DETAILS_TAB: [
'spec.template.metadata.annotations',
'spec.template.metadata.labels',
'spec.template.spec.domain.cpu',
'spec.template.spec.domain.resources.requests',
'metadata.labels',
'metadata.annotations',
],
ENV_TAB: ['spec.template.spec.domain.devices.disks', 'spec.template.spec.volumes'],
DISKS_TAB: ['spec.template.spec.domain.devices.disks', 'spec.template.spec.volumes'],
NETWORK_TAB: ['spec.template.spec.networks', 'spec.template.spec.domain.devices.interfaces'],
SCHEDULING_TAB: [
'spec.template.spec.affinity',
'spec.template.spec.tolerations',
'spec.template.spec.nodeSelector',
'spec.template.metadata.annotations',
],
SCRIPTS_TAB: ['spec.template.spec.volumes', 'spec.template.spec.accessCredentials'],
DEFAULT: ['spec.template.spec.domain.devices.disks', 'spec.template.spec.volumes'],
};
7 changes: 6 additions & 1 deletion src/views/catalog/wizard/tabs/disks/WizardDisksTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEdito
import SidebarEditorSwitch from '@kubevirt-utils/components/SidebarEditor/SidebarEditorSwitch';
import WindowsDrivers from '@kubevirt-utils/components/WindowsDrivers/WindowsDrivers';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { ensurePath } from '@kubevirt-utils/utils/utils';
import {
ListPageBody,
Expand Down Expand Up @@ -36,7 +37,11 @@ const WizardDisksTab: WizardTab = ({ vm, loaded, updateVM, tabsData, updateTabsD
return (
<div className="wizard-disk-tab">
<ListPageBody>
<SidebarEditor resource={vm} onResourceUpdate={(newVM) => updateVM(newVM)}>
<SidebarEditor
resource={vm}
onResourceUpdate={(newVM) => updateVM(newVM)}
pathsToHighlight={PATHS_TO_HIGHLIGHT.DISKS_TAB}
>
<Flex>
<FlexItem>
<ListPageCreateButton
Expand Down
7 changes: 6 additions & 1 deletion src/views/catalog/wizard/tabs/metadata/WizardMetadataTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useModal } from '@kubevirt-utils/components/ModalProvider/ModalProvider
import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEditor';
import SidebarEditorSwitch from '@kubevirt-utils/components/SidebarEditor/SidebarEditorSwitch';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { DescriptionList, PageSection, pluralize } from '@patternfly/react-core';

import { WizardDescriptionItem } from '../../components/WizardDescriptionItem';
Expand All @@ -21,7 +22,11 @@ const WizardMetadataTab: WizardTab = ({ vm, updateVM, loaded }) => {

return (
<PageSection className="wizard-metadata-tab">
<SidebarEditor resource={vm} onResourceUpdate={(newVM) => updateVM(newVM)}>
<SidebarEditor
resource={vm}
onResourceUpdate={(newVM) => updateVM(newVM)}
pathsToHighlight={PATHS_TO_HIGHLIGHT.DETAILS_TAB}
>
{(resource) => (
<>
<SidebarEditorSwitch />
Expand Down
7 changes: 6 additions & 1 deletion src/views/catalog/wizard/tabs/network/WizardNetworkTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useModal } from '@kubevirt-utils/components/ModalProvider/ModalProvider
import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEditor';
import SidebarEditorSwitch from '@kubevirt-utils/components/SidebarEditor/SidebarEditorSwitch';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { ListPageBody, ListPageCreateButton } from '@openshift-console/dynamic-plugin-sdk';
import { Flex, FlexItem } from '@patternfly/react-core';

Expand All @@ -22,7 +23,11 @@ const WizardNetworkTab: WizardTab = ({ vm, updateVM }) => {
return (
<div className="wizard-network-tab">
<ListPageBody>
<SidebarEditor resource={vm} onResourceUpdate={(newVM) => updateVM(newVM)}>
<SidebarEditor
resource={vm}
onResourceUpdate={(newVM) => updateVM(newVM)}
pathsToHighlight={PATHS_TO_HIGHLIGHT.NETWORK_TAB}
>
<Flex>
<FlexItem>
<ListPageCreateButton
Expand Down
7 changes: 6 additions & 1 deletion src/views/catalog/wizard/tabs/overview/WizardOverviewTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as React from 'react';
import { WizardTab } from '@catalog/wizard/tabs';
import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEditor';
import SidebarEditorSwitch from '@kubevirt-utils/components/SidebarEditor/SidebarEditorSwitch';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { PageSection } from '@patternfly/react-core';

import WizardOverviewGrid from './components/WizardOverviewGrid';
Expand All @@ -11,7 +12,11 @@ import './WizardOverviewTab.scss';

const WizardOverviewTab: WizardTab = ({ vm, tabsData, updateVM }) => (
<PageSection className="wizard-overview-tab">
<SidebarEditor resource={vm} onResourceUpdate={(newVM) => updateVM(newVM)}>
<SidebarEditor
resource={vm}
onResourceUpdate={(newVM) => updateVM(newVM)}
pathsToHighlight={PATHS_TO_HIGHLIGHT.DETAILS_TAB}
>
{(resource) => (
<>
<SidebarEditorSwitch />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { WizardTab } from '@catalog/wizard/tabs';
import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEditor';
import SidebarEditorSwitch from '@kubevirt-utils/components/SidebarEditor/SidebarEditorSwitch';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { PageSection } from '@patternfly/react-core';

import WizardSchedulingGrid from './components/WizardSchedulingGrid';
Expand All @@ -13,7 +14,11 @@ import './wizard-scheduling-tab.scss';
const WizardSchedulingTab: WizardTab = ({ vm, updateVM }) => {
return (
<PageSection>
<SidebarEditor<V1VirtualMachine> resource={vm} onResourceUpdate={updateVM}>
<SidebarEditor<V1VirtualMachine>
resource={vm}
onResourceUpdate={updateVM}
pathsToHighlight={PATHS_TO_HIGHLIGHT.SCHEDULING_TAB}
>
{(resource) => (
<>
<SidebarEditorSwitch />
Expand Down
7 changes: 6 additions & 1 deletion src/views/catalog/wizard/tabs/scripts/WizardScriptsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useModal } from '@kubevirt-utils/components/ModalProvider/ModalProvider
import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEditor';
import SidebarEditorSwitch from '@kubevirt-utils/components/SidebarEditor/SidebarEditorSwitch';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { DescriptionList, Divider, PageSection } from '@patternfly/react-core';

import SSHKey from './components/SSHKey';
Expand All @@ -21,7 +22,11 @@ const WizardScriptsTab: WizardTab = ({ vm, updateVM }) => {

return (
<PageSection className="wizard-scripts-tab">
<SidebarEditor resource={vm} onResourceUpdate={(newVM) => updateVM(newVM)}>
<SidebarEditor
resource={vm}
onResourceUpdate={(newVM) => updateVM(newVM)}
pathsToHighlight={PATHS_TO_HIGHLIGHT.SCRIPTS_TAB}
>
<SidebarEditorSwitch />
<DescriptionList className="wizard-scripts-tab__description-list">
<WizardDescriptionItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const VirtualMachineConfigurationTab: FC<VirtualMachineConfigurationTabProps> =
onClick={() => redirectTab(name)}
title={<TabTitleText>{title}</TabTitleText>}
>
<Component {...props} />
{activeTabKey === name && <Component {...props} />}
</Tab>
))}
</Tabs>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { RouteComponentProps } from 'react-router';
import VirtualMachineModel from '@kubevirt-ui/kubevirt-api/console/models/VirtualMachineModel';
import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEditor';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { k8sUpdate } from '@openshift-console/dynamic-plugin-sdk';

import DiskList from './tables/disk/DiskList';
Expand Down Expand Up @@ -32,7 +33,11 @@ const DiskListPage: React.FC<DiskListPageProps> = ({ obj }) => {

return (
<div className="disk-list-page">
<SidebarEditor resource={obj} onResourceUpdate={onSubmit}>
<SidebarEditor
resource={obj}
onResourceUpdate={onSubmit}
pathsToHighlight={PATHS_TO_HIGHLIGHT.DISKS_TAB}
>
<DiskList vm={obj} />
<FilesystemList vm={obj} />
</SidebarEditor>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import VirtualMachineModel from '@kubevirt-ui/kubevirt-api/console/models/Virtua
import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEditor';
import SidebarEditorSwitch from '@kubevirt-utils/components/SidebarEditor/SidebarEditorSwitch';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { k8sUpdate, ListPageBody } from '@openshift-console/dynamic-plugin-sdk';
import { Flex, FlexItem } from '@patternfly/react-core';

Expand Down Expand Up @@ -36,7 +37,11 @@ const NetworkInterfaceListPage: FC<NetworkInterfaceListPageProps> = ({ obj: vm }
return (
<div className="network-interface-list-page">
<ListPageBody>
<SidebarEditor resource={vm} onResourceUpdate={onSubmit}>
<SidebarEditor
resource={vm}
onResourceUpdate={onSubmit}
pathsToHighlight={PATHS_TO_HIGHLIGHT.NETWORK_TAB}
>
<Flex>
<FlexItem>
<AddNetworkInterfaceButton vm={vm} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { RouteComponentProps } from 'react-router';
import VirtualMachineModel from '@kubevirt-ui/kubevirt-api/console/models/VirtualMachineModel';
import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import SidebarEditor from '@kubevirt-utils/components/SidebarEditor/SidebarEditor';
import { PATHS_TO_HIGHLIGHT } from '@kubevirt-utils/resources/vm/utils/constants';
import { k8sUpdate } from '@openshift-console/dynamic-plugin-sdk';
import { PageSection } from '@patternfly/react-core';

Expand All @@ -30,7 +31,11 @@ const VirtualMachineSchedulingPage: React.FC<VirtualMachineSchedulingPageProps>

return (
<PageSection>
<SidebarEditor resource={vm} onResourceUpdate={onChangeResource}>
<SidebarEditor
resource={vm}
onResourceUpdate={onChangeResource}
pathsToHighlight={PATHS_TO_HIGHLIGHT.SCHEDULING_TAB}
>
{(resource) => <SchedulingSection vm={resource} pathname={location?.pathname} />}
</SidebarEditor>
</PageSection>
Expand Down
Loading

0 comments on commit 223de4f

Please sign in to comment.