Skip to content

Make FlowfileEditor embeddable as a Vue component library#338

Merged
Edwardvaneechoud merged 11 commits intomainfrom
claude/embeddable-flowfile-wasm-qFQI1
Feb 17, 2026
Merged

Make FlowfileEditor embeddable as a Vue component library#338
Edwardvaneechoud merged 11 commits intomainfrom
claude/embeddable-flowfile-wasm-qFQI1

Conversation

@Edwardvaneechoud
Copy link
Copy Markdown
Owner

Summary

This PR transforms the FlowfileEditor from a standalone application into an embeddable Vue component library that can be integrated into other Vue 3 applications. The editor can now be published to npm and used as a reusable component with a clean public API.

Key Changes

New Public API & Component Export

  • Added FlowfileEditor.vue as the main embeddable component with comprehensive props for configuration
  • Created lib/index.ts as the library entry point exporting the component, plugin, and all public types
  • Implemented FlowfileEditorPlugin for easy registration via app.use()
  • Defined complete TypeScript interfaces for all public APIs (FlowfileEditorProps, FlowfileEditorAPI, etc.)

Library Build Configuration

  • Updated vite.config.ts to support dual build modes: app (dev/preview) and library (npm package)
  • Configured library build to output ES module format with proper entry points
  • Updated package.json with library metadata (main, module, types, exports, files)
  • Renamed package from flowfile-wasm to flowfile-editor for clarity

Styling & Theme System

  • Added comprehensive editor.css (1367 lines) with design token system aligned with flowfile_frontend
  • Implemented CSS custom properties for colors, typography, spacing, shadows, and animations
  • Added dark theme support via data-theme="dark" attribute
  • Scoped all styles under .flowfile-editor-root for isolation in embedded contexts
  • Customized AG Grid and Vue Flow component themes to match design system

Embedded Mode Features

  • Enhanced theme-store.ts with embedded flag to prevent global document theme changes
  • Added setEmbedded() method to isolate theme application to component scope only
  • Implemented input data injection via injectInputData() for programmatic data loading
  • Added output callbacks in flow-store.ts for capturing execution results
  • Exposed programmatic API via defineExpose() for template ref access

Toolbar & UI Customization

  • Made toolbar buttons conditionally visible via effectiveToolbar config
  • Replaced Material Icons with inline SVGs for better library portability
  • Updated Canvas.vue to respect toolbar configuration (showRun, showSaveLoad, showClear, showCodeGen, showDemo)
  • Updated PreviewSettings.vue and DemoButton.vue to use inline SVGs

Icon Management

  • Created utils/iconUrls.ts to explicitly import all node icons as base64 data URIs
  • Ensures icons work correctly in library builds without import.meta.url issues

Props & Configuration

  • FlowfileEditorProps supports: initialFlow, inputData, pyodide config, theme, toolbar, nodeCategories, readonly, height, width
  • PyodideConfig allows custom CDN URLs and auto-initialization control
  • ToolbarConfig provides granular control over visible toolbar buttons
  • InputDataMap enables programmatic data injection matched by node_reference

Notable Implementation Details

  • Component emits events for ready, flow-change, execution-complete, output, error, and loading-status
  • Exposed API includes: isReady, isExecuting, executeFlow, executeNode, exportFlow, importFlow, setInputData, getNodeResult, clearFlow, initializePyodide
  • Theme system respects system preference while allowing explicit override
  • Loading overlay shown during Pyodide initialization (can be disabled)
  • All styles use CSS custom properties for easy theming and dark mode support

Add library build mode so flowfile_wasm can be used as a drop-in
`<FlowfileEditor>` component in any Vue 3 app, similar to VueFlow.

New files:
- src/lib/types.ts: Public API types (props, events, exposed methods)
- src/lib/FlowfileEditor.vue: Main wrapper component with prop/event bridge
- src/lib/plugin.ts: Vue plugin installer (auto-installs Pinia if needed)
- src/lib/index.ts: Library entry point exporting component and types
- src/styles/editor.css: Scoped CSS (vars under .flowfile-editor-root)
- src/utils/iconUrls.ts: Explicit icon imports for library build

Modified files:
- Canvas.vue: Accept toolbar/node config props, emit execution events,
  replace Material Icons with inline SVGs, use iconUrls utility
- DemoButton.vue, PreviewSettings.vue: Replace Material Icons with SVGs
- flow-store.ts: Add output callback mechanism for embeddable mode
- theme-store.ts: Support scoped theming (embedded mode skips global DOM)
- vite.config.ts: Dual build (app + library via BUILD_MODE=lib env var)
- package.json: Add exports, peerDependencies, build:lib script

All 192 existing tests pass. Both app and library builds succeed.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
@netlify
Copy link
Copy Markdown

netlify bot commented Feb 13, 2026

Deploy Preview for flowfile-wasm ready!

