Skip to content

Conversation

@AustinMroz
Copy link
Collaborator

@AustinMroz AustinMroz commented Aug 21, 2025

Adds a system for saving blueprints of subgraphs for reuse later. When a subgraph is selected, a new publish icon is added to the selection toolbar. Subgraph blueprints can by added by the node library or the node searchbox. When accessed from the library, options are provided for editing or deleting a subgraph.

These blueprints are saved to the user data folder and will persist across different browsers.

┆Issue is synchronized with this Notion page by Unito

@github-actions
Copy link

github-actions bot commented Aug 21, 2025

🎭 Playwright Test Results

All tests passed across all browsers!

⏰ Completed at: 09/06/2025, 05:39:40 PM UTC

📊 Test Reports by Browser


🎉 Your tests are passing across all browsers!

@AustinMroz AustinMroz changed the title Austin/subgraph publishing Implement subgraph publishing Aug 21, 2025
@github-actions
Copy link

github-actions bot commented Aug 21, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 08/22/2025, 05:55:59 PM UTC

📊 Build Summary

  • Components: 13
  • Stories: 52
  • Visual changes: 0
  • Errors: 0

🔗 Links


🎉 Your Storybook is ready for review!

@AustinMroz AustinMroz force-pushed the austin/subgraph-publishing branch from b82a08f to 6187e7a Compare August 21, 2025 19:57
AustinMroz and others added 9 commits August 21, 2025 15:03
When a subgraph is first published, it previously was not added to the
subgraphCache. This would cause deletion to fail until a reload occurred.
A couple of tests that were mocking classes broke SubgraphBlueprint
inheritance. Since they aren't testing anythign related to subgraph
blueprints, the subgraph store is mocked as well.
@AustinMroz AustinMroz marked this pull request as ready for review August 22, 2025 18:18
@DrJKL DrJKL self-assigned this Aug 22, 2025
Copy link
Contributor

@DrJKL DrJKL left a comment

Choose a reason for hiding this comment

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

Looks good, mostly just code style comments 👍🏻

_pasteFromClipboard(
options: IPasteFromClipboardOptions = {}
): ClipboardPasteResult | undefined {
const data = localStorage.getItem('litegrapheditor_clipboard')
Copy link
Contributor

Choose a reason for hiding this comment

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

https://vueuse.org/core/useLocalStorage/
You might be able to use the composable instead. Should help prevent typo based key misalignment.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it'd also help with the serialize/deserialize

Comment on lines 799 to 801
await useWorkspaceStore().workflow.syncWorkflows()
await useSubgraphStore().fetchSubgraphs()
await useExtensionService().loadExtensions()
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these conflict with one another? If not, could we batch them with Promise.allSettled?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think extensions can access the workflowStore or the subgraphStore, but it's not something I'd want to risk.
On the other hand, I hadn't realized Promise.All was sequential. Will have to fix the incorrect usage of it inside fetchSubgraphs()

)
const subgraphs = this.activeState.definitions.subgraphs
const nodes = this.activeState.nodes
//Instanceof doesn't funciton as nodes are serialized
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we use Zod to validate?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think Zod has a way of checking the indirection required here. There's a couple other places with saving and loading blueprints where checks couldd be rolled into Zod, but it kinda comlicates things with zod workflow validation being an optional setting. I wouldn't want the important checks to be skipped if a user has the workflow validation disabled.

throw new Error('not yet loaded')
return subgraphCache[name].changeTracker.initialState
}
function deleteBlueprint(nodeType: string) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would you mind spacing out the functions in here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Just adding an empty newline, yeah? Same for all the functions?

@DrJKL DrJKL assigned AustinMroz and unassigned DrJKL Aug 22, 2025
@christian-byrne
Copy link
Contributor

We can merge this in 1.27 after the manager is merged, if that works.

@AustinMroz
Copy link
Collaborator Author

Sounds like an appropriate goal. I got some additional feedback on menu design from Pablo earlier today which I'm working on, but everything else should be solid.

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Aug 27, 2025
1 is used as a placeholder size as -1 indicates the baking userFile is
temporary, not persisted, and therefore, not able to overwrite when
saved.
Making subgraph blueprints non temporary on publish made it so the
following load actually occurs. A mock has been added for this load.
Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

This is looking great.

