mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-08 16:03:27 +00:00
* feat: preview and edit expanded subflow steps in the flow editor * fix: hide subflow edit button when no flow editor drawer is available * fix: address review findings on expanded subflow step panel * fix: base-prefix subflow links and bound the expanded subflow module cache * fix: do not let a pre-deploy response repopulate the invalidated subflow cache * fix: guard expanded subflow reloads against collapse and encode workspace in link * fix: commit an expanded subflow reload only onto the expansion it fetched for
63 lines
2.4 KiB
TypeScript
63 lines
2.4 KiB
TypeScript
import type { FlowModule } from '$lib/gen'
|
|
import { findStepPath, parseExpandedSubflowId } from '$lib/components/restartFromStepPath'
|
|
|
|
export type ResolvedExpandedSubflowStep = {
|
|
/** The flow the selected step lives in, i.e. the innermost subflow crossed. */
|
|
containingFlowPath: string
|
|
/** Path of each subflow crossed from the edited flow down to the containing one. */
|
|
pathChain: string[]
|
|
/** The selected step, or `undefined` when the id points at something that isn't a
|
|
* module of the containing flow (an AI agent tool node, a stale selection...). */
|
|
module: FlowModule | undefined
|
|
}
|
|
|
|
/**
|
|
* Graph node id of the expansion an inline-expanded subflow node sits in, i.e. the key
|
|
* whose modules hold the step it stands for: `subflow:a:b` → `a`, `subflow:a:b:c` →
|
|
* `subflow:a:b`. `undefined` for a top-level expansion, whose step belongs to the edited
|
|
* flow itself. Note that the last segment of `subflowSteps` is the parent's own step, so
|
|
* every segment stays in the parent key.
|
|
*/
|
|
export function expandedSubflowParentId(nodeId: string): string | undefined {
|
|
const steps = parseExpandedSubflowId(nodeId)?.subflowSteps
|
|
if (!steps) {
|
|
return undefined
|
|
}
|
|
return steps.length > 1 ? 'subflow:' + steps.join(':') : steps[0]
|
|
}
|
|
|
|
/**
|
|
* Resolves a `subflow:A:B:leaf` graph node id (an inline-expanded subflow step) to the
|
|
* step it stands for, following each `Flow{path}` boundary through the flows it points
|
|
* at. `loadFlowModules` fetches a flow's modules by path.
|
|
*
|
|
* Returns `undefined` when `id` is not an expanded-subflow node or a boundary can't be
|
|
* followed; a resolution whose `module` is undefined still carries the containing flow,
|
|
* which is enough to open it in the editor.
|
|
*/
|
|
export async function resolveExpandedSubflowStep(
|
|
id: string,
|
|
rootModules: FlowModule[],
|
|
loadFlowModules: (path: string) => Promise<FlowModule[]>
|
|
): Promise<ResolvedExpandedSubflowStep | undefined> {
|
|
const parsed = parseExpandedSubflowId(id)
|
|
if (!parsed) {
|
|
return undefined
|
|
}
|
|
let modules = rootModules
|
|
const pathChain: string[] = []
|
|
for (const stepId of parsed.subflowSteps) {
|
|
const value = findStepPath(modules, stepId)?.target.value
|
|
if (value?.type !== 'flow') {
|
|
return undefined
|
|
}
|
|
pathChain.push(value.path)
|
|
modules = await loadFlowModules(value.path)
|
|
}
|
|
return {
|
|
containingFlowPath: pathChain[pathChain.length - 1],
|
|
pathChain,
|
|
module: findStepPath(modules, parsed.leaf)?.target
|
|
}
|
|
}
|