tacel-lucid-workflow-viewer
v0.1.1
Published
Reusable browser workflow viewer for published Lucid workflow graphs
Readme
Lucid Workflow Viewer Module
Reusable browser graph viewer for published Lucid workflow graphs.
This module is intentionally host-agnostic. It contains no database credentials, backend internals, server IPs, auth secrets, or private storage paths. Host apps provide every runtime value and decide how those values are sourced.
Files
lucid-workflow-viewer.js- UMD/browser module, exposeswindow.LucidWorkflowViewer.lucid-workflow-http-data-source.js- optional HTTP adapter for the standard Lucid workflow API.lucid-workflow-viewer.css- optional static stylesheet.index.js- CommonJS entry point for Electron/Node bundlers.scripts/sync-to-host.js- copies browser assets into a host app's packaged renderer/static folder.
Runtime Contract
The host app owns all runtime configuration:
apiBaseUrl- base URL for the Lucid workflow API when using the HTTP adapter.documentId- Lucid document id whose published graph should be loaded.workflowId- optional selected workflow id; if omitted, the viewer picks the first workflow.currentUseroruserKey- viewer identity used for video progress.theme-darkorlight; hosts can also passclassNamefor app-specific styling.showEdgeText,showLineJunctions,showAllWorkflowsOption,enableMultiWorkflowSelection,enableWorkflowRenaming,workflowDisplayNames,showControls,showWorkflowPicker,reactFlowAssetBase, and other display options.enableWorkflowFilteringdefaults totrue. Set it tofalseto render the whole graph at once, hide the workflow picker, and use one universalgraphColorfor nodes and edges.graphColoris optional. Whole-graph mode falls back to white when it is empty or invalid.applyPublishedLockedNodeIdslets a host applylockedNodeIdsreturned alongside a published graph response.accessibleNodeIdslets a host pass a certificate allowlist. The module keeps the whole graph visible and derives forced locks for every node outside that list. An empty array locks every node.enableWorkflowRenamingis display-only. It lets viewers override workflow labels in this module without changing the published Lucid graph.workflowDisplayNamescan pre-seed display labels as{ workflowId: "Display name" }.onWorkflowDisplayNamesChange(event)can be used by the host to persist viewer-only label overrides.cacheVideoUrlsdefaults totrueand caches resolved video URLs per viewer instance.transformVideoUrl(rawUrl, context)lets hosts convert a raw file URL or path before playback. Tauri hosts commonly use this to callconvertFileSrc.nodeSelectionModeturns the graph into an authoring node picker: each node renders a membership checkbox instead of the end-user blocked/locked gating.selectedNodeIdsis the checked (included) set andonNodeToggle(nodeId, checked)fires on each toggle. Hosts can also push a new checked set without re-initializing via the instance methodsetSelectedNodeIds(ids)(the viewer reconciles in place, preserving pan/zoom). Off by default — every other host renders unchanged. Used by the WireHub certificate editor so admins pick nodes on the graph itself.openAttachment(args)anddownloadAttachment(args)let hosts own the node-attachment View and Download actions. When provided, the viewer calls them instead of falling back to a browser anchor (which cannot save or open files inside native webviews such as Tauri/Electron).argsincludes{ action, file, node, url, fileId, nodeId, workflowId, documentId }. The module still resolves the file first (so "still optimizing" / "failed" statuses are surfaced) and only delegates on success. Web hosts that omit these callbacks keep the default anchor behavior.unassignedProgressWorkflowIdlets a host persist progress for unassigned nodes under a synthetic workflow id. If omitted, unassigned progress remains local-only.resumeProgressWorkflowIddefaults to__video_resume__. Resume playback uses this single synthetic workflow id so each node/user video position overwrites one row instead of duplicating across workflow progress rows.- Resume rows use
last_position_secondsfor the reopen point andmax_position_secondsfor the no-skip watched watermark. Legacyposition_secondsis still accepted as a fallback. - Playback behavior is host-configurable:
enableResumeturns resume playback on or off.resumeMinPositionSecondsdefaults to5; positions at or below this start from the beginning.resumeEndBufferSecondsdefaults to15; positions within this many seconds of the end start from the beginning. Set0to allow resume until the exact end.resumeCompletedVideosdefaults tofalse; completed nodes normally restart from the beginning.savePositionOnClosedefaults totrue.savePositionOnPausedefaults tofalse.positionSaveIntervalMsdefaults to0, which disables interval saves.preventSkipturns no-skip enforcement on or off.preventSkipToleranceSecondsdefaults to0.5.videoSeekStepSecondsdefaults to5.videoPreloaddefaults tometadata; valid values arenone,metadata, andauto.
syncUsers(context)is an optional host callback for copying users from the host's configured source intoLUCID.user_access.userSyncIntervalMsdefaults to five minutes.syncUsersOnStartdefaults totrue.userSyncKeylets multiple viewer instances share one scheduler. Use a stable host-specific key when syncing from mounted viewers.
Hosts may either provide callbacks directly or create callbacks from the HTTP adapter. The viewer itself does not know where configuration comes from.
Optional User Sync
The module owns scheduling, overlap protection, and teardown. The host owns
database credentials, source-table configuration, and the actual write into
LUCID.user_access. Never pass database credentials into browser code.
Start user sync once during host-app startup:
const userSync = LucidWorkflowViewer.startUserSync({
userSyncKey: 'my-host-users',
userSyncIntervalMs: 5 * 60 * 1000,
syncUsersOnStart: true,
syncUsers: () => hostApi.syncUsersIntoLucid()
});
// On host shutdown:
userSync.stop();Run one sync manually:
await LucidWorkflowViewer.syncUsers({
syncUsers: () => hostApi.syncUsersIntoLucid()
});Simpler hosts may pass the same options into initialize(). The viewer
instance starts the scheduler while mounted and stops it during destroy().
HTTP Adapter
The HTTP adapter has no built-in service address. Hosts must pass one of
apiBaseUrl, baseUrl, serviceUrl, serviceBaseUrl, or syncBaseUrl.
apiBaseUrl is preferred for new hosts.
const dataSource = LucidWorkflowHttpDataSource.create({
apiBaseUrl: hostConfig.lucidWorkflowApiBaseUrl
});The adapter provides:
loadPublishedGraph(args)loadProgress(args)markNodeComplete(args)getVideoUrl(args)
Basic Browser Usage
<div id="workflow-viewer"></div>
<script src="./lucid-workflow-http-data-source.js"></script>
<script src="./lucid-workflow-viewer.js"></script>
<script>
const dataSource = LucidWorkflowHttpDataSource.create({
apiBaseUrl: window.hostLucidConfig.apiBaseUrl
});
const viewer = LucidWorkflowViewer.initialize('#workflow-viewer', {
...dataSource,
documentId: window.hostLucidConfig.documentId,
workflowId: window.hostLucidConfig.workflowId,
currentUser: window.hostCurrentUser,
theme: window.hostLucidConfig.theme || 'dark',
reactFlowAssetBase: window.hostLucidConfig.reactFlowAssetBase,
showEdgeText: Boolean(window.hostLucidConfig.showEdgeText)
});
</script>Direct Callback Usage
LucidWorkflowViewer.initialize(container, {
documentId,
workflowId,
currentUser,
loadPublishedGraph: async ({ documentId, workflowId }) => {
return hostApi.loadWorkflowGraph({ documentId, workflowId });
},
loadProgress: async ({ documentId, workflowId, userKey }) => {
return hostApi.loadWorkflowProgress({ documentId, workflowId, userKey });
},
markNodeComplete: async ({ documentId, workflowId, nodeId, primaryFileId, userKey }) => {
return hostApi.markWorkflowNodeComplete({ documentId, workflowId, nodeId, primaryFileId, userKey });
},
getVideoUrl: ({ fileId }) => {
return hostApi.getWorkflowVideoUrl(fileId);
},
transformVideoUrl: (rawUrl, context) => {
return hostApi.toPlayableVideoUrl(rawUrl, context.file);
}
});Data Shapes
loadPublishedGraph(args) may return either the standard API response shape or
the raw graph:
{
graph: {
workflows: [{ id, name, color }],
nodes: [{ nodeId, title, description, workflowIds, primaryVideoFileId, box, shapeKind, files }],
edges: [{ workflowId, workflowIds, fromNodeId, toNodeId, text }]
}
}Line-to-line publishes can include endpoint metadata:
{
kind: 'edge-to-edge',
from: { kind: 'line', lineId, position, x, y },
to: { kind: 'line', lineId, position, x, y },
resolvedFromNodeIds: ['source-node-id'],
resolvedToNodeIds: ['target-node-id']
}The viewer uses resolvedFromNodeIds and resolvedToNodeIds for video
unlocking. Line endpoint refs are visual only.
A node's files array lists its attachments. Each entry is
{ id, name, mime, size, accessMode, createdAt }, where accessMode is
view, download, or both (defaults to both). The node detail panel
renders a View and/or Download button per attachment according to
accessMode. Hosts handle those clicks via openAttachment /
downloadAttachment (see Runtime Contract).
workflowIds is the cumulative membership of the nodes connected by an edge.
For compatibility with older hosts, workflowId remains populated when an
edge has exactly one workflow membership. Older publishes that only provide
workflowId are still supported.
Newer publishes can also include pathPoints on edges. These are sampled
Lucid line coordinates and are preferred for visual routing, especially for
node-to-edge and edge-to-edge connectors.
loadProgress(args) should return rows containing at least:
[{ node_id: 'lucid-node-id', completed_at: '2026-05-13T12:00:00.000Z' }]For resume playback, hosts may also return last_position_seconds and
max_position_seconds. The viewer writes both offsets through
onPositionChange when a video modal is closed, replaced, or destroyed. Older
hosts that only return position_seconds still work as a fallback.
Viewer Rules
- Start nodes are available immediately.
- A downstream node unlocks when any direct upstream node in the selected workflow has been completed by the current user.
- Workflow colors are used for graph nodes and single-workflow edges. An edge shown in more than one selected workflow renders as a bold black line.
- Hosts can set
enableWorkflowFiltering: falsefor certificate-style viewing. The viewer shows all nodes and edges, hides workflow switching, and paints the graph withgraphColoror white when no color is configured. - Certificate hosts can pass
accessibleNodeIdswhile using whole-graph mode. Nodes outside the allowlist remain visible but render greyed out, show a lock indicator, and ignore clicks. - Hosts can set
showAllWorkflowsOption: trueto add anAll workflows + unassignedpicker option that displays every published workflow plus unassigned nodes. - Hosts can set
enableMultiWorkflowSelection: trueto let viewers select multiple workflow ids at once from the same picker. - Hosts can set
enableWorkflowRenaming: trueto show anEdit labelcontrol for the selected workflow; the rename only changes viewer display text. - Hosts can set
showUnassignedWorkflowOption: trueto add anUnassignedpicker option for nodes and edges with no workflow membership. - Hosts can set
unassignedProgressWorkflowIdwhen they want unassigned node progress to persist through the normal progress callbacks. - Hosts can set
resumeProgressWorkflowIdto control the synthetic workflow id used for per-node resume playback rows. - Published
shapeKind: "diamond"nodes render as text-only diamonds. - Other nodes render as square/card nodes.
- Line-to-line connections render through junction anchors, but only real workflow nodes participate in video progress.
- Junction anchors are hidden by default. Hosts can set
showLineJunctions: trueto show them for debugging or teaching the graph shape. - Edge labels render only when the host sets
showEdgeText: trueand the published edge has text. - Lucid
boxcoordinates are used when present; otherwise the module falls back to a simple layout.
Host Asset Sync
Apps that package static browser assets can sync this module into their own source tree:
node ../Modules/lucid-workflow-viewer-module/scripts/sync-to-host.js path/to/host/static/lucid-workflow-viewer
node ../Modules/lucid-workflow-viewer-module/scripts/sync-to-host.js path/to/host/static/lucid-workflow-viewer --checkThe sync script copies only the module assets listed in this package. It does not copy host configuration or private runtime settings.