To help me, is this the correct flow?

  1. User clicks "Publish Subgraph" button → publishSubgraph() called
  2. Get selected subgraph node → Validates exactly 1 SubgraphNode selected
  3. Serialize the node → canvas._serializeItems([subgraphNode])
  4. Extract data structures → Gets nodes[] and subgraphs[] arrays
  5. Create workflow JSON → Builds a complete workflow structure
  6. Save as file → Stores in subgraphs/filename.json
  7. Register as node type → Makes it available in node library
  8. Cache for editing → Stores loaded workflow for future edits

That is my understanding, want to make sure it's correct.

Also, I like the refactoring of the clipboard logic into distinct methods responsible for clipboard functionality and serialization individually. It makes me want to look into some further refactor to some sort of serialization service like

export function useCanvasSerializationService() {
    function serializeItems(items: Iterable<Positionable>): ClipboardItems {
      // All serialization logic here
    }

    function serializeForClipboard(items: Iterable<Positionable>): void {
      const data = serializeItems(items)
      localStorage.setItem('litegrapheditor_clipboard', JSON.stringify(data))
    }

    function serializeForBlueprint(subgraphNode: SubgraphNode): WorkflowData {
      const data = serializeItems([subgraphNode])
      return formatAsWorkflow(data)
    }

    return { serializeItems, serializeForClipboard, serializeForBlueprint }
}

Just thinking out loud. Also, feel free to ignore the nits.

This also moves the bg tinting to a property of the workflow,
which makes things more extensible in the future.
The prior fix to allow overwrite of an existing blueprint on publish was
misguided. By marking a not-yet-loaded file as non-temporary, the load
performed prior to saving was actually fetching the file off disk and
discarding the existing changes. This additionally entirely prevented
publishing when a blueprint did not already exist with the current name.

To fix this, the blueprint is not marked as non-temporary until after
the load occurs. Note that this load is still required as it initializes
the change tracker state required for saving.
Will need to be revisited if lazy loading is implemented, but this
requires solving some ugly sync/async issues.
@christian-byrne christian-byrne added area:subgraph subgraph-v2 Things slated for 2nd release of subgraph which will introduce linked instance, sharing/saving, etc. labels Sep 7, 2025
Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

LGTM!

@christian-byrne christian-byrne merged commit fc8d562 into main Sep 7, 2025
27 checks passed
@christian-byrne christian-byrne deleted the austin/subgraph-publishing branch September 7, 2025 04:27
@benceruleanlu benceruleanlu mentioned this pull request Sep 7, 2025
snomiao pushed a commit that referenced this pull request Sep 12, 2025
* Implement subgraph publishing

* Add missing null check

* Fix subgraph blueprint display in workflows tab

* Fix demotion of subgraph blueprints on reload

* Update locales [skip ci]

* Update blueprint def on save, cleanup

* Fix skipped tracking on subgraph publish

When a subgraph is first published, it previously was not added to the
subgraphCache. This would cause deletion to fail until a reload occurred.

* Fix failing vite tests

A couple of tests that were mocking classes broke SubgraphBlueprint
inheritance. Since they aren't testing anythign related to subgraph
blueprints, the subgraph store is mocked as well.

* Make blueprint breadcrumb badge clickable

* Add confirmation for overwrite on publish

* Simplify blueprint badge naming

* Swap to promise.allSettled when fetching subgraphs

* Navigate into subgraph on blueprint edit

* Revert mission of value in blueprint breadcrumb

This was causing the blueprint badge to always display

* Misc code quality fixes

* Set subgraphNode title on blueprint add.

When a subgraph blueprint is added to the graph, the title of the
subgraphNode is now set to be the title of the blueprint.

NOTE: The name of the subgraph node when a blueprint is edited is left
unchanged. This may cause minor user confusion.

* Add "Delete Blueprint" option to breadcrumb

When editing a blueprint, the options provided for the root graph of the
breadcrumb included a Delete Workflow option. This still functioned for
deleting the current blueprint when selected, but didn't make sense. It
has been updated to instead describe that it deletes the current
blueprint

* Extract subgraph load code as function

* Fix subgraphs appearing in library after refresh

Subgraph nodes were hidden from the node library and context menu by
setting skip_list to true. Unfortunately, this causes them to be
mistakenly be caught and registered as vue nodes when a refresh is
performed. This is fixed by adding a check for skip_list.

* Add delete button and confirmation for deletion

* Use more specific warning for blueprint deletion

* At success toast on subgraph publish

Will return later to potentially add a node library link to the toast

* Don't apply subgraph context menu to normal nodes

Subgraph blueprints have a right click -> delete option in the node
library.  This was incorrectly being dislplayed on non blueprint nodes.

* Remove hardcoded subgraphs path

Rather happy with this change. Rather than trying to introduce a
recursive import to pass a magic string, this solution is both
sufficient AND allows potential future extensions with less breakage.

* Fix nodeDef update on save

Wait to update the node def cache until after a blueprint has been
saved. Before, changes to links weren't actually being made visisble.

* Fix SaveAs with subgraph blueprints

* Remove ugly serialize/deserialize

Thought I had already tested this, and found that the mere existence of
proxies was causing issues, but simply adding a correct annotation is
sufficient now.

* Improve error specificity

* Framework for user defined blueprint descriptions

BlueprintDescription can be added to a workflows extra field to provide
more useful information about a blueprint's purpose

Actually hooking this up in a way that is user accessible is out of
scope for right now, but this will simplify future implementation.

* Cleanup breadcrumb dropdown options

Removes Dupliate for blueprints, adds a publish subgraph option.

The publish subgraph button currently routes through the save as logic.
Unforunately, this results in the prompt for name referencing workflows.
The cleanest way to resolve this is still being considered

* Move blueprint renaming into blueprint load

Blueprints should automatically set the name of the added node to the
filename when added. This mostly worked, but created uglier edgecases:
The subgraph itself wasn't renamed, and it would need to be
reimplemented to apply when editing a blueprint.

Instead, this is now applied when a subgraphBlueprint is first loaded.
This keeps all the logic routed through a single point

* Move saveAs prompt into workflow class

Ensures that the correct publish text is displayed when editing
blueprints without making an awful mess of imports

* Fix tests by making subgraphBlueprint internal

This has the added benefit of forcing better organization.

Reverts the useWorkflowThumbnail patch as it is no longer required.

* Add tests for subgraph blueprints

* Rewrite confirmation dialog

* Fix overwrite on publish new subgraph

1 is used as a placeholder size as -1 indicates the baking userFile is
temporary, not persisted, and therefore, not able to overwrite when
saved.

* When editing blueprint, tint background blue

* Fix blueprint tint at low LOD

* Set node source for blueprints to Blueprint

* Fix publish test

Making subgraph blueprints non temporary on publish made it so the
following load actually occurs. A mock has been added for this load.

* Fix multiple nits

* Further cleanup: error handling, and comments

* Fixing failing test cases

This also moves the bg tinting to a property of the workflow,
which makes things more extensible in the future.

* Fix temporary marking on publish.

The prior fix to allow overwrite of an existing blueprint on publish was
misguided. By marking a not-yet-loaded file as non-temporary, the load
performed prior to saving was actually fetching the file off disk and
discarding the existing changes. This additionally entirely prevented
publishing when a blueprint did not already exist with the current name.

To fix this, the blueprint is not marked as non-temporary until after
the load occurs. Note that this load is still required as it initializes
the change tracker state required for saving.

* Block unloading subgraph blueprints

Will need to be revisited if lazy loading is implemented, but this
requires solving some ugly sync/async issues.

---------

Co-authored-by: github-actions <github-actions@github.com>
@AustinMroz AustinMroz mentioned this pull request Sep 18, 2025
christian-byrne pushed a commit that referenced this pull request Sep 18, 2025
Implementing subgraph blueprints (#5139) included changes to saving to
ensure that SaveAs generates a new workflow of the correct type. However
this code failed to utilize the pre-prepared state when performing the
actual save. This produced a couple of problems with both failing to
detach the workflow and failing to apply the correct state

This error is only encountered when using Save As from a non temporary
workflow (one loaded from the workflows sidebar tab).

As this state calculation code is only used in this code path, it has
been moved into the saveAs function of the workflowStore.

Resolves #5592

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5643-Fix-SaveAs-2726d73d3650818faa7af449d1f13c26)
by [Unito](https://www.unito.io)
github-actions bot pushed a commit that referenced this pull request Sep 18, 2025
Implementing subgraph blueprints (#5139) included changes to saving to
ensure that SaveAs generates a new workflow of the correct type. However
this code failed to utilize the pre-prepared state when performing the
actual save. This produced a couple of problems with both failing to
detach the workflow and failing to apply the correct state

This error is only encountered when using Save As from a non temporary
workflow (one loaded from the workflows sidebar tab).

As this state calculation code is only used in this code path, it has
been moved into the saveAs function of the workflowStore.

Resolves #5592

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5643-Fix-SaveAs-2726d73d3650818faa7af449d1f13c26)
by [Unito](https://www.unito.io)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:subgraph size:L This PR changes 100-499 lines, ignoring generated files. subgraph-v2 Things slated for 2nd release of subgraph which will introduce linked instance, sharing/saving, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants