Skip to content

Commit

Permalink
frontend: Accept given YAML/JSON in EditorDialog
Browse files Browse the repository at this point in the history
Signed-off-by: Evangelos Skopelitis <eskopelitis@microsoft.com>
  • Loading branch information
skoeva committed Sep 27, 2024
1 parent f2a65fa commit bacabbe
Showing 1 changed file with 39 additions and 25 deletions.
64 changes: 39 additions & 25 deletions frontend/src/components/common/Resource/EditorDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ import SimpleEditor from './SimpleEditor';
type KubeObjectIsh = Partial<KubeObjectInterface>;

export interface EditorDialogProps extends DialogProps {
/** The object to edit, or null to make the dialog be in "loading mode". Pass it an empty object if no contents are to be shown when the dialog is first open. */
item: KubeObjectIsh | null;
/** The object(s) to edit, or null to make the dialog be in "loading mode". Pass it an empty object if no contents are to be shown when the dialog is first open. */
item: KubeObjectIsh | object | object[] | string | null;
/** Called when the dialog is closed. */
onClose: () => void;
/** Called when the user clicks the save button. */
Expand All @@ -76,11 +76,14 @@ export default function EditorDialog(props: EditorDialogProps) {
const [lang, setLang] = React.useState(i18n.language);
const themeName = getThemeName();

const originalCodeRef = React.useRef({ code: '', format: item ? 'yaml' : '' });
const initialCode = typeof item === 'string' ? item : yaml.dump(item || {});
const originalCodeRef = React.useRef({ code: initialCode, format: item ? 'yaml' : '' });
const [code, setCode] = React.useState(originalCodeRef.current);
const codeRef = React.useRef(code);
const lastCodeCheckHandler = React.useRef(0);
const previousVersionRef = React.useRef(item?.metadata?.resourceVersion || '');
const previousVersionRef = React.useRef(
isKubeObjectIsh(item) ? item?.metadata?.resourceVersion || '' : ''
);
const [error, setError] = React.useState('');
const [docSpecs, setDocSpecs] = React.useState<
KubeObjectInterface | KubeObjectInterface[] | null
Expand All @@ -97,36 +100,45 @@ export default function EditorDialog(props: EditorDialogProps) {
setUseSimpleEditorState(data);
}

function isKubeObjectIsh(item: any): item is KubeObjectIsh {
return item && typeof item === 'object' && !Array.isArray(item) && 'metadata' in item;
}

// Update the code when the item changes, but only if the code hasn't been touched.
React.useEffect(() => {
if (!item || Object.keys(item || {}).length === 0) {
const defaultCode = '# Enter your YAML or JSON here';
originalCodeRef.current = { code: defaultCode, format: 'yaml' };
setCode({ code: defaultCode, format: 'yaml' });
return;
}

const originalCode = originalCodeRef.current.code;
const itemCode =
originalCodeRef.current.format === 'json' ? JSON.stringify(item) : yaml.dump(item);
if (itemCode !== originalCodeRef.current.code) {
originalCodeRef.current = { code: itemCode, format: originalCodeRef.current.format };
}
// Determine the format (YAML or JSON) and serialize to string
const format = looksLikeJson(originalCodeRef.current.code) ? 'json' : 'yaml';
const itemCode = format === 'json' ? JSON.stringify(item) : yaml.dump(item);

if (!item.metadata) {
return;
// Update the code if the item representation has changed
if (itemCode !== originalCodeRef.current.code) {
originalCodeRef.current = { code: itemCode, format };
setCode({ code: itemCode, format });
}

const resourceVersionsDiffer =
(previousVersionRef.current || '') !== (item.metadata!.resourceVersion || '');
// Only change if the code hasn't been touched.
// We use the codeRef in this effect instead of the code, because we need to access the current
// state of the code but we don't want to trigger a re-render when we set the code here.
if (resourceVersionsDiffer || codeRef.current.code === originalCode) {
// Prevent updating to the same code, which would lead to an infinite loop.
if (codeRef.current.code !== itemCode) {
setCode({ code: itemCode, format: originalCodeRef.current.format });
}
// Additional handling for Kubernetes objects
if (isKubeObjectIsh(item) && item.metadata) {
const resourceVersionsDiffer =
(previousVersionRef.current || '') !== (item.metadata!.resourceVersion || '');
// Only change if the code hasn't been touched.
// We use the codeRef in this effect instead of the code, because we need to access the current
// state of the code but we don't want to trigger a re-render when we set the code here.
if (resourceVersionsDiffer || codeRef.current.code === originalCodeRef.current.code) {
// Prevent updating to the same code, which would lead to an infinite loop.
if (codeRef.current.code !== itemCode) {
setCode({ code: itemCode, format: originalCodeRef.current.format });
}

if (resourceVersionsDiffer && !!item.metadata!.resourceVersion) {
previousVersionRef.current = item.metadata!.resourceVersion;
if (resourceVersionsDiffer && !!item.metadata!.resourceVersion) {
previousVersionRef.current = item.metadata!.resourceVersion;
}
}
}
}, [item]);
Expand Down Expand Up @@ -297,7 +309,9 @@ export default function EditorDialog(props: EditorDialogProps) {
const errorLabel = error || errorMessage;
let dialogTitle = title;
if (!dialogTitle && item) {
const itemName = item.metadata?.name || t('New Object');
const itemName = isKubeObjectIsh(item)
? item.metadata?.name || t('New Object')
: t('New Object');
dialogTitle = isReadOnly()
? t('translation|View: {{ itemName }}', { itemName })
: t('translation|Edit: {{ itemName }}', { itemName });
Expand Down

0 comments on commit bacabbe

Please sign in to comment.