diff options
author | 2023-09-12 21:59:50 +0200 | |
---|---|---|
committer | 2023-09-12 21:59:50 +0200 | |
commit | a2a4696fdbd6440269d576aeba7b25b2ea40d9bf (patch) | |
tree | 5cbdf981a51a09fbe162e7748555d213ca518ff4 /subprojects/frontend/src/editor | |
parent | fix: avoid GLOP error message on stderr (diff) | |
download | refinery-a2a4696fdbd6440269d576aeba7b25b2ea40d9bf.tar.gz refinery-a2a4696fdbd6440269d576aeba7b25b2ea40d9bf.tar.zst refinery-a2a4696fdbd6440269d576aeba7b25b2ea40d9bf.zip |
feat: connect model generator to UI
Diffstat (limited to 'subprojects/frontend/src/editor')
-rw-r--r-- | subprojects/frontend/src/editor/EditorStore.ts | 85 | ||||
-rw-r--r-- | subprojects/frontend/src/editor/GenerateButton.tsx | 20 | ||||
-rw-r--r-- | subprojects/frontend/src/editor/GeneratedModelStore.ts | 50 |
3 files changed, 153 insertions, 2 deletions
diff --git a/subprojects/frontend/src/editor/EditorStore.ts b/subprojects/frontend/src/editor/EditorStore.ts index b5989ad1..f9a9a7da 100644 --- a/subprojects/frontend/src/editor/EditorStore.ts +++ b/subprojects/frontend/src/editor/EditorStore.ts | |||
@@ -32,6 +32,7 @@ import type XtextClient from '../xtext/XtextClient'; | |||
32 | import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults'; | 32 | import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults'; |
33 | 33 | ||
34 | import EditorErrors from './EditorErrors'; | 34 | import EditorErrors from './EditorErrors'; |
35 | import GeneratedModelStore from './GeneratedModelStore'; | ||
35 | import LintPanelStore from './LintPanelStore'; | 36 | import LintPanelStore from './LintPanelStore'; |
36 | import SearchPanelStore from './SearchPanelStore'; | 37 | import SearchPanelStore from './SearchPanelStore'; |
37 | import createEditorState from './createEditorState'; | 38 | import createEditorState from './createEditorState'; |
@@ -69,6 +70,10 @@ export default class EditorStore { | |||
69 | 70 | ||
70 | graph: GraphStore; | 71 | graph: GraphStore; |
71 | 72 | ||
73 | generatedModels = new Map<string, GeneratedModelStore>(); | ||
74 | |||
75 | selectedGeneratedModel: string | undefined; | ||
76 | |||
72 | constructor(initialValue: string, pwaStore: PWAStore) { | 77 | constructor(initialValue: string, pwaStore: PWAStore) { |
73 | this.id = nanoid(); | 78 | this.id = nanoid(); |
74 | this.state = createEditorState(initialValue, this); | 79 | this.state = createEditorState(initialValue, this); |
@@ -307,4 +312,84 @@ export default class EditorStore { | |||
307 | this.delayedErrors.dispose(); | 312 | this.delayedErrors.dispose(); |
308 | this.disposed = true; | 313 | this.disposed = true; |
309 | } | 314 | } |
315 | |||
316 | startModelGeneration(): void { | ||
317 | this.client | ||
318 | ?.startModelGeneration() | ||
319 | ?.catch((error) => log.error('Could not start model generation', error)); | ||
320 | } | ||
321 | |||
322 | addGeneratedModel(uuid: string): void { | ||
323 | this.generatedModels.set(uuid, new GeneratedModelStore()); | ||
324 | this.selectGeneratedModel(uuid); | ||
325 | } | ||
326 | |||
327 | cancelModelGeneration(): void { | ||
328 | this.client | ||
329 | ?.cancelModelGeneration() | ||
330 | ?.catch((error) => log.error('Could not start model generation', error)); | ||
331 | } | ||
332 | |||
333 | selectGeneratedModel(uuid: string | undefined): void { | ||
334 | if (uuid === undefined) { | ||
335 | this.selectedGeneratedModel = uuid; | ||
336 | return; | ||
337 | } | ||
338 | if (this.generatedModels.has(uuid)) { | ||
339 | this.selectedGeneratedModel = uuid; | ||
340 | return; | ||
341 | } | ||
342 | this.selectedGeneratedModel = undefined; | ||
343 | } | ||
344 | |||
345 | deleteGeneratedModel(uuid: string | undefined): void { | ||
346 | if (uuid === undefined) { | ||
347 | return; | ||
348 | } | ||
349 | if (this.selectedGeneratedModel === uuid) { | ||
350 | let previous: string | undefined; | ||
351 | let found: string | undefined; | ||
352 | this.generatedModels.forEach((_value, key) => { | ||
353 | if (key === uuid) { | ||
354 | found = previous; | ||
355 | } | ||
356 | previous = key; | ||
357 | }); | ||
358 | this.selectGeneratedModel(found); | ||
359 | } | ||
360 | const generatedModel = this.generatedModels.get(uuid); | ||
361 | if (generatedModel !== undefined && generatedModel.running) { | ||
362 | this.cancelModelGeneration(); | ||
363 | } | ||
364 | this.generatedModels.delete(uuid); | ||
365 | } | ||
366 | |||
367 | modelGenerationCancelled(): void { | ||
368 | this.generatedModels.forEach((value) => | ||
369 | value.setError('Model generation cancelled'), | ||
370 | ); | ||
371 | } | ||
372 | |||
373 | setGeneratedModelMessage(uuid: string, message: string): void { | ||
374 | this.generatedModels.get(uuid)?.setMessage(message); | ||
375 | } | ||
376 | |||
377 | setGeneratedModelError(uuid: string, message: string): void { | ||
378 | this.generatedModels.get(uuid)?.setError(message); | ||
379 | } | ||
380 | |||
381 | setGeneratedModelSemantics( | ||
382 | uuid: string, | ||
383 | semantics: SemanticsSuccessResult, | ||
384 | ): void { | ||
385 | this.generatedModels.get(uuid)?.setSemantics(semantics); | ||
386 | } | ||
387 | |||
388 | get generating(): boolean { | ||
389 | let generating = false; | ||
390 | this.generatedModels.forEach((value) => { | ||
391 | generating = generating || value.running; | ||
392 | }); | ||
393 | return generating; | ||
394 | } | ||
310 | } | 395 | } |
diff --git a/subprojects/frontend/src/editor/GenerateButton.tsx b/subprojects/frontend/src/editor/GenerateButton.tsx index 5bac0464..b8dcd531 100644 --- a/subprojects/frontend/src/editor/GenerateButton.tsx +++ b/subprojects/frontend/src/editor/GenerateButton.tsx | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | import CancelIcon from '@mui/icons-material/Cancel'; | 7 | import CancelIcon from '@mui/icons-material/Cancel'; |
8 | import CloseIcon from '@mui/icons-material/Close'; | ||
8 | import PlayArrowIcon from '@mui/icons-material/PlayArrow'; | 9 | import PlayArrowIcon from '@mui/icons-material/PlayArrow'; |
9 | import { observer } from 'mobx-react-lite'; | 10 | import { observer } from 'mobx-react-lite'; |
10 | 11 | ||
@@ -28,8 +29,10 @@ const GenerateButton = observer(function GenerateButton({ | |||
28 | ); | 29 | ); |
29 | } | 30 | } |
30 | 31 | ||
31 | const { analyzing, errorCount, warningCount, semanticsError } = | 32 | const { |
32 | editorStore.delayedErrors; | 33 | delayedErrors: { analyzing, errorCount, warningCount, semanticsError }, |
34 | generating, | ||
35 | } = editorStore; | ||
33 | 36 | ||
34 | if (analyzing) { | 37 | if (analyzing) { |
35 | return ( | 38 | return ( |
@@ -39,6 +42,18 @@ const GenerateButton = observer(function GenerateButton({ | |||
39 | ); | 42 | ); |
40 | } | 43 | } |
41 | 44 | ||
45 | if (generating) { | ||
46 | return ( | ||
47 | <AnimatedButton | ||
48 | color="inherit" | ||
49 | onClick={() => editorStore.cancelModelGeneration()} | ||
50 | startIcon={<CloseIcon />} | ||
51 | > | ||
52 | Cancel | ||
53 | </AnimatedButton> | ||
54 | ); | ||
55 | } | ||
56 | |||
42 | if (semanticsError !== undefined && editorStore.opened) { | 57 | if (semanticsError !== undefined && editorStore.opened) { |
43 | return ( | 58 | return ( |
44 | <AnimatedButton | 59 | <AnimatedButton |
@@ -83,6 +98,7 @@ const GenerateButton = observer(function GenerateButton({ | |||
83 | disabled={!editorStore.opened} | 98 | disabled={!editorStore.opened} |
84 | color={warningCount > 0 ? 'warning' : 'primary'} | 99 | color={warningCount > 0 ? 'warning' : 'primary'} |
85 | startIcon={<PlayArrowIcon />} | 100 | startIcon={<PlayArrowIcon />} |
101 | onClick={() => editorStore.startModelGeneration()} | ||
86 | > | 102 | > |
87 | {summary === '' ? GENERATE_LABEL : `${GENERATE_LABEL} (${summary})`} | 103 | {summary === '' ? GENERATE_LABEL : `${GENERATE_LABEL} (${summary})`} |
88 | </AnimatedButton> | 104 | </AnimatedButton> |
diff --git a/subprojects/frontend/src/editor/GeneratedModelStore.ts b/subprojects/frontend/src/editor/GeneratedModelStore.ts new file mode 100644 index 00000000..d0181eed --- /dev/null +++ b/subprojects/frontend/src/editor/GeneratedModelStore.ts | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | |||
7 | import { makeAutoObservable } from 'mobx'; | ||
8 | |||
9 | import GraphStore from '../graph/GraphStore'; | ||
10 | import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults'; | ||
11 | |||
12 | export default class GeneratedModelStore { | ||
13 | title: string; | ||
14 | |||
15 | message = 'Waiting for server'; | ||
16 | |||
17 | error = false; | ||
18 | |||
19 | graph: GraphStore | undefined; | ||
20 | |||
21 | constructor() { | ||
22 | const time = new Date().toLocaleTimeString(undefined, { hour12: false }); | ||
23 | this.title = `Generated at ${time}`; | ||
24 | makeAutoObservable(this); | ||
25 | } | ||
26 | |||
27 | get running(): boolean { | ||
28 | return !this.error && this.graph === undefined; | ||
29 | } | ||
30 | |||
31 | setMessage(message: string): void { | ||
32 | if (this.running) { | ||
33 | this.message = message; | ||
34 | } | ||
35 | } | ||
36 | |||
37 | setError(message: string): void { | ||
38 | if (this.running) { | ||
39 | this.error = true; | ||
40 | this.message = message; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | setSemantics(semantics: SemanticsSuccessResult): void { | ||
45 | if (this.running) { | ||
46 | this.graph = new GraphStore(); | ||
47 | this.graph.setSemantics(semantics); | ||
48 | } | ||
49 | } | ||
50 | } | ||