Name Link
🔨 Latest commit b67862d
🔍 Latest deploy log https://app.netlify.com/projects/flowfile-wasm/deploys/6994d7a84e84d300088538f7
😎 Deploy Preview https://deploy-preview-338--flowfile-wasm.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Instead of requiring indirect node_reference matching, this adds a proper
"External Data" node type that users drag onto the canvas and select a
dataset from a dropdown. The host application provides datasets via the
inputData prop, and they appear as selectable options in the node settings.

On export, only the dataset name and schema snapshot are saved (not the
actual data), so flows remain lightweight and the host re-provides data
on re-import.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
The right-click context menu was teleported to <body>, which placed it
outside the .flowfile-editor-root container. In embedded mode, CSS
variables are scoped to .flowfile-editor-root (not :root), so the
teleported menu lost access to --bg-secondary and --border-color,
rendering it transparent. Removing the Teleport keeps the menu in the
DOM tree where CSS variables are inherited. The position:fixed style
still positions it relative to the viewport.

Also added external_data icon mapping to FlowNode's iconMap.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
VueFlow renders nodes inside a transformed container, which breaks
position:fixed — making the context menu appear at the wrong coordinates.
Instead of teleporting to <body> (loses CSS vars) or rendering inline
(breaks positioning), teleport to a dedicated container div inside
Canvas.vue. This sits inside the CSS variable scope but outside VueFlow's
transform layer, fixing both the styling and positioning.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
- external_data code gen: generates pl.scan_csv("dataset.csv") placeholder
  with a comment telling the user to replace the path
- external_output node: full stack implementation (types, settings UI,
  execute handler, code gen). On execution, collects the input DataFrame
  and sends it to the host via output callbacks. Code gen produces
  df.collect() to materialize the result.
- New SVG icons for both external_data (blue database + inbound arrow)
  and external_output (green document + outbound arrow), replacing the
  old external_source.png

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
Interactive example page at /embed-example that shows:
- Two editable input datasets (orders + customers) as CSV text areas
- Dataset names are editable and map to External Data node dropdown
- An "Add Dataset" button for adding more inputs on the fly
- Output results panel that shows data from External Output nodes
- The full FlowfileEditor embedded in the right panel

This serves as both a test page and reference implementation for
consumers building their own integration.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
DraggablePanel used position: fixed, so panels were positioned relative
to the viewport. When the editor is embedded in part of a page, panels
would overflow into the host page's other areas.

Changed to position: absolute so panels are positioned relative to
.canvas-container (which has position: relative + overflow: hidden).
All window.innerWidth/Height references now use getContainerRect()
to measure the actual container. Added ResizeObserver to track
container size changes in addition to window resize events.

Panel dragging is also now clamped to container boundaries.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
Triggers on `wasm-v*` tags (e.g. `wasm-v0.1.0`). Runs tests and
type-checking before building the library and publishing to npm
with provenance. Verifies the tag version matches package.json.

Requires an `npm` environment with an NPM_TOKEN secret configured
in the repository settings.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
1. Security: Fix Python injection in external_output — outputName was
   interpolated directly into a Python string. Now uses toPythonJson()
   consistently with all other node handlers.

2. CSS scoping: Scope .vue-flow__* and .ag-theme-balham selectors under
   .flowfile-editor-root so they don't leak into host applications that
   use Vue Flow or AG Grid independently.

3. DraggablePanel: Fix getContainerRect race condition — if container has
   zero dimensions during mount (not laid out yet), defer positioning to
   nextTick.

4. Type gap: Remove unused options parameter from setInputData type
   signature since the implementation doesn't wire it up.

5. Output callbacks: Add clearOutputCallbacks() to flow store and call
   it in FlowfileEditor's onUnmounted to prevent callback leaks.

6. Cleanup: Remove refreshInputData no-op in EmbedExample (v-model
   already triggers reactivity), add coupling comment on external_data's
   reuse of execute_manual_input.

Verified: vue-router is tree-shaken out of the library bundle (0 refs).

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
README: Replace standalone-app README with consumer-facing docs covering
installation, props, events, programmatic API, input data, output
capture, CORS headers, and TypeScript types.

Icons: Replace all 14 PNG node icons (200KB total) with hand-crafted
SVGs (~15KB total). Removes the assetsInlineLimit: 100000 workaround
from vite.config since SVGs are naturally small. Library JS bundle
drops from 1,225KB to 1,048KB gzipped (-14%).

Code-splitting: Lazy-load PolarsCodeSettings and CodeGenerator via
defineAsyncComponent so vue-codemirror and @codemirror/* are only
fetched when the user opens those panels.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
Reverts the SVG icon replacements and restores the original PNG imports
in iconUrls.ts and the assetsInlineLimit config in vite.config.ts.

https://claude.ai/code/session_01SztvepLRjChvuh634qxFnu
@Edwardvaneechoud Edwardvaneechoud merged commit 820bd96 into main Feb 17, 2026
17 checks passed
@Edwardvaneechoud Edwardvaneechoud deleted the claude/embeddable-flowfile-wasm-qFQI1 branch February 17, 2026 21:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants