Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ui): improve editor performance and fix Submit button. Fixes #13892 #13915

Merged
merged 2 commits into from
Nov 22, 2024

Conversation

MasonM
Copy link
Contributor

@MasonM MasonM commented Nov 18, 2024

Fixes #13892

Motivation

The <ObjectEditor> component used by all the edit pages encapsulates the logic for serializing/deserializing the object being edited, but it's extremely inefficient. For example, if you're editing a WorkflowTemplate, every single keystroke will cause parse() to be called twice and stringify() to be called 4 times. For large documents, this serialization/deserialization overhead adds up quickly.

Additionally, the "Submit" button is sometimes incorrectly grayed out, e.g. after clicking the "Update" button. This is happening because useEditableObject() is using reference comparisons on the object being edited, since it doesn't have access to the serialized string version encapsulated by <ObjectEditor>.

Modifications

This decouples <ObjectEditor> from the serialization/deseralization logic and lifts the state involved up to the useEditableObject() hook, as discussed in #13593 (comment). Doing so eliminates unnecessary serialization/deseralization: now, if you're editing a WorkflowTemplate, each keystroke will only call parse() once and won't call stringify() at all. This also fixes issues with the Submit button not reflecting the current page state, since useEditableObject() now uses string comparisons instead of ref comparisons.

Also, I did some minor cleanup:

  • Delete ui/src/cluster-workflow-templates/cluster-workflow-template-editor.tsx because it was identical to ui/src/workflow-templates/workflow-template-editor.tsx
  • Delete ui/src/shared/components/resource-editor/resource.scss because it stopped being used in feat(ui): Argo Events API and UI. Fixes #888 #4470
  • Delete ui/src/shared/components/resource-editor/resource-editor.tsx, which was a thin wrapper around <ObjectEditor>, because the only files using it weren't actually passing any of the props (e.g. onSubmit) that enabled the extra functionality.

Verification

Followed these steps to verify on each of the following pages: http://localhost:8080/workflow-templates, http://localhost:8080/cluster-workflow-templates, http://localhost:8080/cron-workflows, http://localhost:8080/event-sources, and http://localhost:8080/sensors

  1. Click on an object and verify "Submit" button isn't grayed out, but "Update" is
  2. Make an edit and verify "Submit" button is grayed out and "Update" button is no longer grayed out
  3. Click "Update" and verify "Submit" button is no longer grayed out, but "Update" is
  4. Verify I can create a new object and submit it
    Recording of the http://localhost:8080/workflow-templates page:
test-workflowtemplate.mp4

I also verified I can edit objects at http://localhost:8080/event-flow and http://localhost:8080/workflow-event-bindings

…proj#1382

The `<ObjectEditor>` component used by all the edit pages encapsulates
the logic for serializing/deserializing the object being edited, but
it's extremely inefficient. For example, if you're editing a
`WorkflowTemplate`, every single keystroke will cause `parse()` to be
called twice and `stringify()` to be called 4 times. For large
documents, this serializatino/deserialization overhead adds up quickly.

Additionally, the "Submit" button is sometimes incorrectly grayed out,
e.g. after clicking the "Update" button. This is happening because
`useEditableObject()` is using reference comparisons on the object being
edited, since it doesn't have access to the serialized string version
encapsulated by `<ObjectEditor>`.

This decouples `<ObjectEditor>` from serialization/deseralization and
lifts the state involved up to the `useEditableObject()` hook, as
discussed in
argoproj#13593 (comment).
Doing so eliminates unnecessary serialization/deseralization: now, if
you're editing a `WorkflowTemplate`, each keystroke will only call
`parse()` once and won't call `stringify()` at all. This also fixes
issues with the Submit button not reflecting the current page state,
since `useEditableObject()` now uses string comparisons instead of ref
comparisons.

Signed-off-by: Mason Malone <[email protected]>
@MasonM MasonM changed the title fix(ui): improve editor performance and fix Submit button. Fixes #1382 fix(ui): improve editor performance and fix Submit button. Fixes #13892 Nov 18, 2024
@MasonM MasonM marked this pull request as ready for review November 18, 2024 01:16
@MasonM MasonM added the area/ui label Nov 18, 2024
Copy link
Member

@Joibel Joibel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, also tested locally.

@Joibel Joibel merged commit 1392ef5 into argoproj:main Nov 22, 2024
16 checks passed
Joibel pushed a commit that referenced this pull request Nov 22, 2024
@Joibel
Copy link
Member

Joibel commented Nov 22, 2024

@MasonM, I have done some more testing and this doesn't work properly. For me if you go to any of the editing pages, and scroll to the bottom, and press m you will get a full screen error.

Uncaught runtime errors:
ERROR
Implicit map keys need to be followed by map values at line 42, column 1:

  arguments: {}
m
^

