feat(gui): wire the Form View entry points and turn it on - #8456
feat(gui): wire the Form View entry points and turn it on#8456yangzhang75 wants to merge 1 commit into
Conversation
Automated Reviewer SuggestionsBased on the
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #8456 +/- ##
============================================
+ Coverage 95.88% 95.90% +0.01%
Complexity 459 459
============================================
Files 588 589 +1
Lines 33802 33946 +144
Branches 4217 4244 +27
============================================
+ Hits 32411 32555 +144
Misses 813 813
Partials 578 578
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 363 | 0.222 | 28,281/34,499/34,499 us | 🔴 +12.5% / 🔴 +130.3% |
| 🔴 | bs=100 sw=10 sl=64 | 816 | 0.498 | 119,931/141,515/141,515 us | 🔴 +8.8% / 🔴 +37.8% |
| ⚪ | bs=1000 sw=10 sl=64 | 907 | 0.554 | 1,099,779/1,225,814/1,225,814 us | ⚪ within ±5% / 🔴 +25.1% |
Baseline details
Latest main 7190a81 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 363 tuples/sec | 377 tuples/sec | 807.77 tuples/sec | -3.7% | -55.1% |
| bs=10 sw=10 sl=64 | MB/s | 0.222 MB/s | 0.23 MB/s | 0.493 MB/s | -3.5% | -55.0% |
| bs=10 sw=10 sl=64 | p50 | 28,281 us | 25,134 us | 12,280 us | +12.5% | +130.3% |
| bs=10 sw=10 sl=64 | p95 | 34,499 us | 37,873 us | 15,066 us | -8.9% | +129.0% |
| bs=10 sw=10 sl=64 | p99 | 34,499 us | 37,873 us | 19,166 us | -8.9% | +80.0% |
| bs=100 sw=10 sl=64 | throughput | 816 tuples/sec | 829 tuples/sec | 1,054 tuples/sec | -1.6% | -22.6% |
| bs=100 sw=10 sl=64 | MB/s | 0.498 MB/s | 0.506 MB/s | 0.643 MB/s | -1.6% | -22.6% |
| bs=100 sw=10 sl=64 | p50 | 119,931 us | 120,048 us | 96,023 us | -0.1% | +24.9% |
| bs=100 sw=10 sl=64 | p95 | 141,515 us | 130,031 us | 102,660 us | +8.8% | +37.8% |
| bs=100 sw=10 sl=64 | p99 | 141,515 us | 130,031 us | 114,950 us | +8.8% | +23.1% |
| bs=1000 sw=10 sl=64 | throughput | 907 tuples/sec | 924 tuples/sec | 1,086 tuples/sec | -1.8% | -16.5% |
| bs=1000 sw=10 sl=64 | MB/s | 0.554 MB/s | 0.564 MB/s | 0.663 MB/s | -1.8% | -16.5% |
| bs=1000 sw=10 sl=64 | p50 | 1,099,779 us | 1,073,687 us | 940,412 us | +2.4% | +16.9% |
| bs=1000 sw=10 sl=64 | p95 | 1,225,814 us | 1,179,829 us | 979,930 us | +3.9% | +25.1% |
| bs=1000 sw=10 sl=64 | p99 | 1,225,814 us | 1,179,829 us | 1,015,625 us | +3.9% | +20.7% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,550.71,200,128000,363,0.222,28281.45,34498.61,34498.61
1,100,10,64,20,2450.35,2000,1280000,816,0.498,119930.80,141514.76,141514.76
2,1000,10,64,20,22052.80,20000,12800000,907,0.554,1099779.27,1225813.77,1225813.7772bb5b2 to
3fb3a3f
Compare
3fb3a3f to
b149959
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Read-only inspection can mutate shared workflow state, while several entry-point and persistence paths remain incomplete or unreliable.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Completes the Form View rollout by adding authoring, navigation entry points, default-view persistence, and computing-unit recall.
Changes:
- Adds in-place Form View authoring and step inspection.
- Adds dashboard/menu navigation and default-view import/export.
- Enables Form View by default and remembers computing-unit selection.
File summaries
| File | Description |
|---|---|
form-binding.service.ts |
Updates result-selection documentation. |
workflow-form.spec-harness.ts |
Expands authoring and selection mocks. |
workflow-form.rendered.spec.ts |
Stubs the embedded property editor. |
workflow-form.component.ts |
Adds inspection and authoring behavior. |
workflow-form.component.spec.ts |
Tests inspection and authoring. |
workflow-form.component.scss |
Styles inspection and authoring UI. |
workflow-form.component.html |
Renders authoring controls and property panel. |
property-editor.component.ts |
Adds placement and broadcast controls. |
property-editor.component.spec.ts |
Tests new property-editor controls. |
operator-property-edit-frame.component.ts |
Suppresses selected shared-model writes. |
operator-property-edit-frame.component.spec.ts |
Tests broadcast suppression. |
computing-unit-selection.component.ts |
Persists selections per workflow. |
computing-unit-selection.component.spec.ts |
Tests computing-unit recall. |
menu.component.ts |
Adds Canvas-to-Form navigation. |
menu.component.spec.ts |
Tests persistence before switching. |
menu.component.scss |
Styles the view switch. |
menu.component.html |
Renders the view switch. |
download.service.ts |
Exports the default view. |
download.service.spec.ts |
Tests exported metadata. |
user-workflow.component.ts |
Imports the default view. |
user-workflow.component.spec.ts |
Tests legacy and new imports. |
list-item.component.ts |
Applies and toggles landing views. |
list-item.component.spec.ts |
Tests default-view behavior. |
list-item.component.scss |
Styles form-default entries. |
list-item.component.html |
Adds the default-view action. |
workflow-persist.service.ts |
Sends default view during creation. |
workflow-persist.service.spec.ts |
Tests creation payloads. |
formly-config.ts |
Registers the editable-label wrapper. |
editable-label-wrapper.component.ts |
Implements editable field labels. |
editable-label-wrapper.component.spec.ts |
Tests label editing and hiding. |
editable-label-wrapper.component.scss |
Styles editable labels. |
editable-label-wrapper.component.html |
Renders label controls. |
GuiConfigSpec.scala |
Updates the enabled-default assertion. |
gui.conf |
Enables Form View by default. |
Review details
- Files reviewed: 34/34 changed files
- Comments generated: 11
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
dcccaf1 to
3074a06
Compare
2006fad to
125e1a6
Compare
### What changes were proposed in this PR? Closes apache#8496. A regression from apache#8125: since then, every workflow's second autosave (and every one after it) fails with 500, silently on the operator canvas and as "Could not save" on the Form View. `persistWorkflow` wrote `is_public` from the request. The frontend feeds the saved row straight back as its metadata, and that row names the flag `isPublic` while the rest of the frontend calls it `isPublished`, so the very next save went out without the flag, the update wrote NULL into a NOT NULL column, and the request failed. A stale `isPublic: false` on a save could likewise un-publish a published workflow. - Backend: `saveWorkflowFields` now writes name, description and content only. Publishing stays with `/public` and `/private`, `default_view` with `/set-default-view`, and the timestamps are not rewritten, so a save can never clobber a concurrent change to any of them. - Frontend: `WorkflowPersistService.persistWorkflow` no longer sends `isPublic` (the endpoint does not read it, and the value is not reliably known after the first save), and `WorkflowUtilService.parseWorkflowInfo` carries a persist response's `isPublic` over to `isPublished`, so metadata fed back from a save keeps the publish state instead of dropping it. The Form View stack is not blocked by this: apache#8455 touches none of these files, and apache#8456 touches `workflow-persist.service.ts` only in `createWorkflow` (adding `defaultView`), a different function; a dry-run merge of the two is clean. ### Any related issues, documentation, discussions? Closes apache#8496. Found while verifying apache#8455 on a flag-on instance (parent apache#8011). ### How was this PR tested? Backend: `WorkflowResourceSpec` gains two tests, a save carrying no flag neither fails nor changes `is_public` after `/public`, and a save carrying `false` does not un-publish; the existing default-view save test was updated to send no flag, as the frontend does. `WorkflowResourceSpec` and `PublishedCopySchemaSpec` pass (87 tests), scalafmt clean. Frontend: the persist spec asserts the save payload carries no `isPublic` and that the response's `isPublic` comes back as `isPublished`; `parseWorkflowInfo` gains tests for the carry-over and for leaving a present `isPublished` alone. Full suite passes (5777), changed lines fully covered, eslint, prettier and the production (AOT) build pass. End to end, against a running stack rebuilt with this change: the exact second-save payload that returned 500 now returns 200 with `is_public` unchanged; a create-through-persist with the new payload inserts with `is_public = false`; and in a headless browser the Form View renames a workflow twice with every `/api/workflow/persist` answering 200, no `isPublic` key in any request body, and no "Could not save". ### Was this PR authored or co-authored using generative AI tooling? Yes. Generated-by: Claude Code (Claude Fable 5.1, Anthropic). Co-authored with Claude, reviewed line by line by the author before submission. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Meng Wang <mengw15@uci.edu>
The workspace menu's export test module-mocked the CommonJS file-saver
package (vi.mock("file-saver")). Under the Angular unit-test builder that
call ends up inside the built spec chunk rather than at its top level
(Vitest warns about it on every platform), and once this stack shifted the
shared chunk graph the mock stopped applying on the Windows leg: the real
saveAs ran and the spy saw 0 calls (7 of the last 8 Windows runs on apache#8455
and apache#8456, while main and apache#8499 pass).
Route the download through the existing injectable FileSaverService, as
the dashboard downloads already do, and stub that with TestBed, which does
not depend on mock hoisting. No behaviour change.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
125e1a6 to
379293f
Compare
The workspace menu's export test module-mocked the CommonJS file-saver
package (vi.mock("file-saver")). Under the Angular unit-test builder that
call ends up inside the built spec chunk rather than at its top level
(Vitest warns about it on every platform), and once this stack shifted the
shared chunk graph the mock stopped applying on the Windows leg: the real
saveAs ran and the spy saw 0 calls (7 of the last 8 Windows runs on apache#8455
and apache#8456, while main and apache#8499 pass).
Route the download through the existing injectable FileSaverService, as
the dashboard downloads already do, and stub that with TestBed, which does
not depend on mock hoisting. No behaviour change.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
ff7d8e6 to
cef8521
Compare
cef8521 to
d8723f8
Compare
The workspace menu's export test module-mocked the CommonJS file-saver
package (vi.mock("file-saver")). Under the Angular unit-test builder that
call ends up inside the built spec chunk rather than at its top level
(Vitest warns about it on every platform), and once this stack shifted the
shared chunk graph the mock stopped applying on the Windows leg: the real
saveAs ran and the spy saw 0 calls (7 of the last 8 Windows runs on apache#8455
and apache#8456, while main and apache#8499 pass).
Route the download through the existing injectable FileSaverService, as
the dashboard downloads already do, and stub that with TestBed, which does
not depend on mock hoisting. No behaviour change.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
e3dc39c to
1a274e7
Compare
The workspace menu's export test module-mocked the CommonJS file-saver
package (vi.mock("file-saver")). Under the Angular unit-test builder that
call ends up inside the built spec chunk rather than at its top level
(Vitest warns about it on every platform), and once this stack shifted the
shared chunk graph the mock stopped applying on the Windows leg: the real
saveAs ran and the spy saw 0 calls (7 of the last 8 Windows runs on apache#8455
and apache#8456, while main and apache#8499 pass).
Route the download through the existing injectable FileSaverService, as
the dashboard downloads already do, and stub that with TestBed, which does
not depend on mock hoisting. No behaviour change.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
9f8c9d2 to
b0752fa
Compare
…uthoring (apache#8516) ### What changes were proposed in this PR? Closes apache#8026. Part of the Form View stack (parent issue apache#8011), on main. This is the first half of what was apache#8455 (closed, split in two at 2200 lines); the second half, authoring the inputs themselves, is apache#8517 stacked on this one. Four commits: the first is the feature, the second and third are test-only follow-ups (the Windows CI leg and the template coverage report), and the last opens the result picker to everyone with one saved list of shown results (the design changes asked for in review, mengw15's list shape included). The review commit is the branch tip. Adds the edit mode of the page and the page-level authoring it enables. - `toggleAuthoring`: with write access, Edit turns the page into in-place authoring; Done returns it to the reader state. Edit mode is the only state that enables workflow modification here (`applyEditability`), and entering it is refused without write access at the method itself, not only by hiding the button. - The inspect panel goes live in edit mode: it acts as an editor (`actsAsEditor`), its expose tick boxes are on (`exposeChoosing`), and `inert` comes off, so the author opens a step on the embedded preview and chooses which of its settings people fill in right there. It stays inert and read-only for everyone else, as before. - The embedded preview's right-click menu carries the structure lock. The menu's re-shaping commands followed the modification flag alone, so re-enabling it for the panel would have offered cut, paste, delete and disable on the structure-locked preview. `texera-context-menu` now takes `[structureLocked]` from the editor and gates those on modification AND no lock (`canModify`); copy, the result toggles, execute-to and export do not re-shape the graph and are unchanged. - Write the author's instruction in place: the heading is edited in the header (a row rather than one button, so the input is not nested in a control) and the body as markdown with Write / Preview tabs. A reader still sees it rendered, only when there is text. - Pick which results to show, for everyone: the picker lists the final steps and the intermediate steps that have view-result on the canvas, and rebuilds live when an eye is toggled or the graph's shape or names change (a step deleted, disabled, given a downstream link, or renamed, a co-editor's edit included), from the graph's own streams rather than only after the debounced compilation. What shows is one saved list, `shownResultIds` (the shape mengw15 proposed): absent, every final step shows, as on the canvas; once the author has chosen, exactly the listed steps show, and `[]` means none, a choice the earlier pair of opposite-signed lists (featured / turned off) could not store and could contradict each other on. In edit mode a pill adds the step to or removes it from that list; the first choice starts the list from the final steps at that moment, so nothing the author saw disappears. The accepted cost: a step that becomes final after the author has chosen does not appear by itself. A definition whose only content is that list, an empty one included, is still saved. A listed step whose eye has since been turned off stays offered in edit mode only, so the author can take it off the list; a reader is not offered a pill that could never turn on. Anyone else, a writer merely viewing included, gets the same picker but changes only their own view of the page; nothing is written, so a reader without write access can choose too, and the choice lasts for the page. A disabled step is neither offered nor shown, eye or no eye: the compiled plan leaves it out. - Edit mode is the only state that unlocks the graph from this page, and only while no run is in flight (the canvas rule, kept so that entering edit mode mid-run cannot undo it). The lock is a root-level flag with writers that know nothing of this page: the execute service unlocks it whenever a run ends (completed, failed, killed, reset), and the computing-unit selector embedded here unlocks it when it finds no run on the chosen unit. Rather than chase each caller, the page clamps at the stream they all report to (`getWorkflowModificationEnabledStream`): whenever the flag turns on while the page must stay locked, it is turned off again, so a writer merely viewing can never reach the preview's view-result command. In edit mode the canvas rule stands: locked while running, unlocked when the run ends. The clamp runs a microtask after the unlocking call, never inside it: `enableWorkflowModification` enables undo/redo after it emits, and the stream still has other subscribers to reach, so a nested disable would leave them on the stale "true"; run afterwards, the disable is the last word and every consumer sees one locked state. The execute service flips the lock before it emits the new state; by the time the clamp looks, the execution-state handler has re-applied the same rule with the final state, so in edit mode the unlock stands. The step panel follows the same rule (`panelLive`), not edit mode alone: the property frame does not consult the lock before its own writes (the version sync on mount, the schema defaults ajv fills in, the editing marker), so a step selected while a run is in flight stays a read-only, inert mount even in edit mode and turns live when the run ends. Done dismisses the step panel before leaving edit mode, while the frame is still an editor: that is the only state in which the property editor clears the "currently editing" marker co-editors see. - The embedded preview grows no editing buttons: no link tools on hover (remove, breakpoint), and a selected operator unfolds its state and port counts but not its delete, chat and add/remove-port buttons. None of them can act on the structure-locked preview, so they only suggested it could be edited. - Open canvas saves first and hands over only once the save has completed: the switch is a full-page load, which aborts a request still in flight. Saves go out one at a time, in order: two persists in flight at once can reach the backend out of order and the older content would win, so the switch's save waits for an autosave already on its way, and the page hands over only once the queue has drained: that save and any asked for while it was in flight (the page stays interactive until the hand-over) have completed; each request carries the workflow as it was when the save was asked for, so the last one enqueued is the latest. The drain outlives the page: the final save on the way out joins the same queue rather than racing an autosave still in flight, and the queue is closed after it. A failed save keeps the author on the form with the error shown and does not stop the queue; a reader with nothing to save goes straight through. A save's response feeds back the server-owned metadata (the timestamp, and the normalised name when nothing changed) but never undoes a rename made while it was in flight, and repaints nothing once the page is gone. (apache#8456 does the save-then-navigate part on the canvas side.) - Keyboard focus is visible on the pill and tab buttons (`:focus-visible`). The picker's pills are tracked by step (`trackBy`): a toggle re-reads the config and rebuilds the choices as new objects, and re-created buttons would have dropped the keyboard focus from the pill just pressed. The instruction body carries an `aria-label`, since its placeholder is gone as soon as there is text. - `29c54bb85` (test only, workspace menu): the menu's export test module-mocked the CommonJS `file-saver` package with `vi.mock`. Under the Angular unit-test builder that call is not reliably hoisted (Vitest warns about it on every platform), and with this stack's shared-chunk graph it stopped applying on the Windows leg (7 of the last 8 Windows runs of the unsplit PR, while main passes). The export now goes through the existing injectable `FileSaverService`, as the dashboard downloads already do, and the spec stubs that with TestBed. No behaviour change. - `695c2fb4f` (test only, Form View rendered spec): the spec swapped the property panel for a stub by overriding the page's imports, which JIT-recompiles the page; a JIT template has no mapping back to the `.component.html`, so the page's template read as 0% covered on codecov from apache#8442 on (the 10 "missing" template lines there, 132 on the unsplit PR). The real panel's template is blanked instead, with its lifecycle hooks switched off, so the page stays AOT-compiled and its template is measured again. The edit-mode markup this PR adds is then covered through the DOM: Edit / Done, the Write / Preview tabs, heading and body writing through, the picker's pills and empty hint. The diff is about 1400 added lines because 725 of them are spec against 694 of source (of which 192 are stylesheet); the two test-only commits and the review-driven redesign of the picker are a large part of it, and the feature itself is under 700 lines. Not in this PR: renaming, hiding, reordering, help text and removal of the exposed inputs, and the author's view of a broken input. Those are apache#8517. ### Any related issues, documentation, discussions? Closes apache#8026. Part of the Form View feature (parent issue apache#8011). Replaces the first half of apache#8455. ### How was this PR tested? Unit tests (vitest). Direct-construction tests cover the authoring gate (enter, leave, refused without write access, always allowed to leave), the result picker's range (final steps until the author chooses, then exactly the saved list, `[]` included; viewed and listed intermediates; disabled steps left out), its live rebuild on an eye toggle, the edit-mode toggle writing the default (the saved list started from the final steps on the first choice), a viewer's own toggle writing nothing and giving way on entering edit mode, a reader not offered a saved pick whose eye is off, the lock clamped back whenever anything else unlocks the graph outside edit mode, unlocked in edit mode once a run has ended in the execute service's real order (unlock before state), and kept locked when edit mode is entered mid-run, the switch's save queued behind an autosave in flight with navigation after both, the final save on the way out drained behind an autosave in flight after the page is gone, a failed save not stopping the queue, a failed final save still reported without throwing, an older save's response not undoing a rename made meanwhile and no metadata repaint after the page is gone, a shown step dropped from the cards and the picker the moment the graph's shape makes it unavailable, a pill renamed the moment its step's display name changes, the hand-over waiting for a save queued behind the switch's and staying put when that save fails, the step panel dismissed on Done while the frame is still an editor, the instruction writes going through the binding service, and the switch's save-then-navigate order (navigates on complete, stays on error, straight through for a reader). The rendered spec covers the edit-mode header shape (title input outside the toggle, `aria-controls`), the panel turning live in edit mode (editor on, tick boxes on, inert off), and the panel staying read-only while a run is in flight even in edit mode, turning live when the run ends. The context menu's spec renders it under a structure lock with modification enabled and checks cut, paste, delete, disable and enable are off while copy and the result toggle stay; the editor's spec opens the right-click menu on a locked editor and checks the lock arrived, and checks a locked preview grows no link tools on hover or on add, and keeps a selected operator's delete, chat and port buttons hidden while its state still unfolds, while the canvas shows all of them. The binding service's spec checks the first choice starts the list from the default handed in, later choices flip within the list ignoring the default, and turning off the only shown step leaves `[]` rather than an absent list; the action service's spec checks a definition whose only content is `shownResultIds: []` is still carried in the saved content. Each new guard was deletion-checked (removing it turns the corresponding test red). eslint, prettier and the production (AOT) build pass; every changed line, template lines included, is statement and function covered (5830 tests). #### Video https://github.com/user-attachments/assets/ca2f8e99-357a-48f7-95cb-6bf4e57c1bc4 ### Was this PR authored or co-authored using generative AI tooling? Yes. Generated-by: Claude Code (Claude Fable 5.1, Anthropic). Co-authored with Claude, reviewed line by line by the author before submission. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Meng Wang <mengw15@uci.edu> Co-authored-by: mengw15 <125719918+mengw15@users.noreply.github.com>
Now that the Form View is complete, wire it into the app and flip the flag on. A workflow opens in its default view: the dashboard card deep-links a form-default one straight into the form (with the Form View icon) and carries a per-card toggle to change the default via set-default-view; a canvas-default one is unchanged. Either view switches to the other at any time from the same control in the operator canvas menu. The page redirects to the canvas only when the flag is off. The picked computing unit is remembered per workflow (localStorage) so it survives the full-page reload between the two views. Download-then-upload round-trips the landing view: the exported JSON carries default_view as a sibling of the content, and upload pulls it back onto the workflow row rather than into the content. Flips form-view-enabled on by default. Saves now go out one at a time and in call order (WorkflowPersistService), so the switch's save lands after an autosave already in flight; an edit made while the switch's save is out is saved once more before the hand-over; a second click mid hand-over is a no-op. Only the user's own pick of a computing unit is remembered, not the units selected on load. The dashboard toggle handlers check WRITE access themselves. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
b0752fa to
5db7eef
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Read-only switching, save-drain races, stale computing-unit callbacks, and canvas export round-tripping remain incorrect.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
frontend/src/app/workspace/component/menu/menu.component.ts:671
- This dirty marker only observes graph/form-binding events; workflow-name edits emit
workflowMetaDataChanged()instead. If the name is committed while this save is in flight, its queued save starts after this one, but this completion immediately unloads the page and can abort it; the response also temporarily overwrites the new name. Preserve and mark a name that changed after the snapshot so the hand-over performs its final save before navigating.
// The snapshot below carries everything reported up to now.
this.editedSinceSwitchSnapshot = false;
this.workflowPersistService
.persistWorkflow(this.workflowActionService.getWorkflow())
- Files reviewed: 24/24 changed files
- Comments generated: 3
- Review effort level: Balanced
| map(({ content, defaultView }) => { | ||
| // Carry the landing view so a download-then-upload keeps a form-default workflow opening | ||
| // as a form. It goes in as one extra top-level key next to the workflow's own | ||
| // (operators/links/...); the importer destructures it back out (see uploadWorkflow), and an | ||
| // older importer that reads the whole object as content simply ignores the unknown key. | ||
| const exported = defaultView === undefined ? content : { ...content, defaultView }; | ||
| const workflowJson = JSON.stringify(exported, null, 2); |
| this.handingOverToFormView = true; | ||
| this.isSaving = true; | ||
| this.saveThenOpenFormView(wid); |
| next: (latestWorkflowExecution: WorkflowExecutionsEntry) => { | ||
| this.selectComputingUnit(wid, latestWorkflowExecution.cuId); | ||
| }, | ||
| error: () => { | ||
| const runningUnit = this.allComputingUnits.find(unit => unit.status === "Running"); | ||
| if (runningUnit) { | ||
| this.selectComputingUnit(wid, runningUnit.computingUnit.cuid); | ||
| } | ||
| }, |
What changes were proposed in this PR?
Closes #8028. Part of the Form View stack (parent issue #8011), on main now that #8516 and #8517 have merged. The review commit is the branch's single commit.
Wires the Form View entry points and turns the feature on.
default_view(form or canvas), with a toggle that persists the choice; the deep link goes to the existing/workflow/:id/formroute. Both renderers of the dashboard, the list row and the card, follow one shared rule (default-view-landing.ts: mark, deep link, toggle), so switching the view mode does not lose the entry point. The toggle is offered only with WRITE access, which the endpoint requires, and the handler checks the same rule rather than trusting the template; it is a proper toggle button (constant accessible name, state inaria-pressed, the hover title spelling out what a click does); hub links are left untouched.WorkflowPersistServicenow sends saves one at a time and in call order, at the one place every save goes through, so the switch's save lands and completes after it; each caller still gets only its own result and a failed save does not hold up the next), and an edit made while the switch's save is out (the page stays editable until the load;workflowChangedmarks it and the hand-over saves once more before leaving). A second click while the hand-over is in progress is a no-op. A failed save keeps the user on the canvas with the error shown. Every workflow offers both views whenever the flag is on:default_viewonly decides the landing view, and neither view gates the other.defaultViewas a sibling key next to the workflow content; an old export without it imports unchanged.form-view-enabledto true, with the GuiConfigSpec assertion updated to match.Any related issues, documentation, discussions?
Closes #8028. Part of the Form View feature (parent issue #8011).
How was this PR tested?
Unit tests (vitest) cover the menu's Canvas / Form View switch through the DOM (absent with the flag off, Canvas pressed, Form View handing over, hidden while an older version is displayed), the row's and the card's default-view behavior (mark and deep link, hub link untouched, flag off leaves the dashboard as today, WRITE-only toggle in the DOM, toggle on / off / failed request / no cached row), the menu switch (navigates only once the save completes, stays on the canvas with the error when it fails, saves once more when an edit lands while its save is out, ignores a second click mid hand-over), the persist service sending saves one at a time in order with each caller getting its own result and a failure not holding up the next, the dashboard toggle handlers refusing without WRITE access, the toggle's aria-pressed following the state, the export/import round-trip including a legacy file without
defaultView, and the computing-unit recall (waits for the first non-empty unit list, forgets a terminated unit and falls back, drops a stale decision after the workflow changed, positive-integer validation, storage failures, only an explicit pick remembered). GuiConfigSpec asserts the flag. Each new guard was deletion-checked (removing it turns the corresponding test red). eslint, prettier and the production (AOT) build pass; every changed line, template lines included, is statement and function covered.Video
1. Default view on the dashboard
(row and card toggle, Form View icon, deep link into the form, toggle off again, no toggle without write access)
2. Canvas / Form View switch
(save first, then the hand-over; and back)
3. Computing unit remembered across the switch
4. Download / upload keeps the default view
Was this PR authored or co-authored using generative AI tooling?
Yes. Generated-by: Claude Code (Claude Fable 5.1, Anthropic). Co-authored with Claude, reviewed line by line by the author before submission.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY