Skip to content

Commit 4935a01

Browse files
r4zr32d3k1lclaude
andauthored
[Workflows] Add editor settings popover to YAML editor (elastic#267421)
## Summary https://github.com/user-attachments/assets/3cabaaf7-385e-44da-9167-e68dbd8805ba Adds an **Editor Settings** popover icon to the YAML editor bottom bar (to the right of the keyboard shortcuts icon), with two toggles: - **Show indent guides** — vertical grey lines at each indent level (on by default) - **Show whitespace characters** — dots for every space (off by default) ## Test plan - [x] Open the Workflow YAML editor — verify indent guide lines are visible by default - [x] Click the settings icon in the bottom bar — popover opens with two checkboxes - [x] Toggle "Show indent guides" off — vertical lines disappear from the editor - [x] Toggle "Show whitespace characters" on — dots appear for every space - [x] Settings icon and keyboard shortcuts icon coexist correctly in the bottom bar 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 094bf9c commit 4935a01

2 files changed

Lines changed: 127 additions & 1 deletion

File tree

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
import {
11+
EuiButtonIcon,
12+
EuiCheckbox,
13+
EuiFlexGroup,
14+
EuiFlexItem,
15+
EuiPopover,
16+
EuiPopoverTitle,
17+
EuiToolTip,
18+
useEuiTheme,
19+
useGeneratedHtmlId,
20+
} from '@elastic/eui';
21+
import React, { useCallback, useState } from 'react';
22+
import { i18n } from '@kbn/i18n';
23+
import type { monaco } from '@kbn/monaco';
24+
25+
interface EditorSettingsPopoverProps {
26+
editorRef: React.MutableRefObject<monaco.editor.IStandaloneCodeEditor | null>;
27+
}
28+
29+
export function EditorSettingsPopover({ editorRef }: EditorSettingsPopoverProps) {
30+
const { euiTheme } = useEuiTheme();
31+
const [isOpen, setIsOpen] = useState(false);
32+
const [showIndentGuides, setShowIndentGuides] = useState(true);
33+
const [showWhitespace, setShowWhitespace] = useState(false);
34+
35+
const indentGuidesCheckboxId = useGeneratedHtmlId({ prefix: 'wf-editor-setting-indent-guides' });
36+
const whitespaceCheckboxId = useGeneratedHtmlId({ prefix: 'wf-editor-setting-whitespace' });
37+
const popoverTitleId = useGeneratedHtmlId({ prefix: 'wf-editor-settings-title' });
38+
39+
const handleIndentGuidesChange = useCallback(
40+
(e: React.ChangeEvent<HTMLInputElement>) => {
41+
const enabled = e.target.checked;
42+
setShowIndentGuides(enabled);
43+
editorRef.current?.updateOptions({
44+
guides: { indentation: enabled },
45+
});
46+
},
47+
[editorRef]
48+
);
49+
50+
const handleWhitespaceChange = useCallback(
51+
(e: React.ChangeEvent<HTMLInputElement>) => {
52+
const enabled = e.target.checked;
53+
setShowWhitespace(enabled);
54+
editorRef.current?.updateOptions({
55+
renderWhitespace: enabled ? 'all' : 'none',
56+
});
57+
},
58+
[editorRef]
59+
);
60+
61+
const label = i18n.translate('workflows.yamlEditor.editorSettings.label', {
62+
defaultMessage: 'Editor settings',
63+
});
64+
65+
return (
66+
<EuiPopover
67+
css={{ marginLeft: euiTheme.size.xs }}
68+
data-test-subj="workflowYamlEditorSettingsPopover"
69+
aria-labelledby={popoverTitleId}
70+
isOpen={isOpen}
71+
closePopover={() => setIsOpen(false)}
72+
anchorPosition="upRight"
73+
panelPaddingSize="none"
74+
button={
75+
<EuiToolTip content={label} delay="long" disableScreenReaderOutput>
76+
<EuiButtonIcon
77+
size="xs"
78+
iconType="controlsHorizontal"
79+
data-test-subj="workflowYamlEditorSettingsButton"
80+
onClick={() => setIsOpen(!isOpen)}
81+
aria-label={label}
82+
color="primary"
83+
/>
84+
</EuiToolTip>
85+
}
86+
>
87+
<EuiPopoverTitle id={popoverTitleId} paddingSize="s">
88+
{label}
89+
</EuiPopoverTitle>
90+
<EuiFlexGroup
91+
direction="column"
92+
gutterSize="s"
93+
css={{ padding: `${euiTheme.size.xs} ${euiTheme.size.s} ${euiTheme.size.s}` }}
94+
responsive={false}
95+
>
96+
<EuiFlexItem>
97+
<EuiCheckbox
98+
id={indentGuidesCheckboxId}
99+
label={i18n.translate('workflows.yamlEditor.editorSettings.showIndentGuides', {
100+
defaultMessage: 'Show indent guides',
101+
})}
102+
checked={showIndentGuides}
103+
onChange={handleIndentGuidesChange}
104+
/>
105+
</EuiFlexItem>
106+
<EuiFlexItem>
107+
<EuiCheckbox
108+
id={whitespaceCheckboxId}
109+
label={i18n.translate('workflows.yamlEditor.editorSettings.showWhitespace', {
110+
defaultMessage: 'Show whitespace characters',
111+
})}
112+
checked={showWhitespace}
113+
onChange={handleWhitespaceChange}
114+
/>
115+
</EuiFlexItem>
116+
</EuiFlexGroup>
117+
</EuiPopover>
118+
);
119+
}

src/platform/plugins/shared/workflows_management/public/widgets/workflow_yaml_editor/ui/workflow_yaml_editor.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
useWorkflowIdDecorations,
3333
} from './decorations';
3434
import { DocumentationLink } from './documentation_link';
35+
import { EditorSettingsPopover } from './editor_settings_popover';
3536
import type { ExtraAction } from './extra_actions_bar';
3637
import { ExtraActionsBar } from './extra_actions_bar';
3738
import { useAgentBuilderIntegration } from './hooks/use_agent_builder_integration';
@@ -130,6 +131,7 @@ const editorOptions: monaco.editor.IStandaloneEditorConstructionOptions = {
130131
lineHeight: 23, // default ~21px + 2px
131132
renderWhitespace: 'none',
132133
roundedSelection: false,
134+
guides: { indentation: true },
133135
wordWrap: 'on',
134136
wordWrapColumn: 80,
135137
wrappingIndent: 'indent',
@@ -747,8 +749,13 @@ export const WorkflowYAMLEditor = ({
747749
content: <KeyboardShortcutsPopover />,
748750
showInReadOnly: true,
749751
},
752+
{
753+
id: 'editor-settings',
754+
content: <EditorSettingsPopover editorRef={editorRef} />,
755+
showInReadOnly: true,
756+
},
750757
],
751-
[openActionsPopover]
758+
[openActionsPopover, editorRef]
752759
);
753760

754761
// These were triggering rerendering of the actions containers on every scroll, because they were

0 commit comments

Comments
 (0)