YAMLError@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/errors.js?:10:5
YAMLParseError@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/errors.js?:19:5
Composer/this.onError@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/composer.js?:99:26
resolveBlockMap@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/resolve-block-map.js?:92:16
resolveCollection@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/compose-collection.js?:20:115
composeCollection@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/compose-collection.js?:44:12
composeNode@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/compose-node.js?:38:87
composeDoc@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/compose-doc.js?:35:87
next@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/composer.js?:174:80
method/it[k]@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/composer.js?:23:42
compose@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/composer.js?:158:14
parseDocument@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/public-api.js?:44:3
parse@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/public-api.js?:65:28
parse@webpack://argo-workflows-ui/./src/shared/components/object-parser.ts?:13:55
reducer@webpack://argo-workflows-ui/./src/shared/use-editable-object.ts?:41:98
updateReducer@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:11344:26
useReducer@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:12287:20
useReducer@webpack://argo-workflows-ui/./node_modules/react/cjs/react.development.js?:1073:25
useEditableObject@webpack://argo-workflows-ui/./src/shared/use-editable-object.ts?:74:78
WorkflowTemplateDetails@webpack://argo-workflows-ui/./src/workflow-templates/workflow-template-details.tsx?:74:201
renderWithHooks@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:11098:31
updateFunctionComponent@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:14130:24
beginWork@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:15472:18
callCallback2@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:3211:18
invokeGuardedCallbackDev@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:3236:20
invokeGuardedCallback@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:3270:35
beginWork$1@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:19313:32
performUnitOfWork@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18749:16
workLoopSync@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18685:26
renderRootSync@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18664:11
performSyncWorkOnRoot@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18422:38
flushSyncCallbacks@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:8669:26
ensureRootIsScheduled/<@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18175:17
ERROR
Implicit map keys need to be followed by map values at line 42, column 1:

  arguments: {}
m
^

YAMLError@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/errors.js?:10:5
YAMLParseError@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/errors.js?:19:5
Composer/this.onError@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/composer.js?:99:26
resolveBlockMap@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/resolve-block-map.js?:92:16
resolveCollection@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/compose-collection.js?:20:115
composeCollection@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/compose-collection.js?:44:12
composeNode@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/compose-node.js?:38:87
composeDoc@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/compose-doc.js?:35:87
next@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/composer.js?:174:80
method/it[k]@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/composer.js?:23:42
compose@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/compose/composer.js?:158:14
parseDocument@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/public-api.js?:44:3
parse@webpack://argo-workflows-ui/./node_modules/yaml/browser/dist/public-api.js?:65:28
parse@webpack://argo-workflows-ui/./src/shared/components/object-parser.ts?:13:55
reducer@webpack://argo-workflows-ui/./src/shared/use-editable-object.ts?:41:98
updateReducer@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:11344:26
useReducer@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:12287:20
useReducer@webpack://argo-workflows-ui/./node_modules/react/cjs/react.development.js?:1073:25
useEditableObject@webpack://argo-workflows-ui/./src/shared/use-editable-object.ts?:74:78
WorkflowTemplateDetails@webpack://argo-workflows-ui/./src/workflow-templates/workflow-template-details.tsx?:74:201
renderWithHooks@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:11098:31
updateFunctionComponent@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:14130:24
beginWork@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:15472:18
callCallback2@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:3211:18
invokeGuardedCallbackDev@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:3236:20
invokeGuardedCallback@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:3270:35
beginWork$1@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:19313:32
performUnitOfWork@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18749:16
workLoopSync@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18685:26
renderRootSync@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18664:11
recoverFromConcurrentError@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18284:38
performSyncWorkOnRoot@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18427:24
flushSyncCallbacks@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:8669:26
ensureRootIsScheduled/<@webpack://argo-workflows-ui/./node_modules/react-dom/cjs/react-dom.development.js?:18175:17
ERROR
Model is disposed!
_assertNotDisposed@webpack://argo-workflows-ui/./node_modules/monaco-editor/esm/vs/editor/common/model/textModel.js?:272:19
getVersionId@webpack://argo-workflows-ui/./node_modules/monaco-editor/esm/vs/editor/common/model/textModel.js?:477:14
fetch/promise<@webpack://argo-workflows-ui/./node_modules/monaco-editor/esm/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsSource.js?:75:72

I haven't reverted this at this point.

MasonM added a commit to MasonM/argo-workflows that referenced this pull request Nov 23, 2024
argoproj#13915 introduced a
regression where edits made in an object editor that introduce syntax
errors cause a full screen error. The editor uses the following
`try-catch` block to handle parse errors, but the `catch` block no
longer works because the parsing logic was moved to `reducer()`, which
is executed async:
https://github.com/argoproj/argo-workflows/blob/main/ui/src/shared/components/object-editor.tsx#L117-L122

This moves the parsing logic to the `setObject()` function, which means
errors are now propagated to the caller.

Tested by going http://localhost:8080/workflow-templates, creating a new
`WorkflowTemplate`, and making edits.

Signed-off-by: Mason Malone <[email protected]>
@MasonM
Copy link
Contributor Author

MasonM commented Nov 23, 2024

@Joibel Sorry about that. I entered a fix: #13931

This also highlights the need for testing the React components, which is currently not possible. I entered #13932 for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

UI (when 2 tabs open) 3.6.0rc4 - submit workflowtemplate greyed out
3 participants