fix(ui): convert yaml-editor to functional component (#24921)

Signed-off-by: Mike <mike.kangaroo.world@gmail.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
This commit is contained in:
Mike
2026-02-05 23:45:06 +09:00
committed by GitHub
parent feab8bde77
commit 96bfc1e20b

View File

@@ -2,114 +2,100 @@ import {ErrorNotification, NotificationType} from 'argo-ui';
import * as jsYaml from 'js-yaml';
import * as monacoEditor from 'monaco-editor';
import * as React from 'react';
import {useContext, useState, useRef} from 'react';
import {Consumer} from '../../context';
import {Context} from '../../context';
import {MonacoEditor} from '../monaco-editor';
const jsonMergePatch = require('json-merge-patch');
require('./yaml-editor.scss');
export class YamlEditor<T> extends React.Component<
{
input: T;
hideModeButtons?: boolean;
initialEditMode?: boolean;
vScrollbar?: boolean;
enableWordWrap?: boolean;
onSave?: (patch: string, patchType: string) => Promise<any>;
onCancel?: () => any;
minHeight?: number;
},
{
editing: boolean;
}
> {
private model: monacoEditor.editor.ITextModel;
constructor(props: any) {
super(props);
this.state = {editing: props.initialEditMode};
}
public render() {
const props = this.props;
const yaml = props.input ? jsYaml.dump(props.input) : '';
return (
<div className='yaml-editor'>
{!props.hideModeButtons && (
<div className='yaml-editor__buttons'>
{(this.state.editing && (
<Consumer>
{ctx => (
<React.Fragment>
<button
onClick={async () => {
try {
const updated = jsYaml.load(this.model.getLinesContent().join('\n'));
const patch = jsonMergePatch.generate(props.input, updated);
try {
const unmounted = await this.props.onSave(JSON.stringify(patch || {}), 'application/merge-patch+json');
if (unmounted !== true) {
this.setState({editing: false});
}
} catch (e) {
ctx.notifications.show({
content: (
<div className='yaml-editor__error'>
<ErrorNotification title='Unable to save changes' e={e} />
</div>
),
type: NotificationType.Error
});
}
} catch (e) {
ctx.notifications.show({
content: <ErrorNotification title='Unable to validate changes' e={e} />,
type: NotificationType.Error
});
}
}}
className='argo-button argo-button--base'>
Save
</button>{' '}
<button
onClick={() => {
this.model.setValue(jsYaml.dump(props.input));
this.setState({editing: !this.state.editing});
if (props.onCancel) {
props.onCancel();
}
}}
className='argo-button argo-button--base-o'>
Cancel
</button>
</React.Fragment>
)}
</Consumer>
)) || (
<button onClick={() => this.setState({editing: true})} className='argo-button argo-button--base'>
Edit
</button>
)}
</div>
)}
<MonacoEditor
minHeight={props.minHeight}
vScrollBar={props.vScrollbar}
editor={{
input: {text: yaml, language: 'yaml'},
options: {
readOnly: !this.state.editing,
minimap: {enabled: false},
wordWrap: props.enableWordWrap ? 'on' : 'off'
},
getApi: api => {
this.model = api.getModel() as monacoEditor.editor.ITextModel;
}
}}
/>
</div>
);
}
interface YamlEditorProps<T> {
input: T;
hideModeButtons?: boolean;
initialEditMode?: boolean;
vScrollbar?: boolean;
enableWordWrap?: boolean;
onSave?: (patch: string, patchType: string) => Promise<any>;
onCancel?: () => any;
minHeight?: number;
}
export function YamlEditor<T>(props: YamlEditorProps<T>) {
const ctx = useContext(Context);
const [editing, setEditing] = useState(!!props.initialEditMode);
const modelRef = useRef<monacoEditor.editor.ITextModel | null>(null);
const yamlText = props.input ? jsYaml.dump(props.input) : '';
const handleSave = async () => {
try {
const updated = jsYaml.load(modelRef.current!.getLinesContent().join('\n'));
const patch = jsonMergePatch.generate(props.input, updated);
try {
const unmounted = await props.onSave?.(JSON.stringify(patch || {}), 'application/merge-patch+json');
if (unmounted !== true) {
setEditing(false);
}
} catch (e) {
ctx.notifications.show({
content: (
<div className='yaml-editor__error'>
<ErrorNotification title='Unable to save changes' e={e} />
</div>
),
type: NotificationType.Error
});
}
} catch (e) {
ctx.notifications.show({
content: <ErrorNotification title='Unable to validate changes' e={e} />,
type: NotificationType.Error
});
}
};
const handleCancel = () => {
modelRef.current?.setValue(jsYaml.dump(props.input));
setEditing(false);
props.onCancel?.();
};
return (
<div className='yaml-editor'>
{!props.hideModeButtons && (
<div className='yaml-editor__buttons'>
{editing ? (
<>
<button onClick={handleSave} className='argo-button argo-button--base'>
Save
</button>{' '}
<button onClick={handleCancel} className='argo-button argo-button--base-o'>
Cancel
</button>
</>
) : (
<button onClick={() => setEditing(true)} className='argo-button argo-button--base'>
Edit
</button>
)}
</div>
)}
<MonacoEditor
minHeight={props.minHeight}
vScrollBar={props.vScrollbar}
editor={{
input: {text: yamlText, language: 'yaml'},
options: {
readOnly: !editing,
minimap: {enabled: false},
wordWrap: props.enableWordWrap ? 'on' : 'off'
},
getApi: api => {
modelRef.current = api.getModel() as monacoEditor.editor.ITextModel;
}
}}
/>
</div>
);
}