aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/editor
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/frontend/src/editor')
-rw-r--r--subprojects/frontend/src/editor/AnalysisErrorNotification.tsx74
-rw-r--r--subprojects/frontend/src/editor/AnimatedButton.tsx9
-rw-r--r--subprojects/frontend/src/editor/DiagnosticValue.ts1
-rw-r--r--subprojects/frontend/src/editor/EditorButtons.tsx6
-rw-r--r--subprojects/frontend/src/editor/EditorErrors.tsx93
-rw-r--r--subprojects/frontend/src/editor/EditorPane.tsx4
-rw-r--r--subprojects/frontend/src/editor/EditorStore.ts47
-rw-r--r--subprojects/frontend/src/editor/EditorTheme.ts15
-rw-r--r--subprojects/frontend/src/editor/GenerateButton.tsx48
9 files changed, 253 insertions, 44 deletions
diff --git a/subprojects/frontend/src/editor/AnalysisErrorNotification.tsx b/subprojects/frontend/src/editor/AnalysisErrorNotification.tsx
new file mode 100644
index 00000000..591a3600
--- /dev/null
+++ b/subprojects/frontend/src/editor/AnalysisErrorNotification.tsx
@@ -0,0 +1,74 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import { reaction } from 'mobx';
8import { type SnackbarKey, useSnackbar } from 'notistack';
9import { useEffect, useState } from 'react';
10
11import type EditorStore from './EditorStore';
12
13function MessageObserver({
14 editorStore,
15}: {
16 editorStore: EditorStore;
17}): React.ReactNode {
18 const [message, setMessage] = useState(
19 editorStore.delayedErrors.semanticsError ?? '',
20 );
21 // Instead of making this component an `observer`,
22 // we only update the message is one is present to make sure that the
23 // disappear animation has a chance to complete.
24 useEffect(
25 () =>
26 reaction(
27 () => editorStore.delayedErrors.semanticsError,
28 (newMessage) => {
29 if (newMessage !== undefined) {
30 setMessage(newMessage);
31 }
32 },
33 { fireImmediately: false },
34 ),
35 [editorStore],
36 );
37 return message;
38}
39
40export default function AnalysisErrorNotification({
41 editorStore,
42}: {
43 editorStore: EditorStore;
44}): null {
45 const { enqueueSnackbar, closeSnackbar } = useSnackbar();
46 useEffect(() => {
47 let key: SnackbarKey | undefined;
48 const disposer = reaction(
49 () => editorStore.delayedErrors.semanticsError !== undefined,
50 (hasError) => {
51 if (hasError) {
52 if (key === undefined) {
53 key = enqueueSnackbar({
54 message: <MessageObserver editorStore={editorStore} />,
55 variant: 'error',
56 persist: true,
57 });
58 }
59 } else if (key !== undefined) {
60 closeSnackbar(key);
61 key = undefined;
62 }
63 },
64 { fireImmediately: true },
65 );
66 return () => {
67 disposer();
68 if (key !== undefined) {
69 closeSnackbar(key);
70 }
71 };
72 }, [editorStore, enqueueSnackbar, closeSnackbar]);
73 return null;
74}
diff --git a/subprojects/frontend/src/editor/AnimatedButton.tsx b/subprojects/frontend/src/editor/AnimatedButton.tsx
index dbbda618..24ec69be 100644
--- a/subprojects/frontend/src/editor/AnimatedButton.tsx
+++ b/subprojects/frontend/src/editor/AnimatedButton.tsx
@@ -48,7 +48,7 @@ export default function AnimatedButton({
48 onClick?: () => void; 48 onClick?: () => void;
49 color: 'error' | 'warning' | 'primary' | 'inherit'; 49 color: 'error' | 'warning' | 'primary' | 'inherit';
50 disabled?: boolean; 50 disabled?: boolean;
51 startIcon: JSX.Element; 51 startIcon?: JSX.Element;
52 sx?: SxProps<Theme> | undefined; 52 sx?: SxProps<Theme> | undefined;
53 children?: ReactNode; 53 children?: ReactNode;
54}): JSX.Element { 54}): JSX.Element {
@@ -79,7 +79,11 @@ export default function AnimatedButton({
79 className="rounded shaded" 79 className="rounded shaded"
80 disabled={disabled ?? false} 80 disabled={disabled ?? false}
81 startIcon={startIcon} 81 startIcon={startIcon}
82 width={width === undefined ? 'auto' : `calc(${width} + 50px)`} 82 width={
83 width === undefined
84 ? 'auto'
85 : `calc(${width} + ${startIcon === undefined ? 28 : 50}px)`
86 }
83 > 87 >
84 <Box 88 <Box
85 display="flex" 89 display="flex"
@@ -100,6 +104,7 @@ AnimatedButton.defaultProps = {
100 'aria-label': undefined, 104 'aria-label': undefined,
101 onClick: undefined, 105 onClick: undefined,
102 disabled: false, 106 disabled: false,
107 startIcon: undefined,
103 sx: undefined, 108 sx: undefined,
104 children: undefined, 109 children: undefined,
105}; 110};
diff --git a/subprojects/frontend/src/editor/DiagnosticValue.ts b/subprojects/frontend/src/editor/DiagnosticValue.ts
index 20478262..410a46b7 100644
--- a/subprojects/frontend/src/editor/DiagnosticValue.ts
+++ b/subprojects/frontend/src/editor/DiagnosticValue.ts
@@ -14,6 +14,7 @@ export default class DiagnosticValue extends RangeValue {
14 error: new DiagnosticValue('error'), 14 error: new DiagnosticValue('error'),
15 warning: new DiagnosticValue('warning'), 15 warning: new DiagnosticValue('warning'),
16 info: new DiagnosticValue('info'), 16 info: new DiagnosticValue('info'),
17 hint: new DiagnosticValue('hint'),
17 }; 18 };
18 19
19 private constructor(public readonly severity: Severity) { 20 private constructor(public readonly severity: Severity) {
diff --git a/subprojects/frontend/src/editor/EditorButtons.tsx b/subprojects/frontend/src/editor/EditorButtons.tsx
index 9b187e5c..ca51f975 100644
--- a/subprojects/frontend/src/editor/EditorButtons.tsx
+++ b/subprojects/frontend/src/editor/EditorButtons.tsx
@@ -5,8 +5,8 @@
5 */ 5 */
6 6
7import type { Diagnostic } from '@codemirror/lint'; 7import type { Diagnostic } from '@codemirror/lint';
8import CancelIcon from '@mui/icons-material/Cancel';
8import CheckIcon from '@mui/icons-material/Check'; 9import CheckIcon from '@mui/icons-material/Check';
9import ErrorIcon from '@mui/icons-material/Error';
10import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered'; 10import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered';
11import FormatPaint from '@mui/icons-material/FormatPaint'; 11import FormatPaint from '@mui/icons-material/FormatPaint';
12import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; 12import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
@@ -28,7 +28,7 @@ import type EditorStore from './EditorStore';
28function getLintIcon(severity: Diagnostic['severity'] | undefined) { 28function getLintIcon(severity: Diagnostic['severity'] | undefined) {
29 switch (severity) { 29 switch (severity) {
30 case 'error': 30 case 'error':
31 return <ErrorIcon fontSize="small" />; 31 return <CancelIcon fontSize="small" />;
32 case 'warning': 32 case 'warning':
33 return <WarningIcon fontSize="small" />; 33 return <WarningIcon fontSize="small" />;
34 case 'info': 34 case 'info':
@@ -95,7 +95,7 @@ export default observer(function EditorButtons({
95 })} 95 })}
96 value="show-lint-panel" 96 value="show-lint-panel"
97 > 97 >
98 {getLintIcon(editorStore?.highestDiagnosticLevel)} 98 {getLintIcon(editorStore?.delayedErrors?.highestDiagnosticLevel)}
99 </ToggleButton> 99 </ToggleButton>
100 </ToggleButtonGroup> 100 </ToggleButtonGroup>
101 <IconButton 101 <IconButton
diff --git a/subprojects/frontend/src/editor/EditorErrors.tsx b/subprojects/frontend/src/editor/EditorErrors.tsx
new file mode 100644
index 00000000..40becf7e
--- /dev/null
+++ b/subprojects/frontend/src/editor/EditorErrors.tsx
@@ -0,0 +1,93 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import { Diagnostic } from '@codemirror/lint';
8import { type IReactionDisposer, makeAutoObservable, reaction } from 'mobx';
9
10import type EditorStore from './EditorStore';
11
12const HYSTERESIS_TIME_MS = 250;
13
14export interface State {
15 analyzing: boolean;
16 errorCount: number;
17 warningCount: number;
18 infoCount: number;
19 semanticsError: string | undefined;
20}
21
22export default class EditorErrors implements State {
23 private readonly disposer: IReactionDisposer;
24
25 private timer: number | undefined;
26
27 analyzing = false;
28
29 errorCount = 0;
30
31 warningCount = 0;
32
33 infoCount = 0;
34
35 semanticsError: string | undefined;
36
37 constructor(private readonly store: EditorStore) {
38 this.updateImmediately(this.getNextState());
39 makeAutoObservable<EditorErrors, 'disposer' | 'timer'>(this, {
40 disposer: false,
41 timer: false,
42 });
43 this.disposer = reaction(
44 () => this.getNextState(),
45 (nextState) => {
46 if (this.timer !== undefined) {
47 clearTimeout(this.timer);
48 this.timer = undefined;
49 }
50 if (nextState.analyzing) {
51 this.timer = setTimeout(
52 () => this.updateImmediately(nextState),
53 HYSTERESIS_TIME_MS,
54 );
55 } else {
56 this.updateImmediately(nextState);
57 }
58 },
59 { fireImmediately: true },
60 );
61 }
62
63 get highestDiagnosticLevel(): Diagnostic['severity'] | undefined {
64 if (this.errorCount > 0) {
65 return 'error';
66 }
67 if (this.warningCount > 0) {
68 return 'warning';
69 }
70 if (this.infoCount > 0) {
71 return 'info';
72 }
73 return undefined;
74 }
75
76 private getNextState(): State {
77 return {
78 analyzing: this.store.analyzing,
79 errorCount: this.store.errorCount,
80 warningCount: this.store.warningCount,
81 infoCount: this.store.infoCount,
82 semanticsError: this.store.semanticsError,
83 };
84 }
85
86 private updateImmediately(nextState: State) {
87 Object.assign(this, nextState);
88 }
89
90 dispose() {
91 this.disposer();
92 }
93}
diff --git a/subprojects/frontend/src/editor/EditorPane.tsx b/subprojects/frontend/src/editor/EditorPane.tsx
index 87f408fe..1125a0ec 100644
--- a/subprojects/frontend/src/editor/EditorPane.tsx
+++ b/subprojects/frontend/src/editor/EditorPane.tsx
@@ -13,6 +13,7 @@ import { useState } from 'react';
13 13
14import { useRootStore } from '../RootStoreProvider'; 14import { useRootStore } from '../RootStoreProvider';
15 15
16import AnalysisErrorNotification from './AnalysisErrorNotification';
16import ConnectionStatusNotification from './ConnectionStatusNotification'; 17import ConnectionStatusNotification from './ConnectionStatusNotification';
17import EditorArea from './EditorArea'; 18import EditorArea from './EditorArea';
18import EditorButtons from './EditorButtons'; 19import EditorButtons from './EditorButtons';
@@ -39,7 +40,7 @@ export default observer(function EditorPane(): JSX.Element {
39 const { editorStore } = useRootStore(); 40 const { editorStore } = useRootStore();
40 41
41 return ( 42 return (
42 <Stack direction="column" flexGrow={1} flexShrink={1} overflow="auto"> 43 <Stack direction="column" height="100%" overflow="auto">
43 <Toolbar variant="dense"> 44 <Toolbar variant="dense">
44 <EditorButtons editorStore={editorStore} /> 45 <EditorButtons editorStore={editorStore} />
45 </Toolbar> 46 </Toolbar>
@@ -48,6 +49,7 @@ export default observer(function EditorPane(): JSX.Element {
48 <EditorLoading /> 49 <EditorLoading />
49 ) : ( 50 ) : (
50 <> 51 <>
52 <AnalysisErrorNotification editorStore={editorStore} />
51 <ConnectionStatusNotification editorStore={editorStore} /> 53 <ConnectionStatusNotification editorStore={editorStore} />
52 <SearchPanelPortal editorStore={editorStore} /> 54 <SearchPanelPortal editorStore={editorStore} />
53 <EditorArea editorStore={editorStore} /> 55 <EditorArea editorStore={editorStore} />
diff --git a/subprojects/frontend/src/editor/EditorStore.ts b/subprojects/frontend/src/editor/EditorStore.ts
index b98f085e..b5989ad1 100644
--- a/subprojects/frontend/src/editor/EditorStore.ts
+++ b/subprojects/frontend/src/editor/EditorStore.ts
@@ -26,9 +26,12 @@ import { makeAutoObservable, observable, runInAction } from 'mobx';
26import { nanoid } from 'nanoid'; 26import { nanoid } from 'nanoid';
27 27
28import type PWAStore from '../PWAStore'; 28import type PWAStore from '../PWAStore';
29import GraphStore from '../graph/GraphStore';
29import getLogger from '../utils/getLogger'; 30import getLogger from '../utils/getLogger';
30import type XtextClient from '../xtext/XtextClient'; 31import type XtextClient from '../xtext/XtextClient';
32import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults';
31 33
34import EditorErrors from './EditorErrors';
32import LintPanelStore from './LintPanelStore'; 35import LintPanelStore from './LintPanelStore';
33import SearchPanelStore from './SearchPanelStore'; 36import SearchPanelStore from './SearchPanelStore';
34import createEditorState from './createEditorState'; 37import createEditorState from './createEditorState';
@@ -54,13 +57,22 @@ export default class EditorStore {
54 57
55 readonly lintPanel: LintPanelStore; 58 readonly lintPanel: LintPanelStore;
56 59
60 readonly delayedErrors: EditorErrors;
61
57 showLineNumbers = false; 62 showLineNumbers = false;
58 63
59 disposed = false; 64 disposed = false;
60 65
66 analyzing = false;
67
68 semanticsError: string | undefined;
69
70 graph: GraphStore;
71
61 constructor(initialValue: string, pwaStore: PWAStore) { 72 constructor(initialValue: string, pwaStore: PWAStore) {
62 this.id = nanoid(); 73 this.id = nanoid();
63 this.state = createEditorState(initialValue, this); 74 this.state = createEditorState(initialValue, this);
75 this.delayedErrors = new EditorErrors(this);
64 this.searchPanel = new SearchPanelStore(this); 76 this.searchPanel = new SearchPanelStore(this);
65 this.lintPanel = new LintPanelStore(this); 77 this.lintPanel = new LintPanelStore(this);
66 (async () => { 78 (async () => {
@@ -75,6 +87,7 @@ export default class EditorStore {
75 })().catch((error) => { 87 })().catch((error) => {
76 log.error('Failed to load XtextClient', error); 88 log.error('Failed to load XtextClient', error);
77 }); 89 });
90 this.graph = new GraphStore();
78 makeAutoObservable<EditorStore, 'client'>(this, { 91 makeAutoObservable<EditorStore, 'client'>(this, {
79 id: false, 92 id: false,
80 state: observable.ref, 93 state: observable.ref,
@@ -213,19 +226,6 @@ export default class EditorStore {
213 this.doCommand(nextDiagnostic); 226 this.doCommand(nextDiagnostic);
214 } 227 }
215 228
216 get highestDiagnosticLevel(): Diagnostic['severity'] | undefined {
217 if (this.errorCount > 0) {
218 return 'error';
219 }
220 if (this.warningCount > 0) {
221 return 'warning';
222 }
223 if (this.infoCount > 0) {
224 return 'info';
225 }
226 return undefined;
227 }
228
229 updateSemanticHighlighting(ranges: IHighlightRange[]): void { 229 updateSemanticHighlighting(ranges: IHighlightRange[]): void {
230 this.dispatch(setSemanticHighlighting(ranges)); 230 this.dispatch(setSemanticHighlighting(ranges));
231 } 231 }
@@ -282,8 +282,29 @@ export default class EditorStore {
282 return true; 282 return true;
283 } 283 }
284 284
285 analysisStarted() {
286 this.analyzing = true;
287 }
288
289 analysisCompleted(semanticAnalysisSkipped = false) {
290 this.analyzing = false;
291 if (semanticAnalysisSkipped) {
292 this.semanticsError = undefined;
293 }
294 }
295
296 setSemanticsError(semanticsError: string) {
297 this.semanticsError = semanticsError;
298 }
299
300 setSemantics(semantics: SemanticsSuccessResult) {
301 this.semanticsError = undefined;
302 this.graph.setSemantics(semantics);
303 }
304
285 dispose(): void { 305 dispose(): void {
286 this.client?.dispose(); 306 this.client?.dispose();
307 this.delayedErrors.dispose();
287 this.disposed = true; 308 this.disposed = true;
288 } 309 }
289} 310}
diff --git a/subprojects/frontend/src/editor/EditorTheme.ts b/subprojects/frontend/src/editor/EditorTheme.ts
index e057ce18..055b62e2 100644
--- a/subprojects/frontend/src/editor/EditorTheme.ts
+++ b/subprojects/frontend/src/editor/EditorTheme.ts
@@ -4,15 +4,13 @@
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6 6
7import errorSVG from '@material-icons/svg/svg/error/baseline.svg?raw'; 7import cancelSVG from '@material-icons/svg/svg/cancel/baseline.svg?raw';
8import expandMoreSVG from '@material-icons/svg/svg/expand_more/baseline.svg?raw'; 8import expandMoreSVG from '@material-icons/svg/svg/expand_more/baseline.svg?raw';
9import infoSVG from '@material-icons/svg/svg/info/baseline.svg?raw'; 9import infoSVG from '@material-icons/svg/svg/info/baseline.svg?raw';
10import warningSVG from '@material-icons/svg/svg/warning/baseline.svg?raw'; 10import warningSVG from '@material-icons/svg/svg/warning/baseline.svg?raw';
11import { alpha, styled, type CSSObject } from '@mui/material/styles'; 11import { alpha, styled, type CSSObject } from '@mui/material/styles';
12 12
13function svgURL(svg: string): string { 13import svgURL from '../utils/svgURL';
14 return `url('data:image/svg+xml;utf8,${svg}')`;
15}
16 14
17export default styled('div', { 15export default styled('div', {
18 name: 'EditorTheme', 16 name: 'EditorTheme',
@@ -56,15 +54,16 @@ export default styled('div', {
56 '.cm-activeLineGutter': { 54 '.cm-activeLineGutter': {
57 background: 'transparent', 55 background: 'transparent',
58 }, 56 },
59 '.cm-cursor, .cm-cursor-primary': { 57 '.cm-cursor, .cm-dropCursor, .cm-cursor-primary': {
60 borderLeft: `2px solid ${theme.palette.info.main}`, 58 borderLeft: `2px solid ${theme.palette.info.main}`,
59 marginLeft: -1,
61 }, 60 },
62 '.cm-selectionBackground': { 61 '.cm-selectionBackground': {
63 background: theme.palette.highlight.selection, 62 background: theme.palette.highlight.selection,
64 }, 63 },
65 '.cm-focused': { 64 '.cm-focused': {
66 outline: 'none', 65 outline: 'none',
67 '.cm-selectionBackground': { 66 '& > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': {
68 background: theme.palette.highlight.selection, 67 background: theme.palette.highlight.selection,
69 }, 68 },
70 }, 69 },
@@ -106,7 +105,7 @@ export default styled('div', {
106 color: theme.palette.text.primary, 105 color: theme.palette.text.primary,
107 }, 106 },
108 }, 107 },
109 '.tok-problem-abstract, .tok-problem-new': { 108 '.tok-problem-abstract': {
110 fontStyle: 'italic', 109 fontStyle: 'italic',
111 }, 110 },
112 '.tok-problem-containment': { 111 '.tok-problem-containment': {
@@ -331,7 +330,7 @@ export default styled('div', {
331 '.cm-lintRange-active': { 330 '.cm-lintRange-active': {
332 background: theme.palette.highlight.activeLintRange, 331 background: theme.palette.highlight.activeLintRange,
333 }, 332 },
334 ...lintSeverityStyle('error', errorSVG, 120), 333 ...lintSeverityStyle('error', cancelSVG, 120),
335 ...lintSeverityStyle('warning', warningSVG, 110), 334 ...lintSeverityStyle('warning', warningSVG, 110),
336 ...lintSeverityStyle('info', infoSVG, 100), 335 ...lintSeverityStyle('info', infoSVG, 100),
337 }; 336 };
diff --git a/subprojects/frontend/src/editor/GenerateButton.tsx b/subprojects/frontend/src/editor/GenerateButton.tsx
index 3837ef8e..5bac0464 100644
--- a/subprojects/frontend/src/editor/GenerateButton.tsx
+++ b/subprojects/frontend/src/editor/GenerateButton.tsx
@@ -4,10 +4,8 @@
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6 6
7import DangerousOutlinedIcon from '@mui/icons-material/DangerousOutlined'; 7import CancelIcon from '@mui/icons-material/Cancel';
8import PlayArrowIcon from '@mui/icons-material/PlayArrow'; 8import PlayArrowIcon from '@mui/icons-material/PlayArrow';
9import Button from '@mui/material/Button';
10import type { SxProps, Theme } from '@mui/material/styles';
11import { observer } from 'mobx-react-lite'; 9import { observer } from 'mobx-react-lite';
12 10
13import AnimatedButton from './AnimatedButton'; 11import AnimatedButton from './AnimatedButton';
@@ -18,26 +16,45 @@ const GENERATE_LABEL = 'Generate';
18const GenerateButton = observer(function GenerateButton({ 16const GenerateButton = observer(function GenerateButton({
19 editorStore, 17 editorStore,
20 hideWarnings, 18 hideWarnings,
21 sx,
22}: { 19}: {
23 editorStore: EditorStore | undefined; 20 editorStore: EditorStore | undefined;
24 hideWarnings?: boolean | undefined; 21 hideWarnings?: boolean | undefined;
25 sx?: SxProps<Theme> | undefined;
26}): JSX.Element { 22}): JSX.Element {
27 if (editorStore === undefined) { 23 if (editorStore === undefined) {
28 return ( 24 return (
29 <Button 25 <AnimatedButton color="inherit" disabled>
30 color="inherit"
31 className="rounded shaded"
32 disabled
33 {...(sx === undefined ? {} : { sx })}
34 >
35 Loading&hellip; 26 Loading&hellip;
36 </Button> 27 </AnimatedButton>
28 );
29 }
30
31 const { analyzing, errorCount, warningCount, semanticsError } =
32 editorStore.delayedErrors;
33
34 if (analyzing) {
35 return (
36 <AnimatedButton color="inherit" disabled>
37 Analyzing&hellip;
38 </AnimatedButton>
37 ); 39 );
38 } 40 }
39 41
40 const { errorCount, warningCount } = editorStore; 42 if (semanticsError !== undefined && editorStore.opened) {
43 return (
44 <AnimatedButton
45 color="error"
46 disabled
47 startIcon={<CancelIcon />}
48 sx={(theme) => ({
49 '&.Mui-disabled': {
50 color: `${theme.palette.error.main} !important`,
51 },
52 })}
53 >
54 Analysis error
55 </AnimatedButton>
56 );
57 }
41 58
42 const diagnostics: string[] = []; 59 const diagnostics: string[] = [];
43 if (errorCount > 0) { 60 if (errorCount > 0) {
@@ -54,8 +71,7 @@ const GenerateButton = observer(function GenerateButton({
54 aria-label={`Select next diagnostic out of ${summary}`} 71 aria-label={`Select next diagnostic out of ${summary}`}
55 onClick={() => editorStore.nextDiagnostic()} 72 onClick={() => editorStore.nextDiagnostic()}
56 color="error" 73 color="error"
57 startIcon={<DangerousOutlinedIcon />} 74 startIcon={<CancelIcon />}
58 {...(sx === undefined ? {} : { sx })}
59 > 75 >
60 {summary} 76 {summary}
61 </AnimatedButton> 77 </AnimatedButton>
@@ -67,7 +83,6 @@ const GenerateButton = observer(function GenerateButton({
67 disabled={!editorStore.opened} 83 disabled={!editorStore.opened}
68 color={warningCount > 0 ? 'warning' : 'primary'} 84 color={warningCount > 0 ? 'warning' : 'primary'}
69 startIcon={<PlayArrowIcon />} 85 startIcon={<PlayArrowIcon />}
70 {...(sx === undefined ? {} : { sx })}
71 > 86 >
72 {summary === '' ? GENERATE_LABEL : `${GENERATE_LABEL} (${summary})`} 87 {summary === '' ? GENERATE_LABEL : `${GENERATE_LABEL} (${summary})`}
73 </AnimatedButton> 88 </AnimatedButton>
@@ -76,7 +91,6 @@ const GenerateButton = observer(function GenerateButton({
76 91
77GenerateButton.defaultProps = { 92GenerateButton.defaultProps = {
78 hideWarnings: false, 93 hideWarnings: false,
79 sx: undefined,
80}; 94};
81 95
82export default GenerateButton; 96export default GenerateButton;