@tduniec/plugin-template-designer-foundation 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +13 -0
- package/dist/api/useScaffolderActions.esm.js +59 -0
- package/dist/api/useScaffolderActions.esm.js.map +1 -0
- package/dist/components/FieldEditorDialog.esm.js +55 -0
- package/dist/components/FieldEditorDialog.esm.js.map +1 -0
- package/dist/components/Nodes/ActionNode.esm.js +613 -0
- package/dist/components/Nodes/ActionNode.esm.js.map +1 -0
- package/dist/components/Nodes/OutputNode.esm.js +373 -0
- package/dist/components/Nodes/OutputNode.esm.js.map +1 -0
- package/dist/components/Nodes/ParameterInputNode.esm.js +320 -0
- package/dist/components/Nodes/ParameterInputNode.esm.js.map +1 -0
- package/dist/components/Nodes/ParameterTitlesNode.esm.js +251 -0
- package/dist/components/Nodes/ParameterTitlesNode.esm.js.map +1 -0
- package/dist/components/Nodes/ParametersNode.esm.js +147 -0
- package/dist/components/Nodes/ParametersNode.esm.js.map +1 -0
- package/dist/components/Nodes/action/schema.esm.js +68 -0
- package/dist/components/Nodes/action/schema.esm.js.map +1 -0
- package/dist/components/Nodes/action/useActionInputs.esm.js +71 -0
- package/dist/components/Nodes/action/useActionInputs.esm.js.map +1 -0
- package/dist/components/Nodes/common/AutoWidthPopper.esm.js +11 -0
- package/dist/components/Nodes/common/AutoWidthPopper.esm.js.map +1 -0
- package/dist/components/Nodes/common/nodeInteraction.esm.js +20 -0
- package/dist/components/Nodes/common/nodeInteraction.esm.js.map +1 -0
- package/dist/components/Nodes/output/useOutputController.esm.js +125 -0
- package/dist/components/Nodes/output/useOutputController.esm.js.map +1 -0
- package/dist/components/TemplateDesigner/TemplateLanding.esm.js +157 -0
- package/dist/components/TemplateDesigner/TemplateLanding.esm.js.map +1 -0
- package/dist/components/TemplateDesigner/TemplateWorkspace.esm.js +416 -0
- package/dist/components/TemplateDesigner/TemplateWorkspace.esm.js.map +1 -0
- package/dist/components/TemplateDesigner/codemirrorTheme.esm.js +30 -0
- package/dist/components/TemplateDesigner/codemirrorTheme.esm.js.map +1 -0
- package/dist/components/TemplateDesigner/useFieldEditor.esm.js +95 -0
- package/dist/components/TemplateDesigner/useFieldEditor.esm.js.map +1 -0
- package/dist/components/TemplateDesignerIcon.esm.js +33 -0
- package/dist/components/TemplateDesignerIcon.esm.js.map +1 -0
- package/dist/components/designerFlowConfig.esm.js +13 -0
- package/dist/components/designerFlowConfig.esm.js.map +1 -0
- package/dist/designerFlow/DesignerFlow.esm.js +828 -0
- package/dist/designerFlow/DesignerFlow.esm.js.map +1 -0
- package/dist/designerFlow/handlers.esm.js +317 -0
- package/dist/designerFlow/handlers.esm.js.map +1 -0
- package/dist/designerFlow/model.esm.js +166 -0
- package/dist/designerFlow/model.esm.js.map +1 -0
- package/dist/designerFlow/nodeLayout.esm.js +108 -0
- package/dist/designerFlow/nodeLayout.esm.js.map +1 -0
- package/dist/designerFlow/parameterTransforms.esm.js +124 -0
- package/dist/designerFlow/parameterTransforms.esm.js.map +1 -0
- package/dist/designerFlow/utils/stableComparators.esm.js +69 -0
- package/dist/designerFlow/utils/stableComparators.esm.js.map +1 -0
- package/dist/foundation/actionNodeCustomization.esm.js +20 -0
- package/dist/foundation/actionNodeCustomization.esm.js.map +1 -0
- package/dist/foundation/actionNodeRegistry.esm.js +30 -0
- package/dist/foundation/actionNodeRegistry.esm.js.map +1 -0
- package/dist/foundation/featureFlags.esm.js +6 -0
- package/dist/foundation/featureFlags.esm.js.map +1 -0
- package/dist/foundation/templateSources.esm.js +16 -0
- package/dist/foundation/templateSources.esm.js.map +1 -0
- package/dist/index.d.ts +382 -0
- package/dist/index.esm.js +25 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/state/templateUtils.esm.js +46 -0
- package/dist/state/templateUtils.esm.js.map +1 -0
- package/dist/state/useParameterSections.esm.js +162 -0
- package/dist/state/useParameterSections.esm.js.map +1 -0
- package/dist/state/useTemplateState.esm.js +627 -0
- package/dist/state/useTemplateState.esm.js.map +1 -0
- package/dist/types/flowNodes.esm.js +8 -0
- package/dist/types/flowNodes.esm.js.map +1 -0
- package/dist/utils/createSequentialEdges.esm.js +15 -0
- package/dist/utils/createSequentialEdges.esm.js.map +1 -0
- package/dist/utils/mocks/mocks.esm.js +120 -0
- package/dist/utils/mocks/mocks.esm.js.map +1 -0
- package/dist/utils/sampleTemplate.esm.js +40 -0
- package/dist/utils/sampleTemplate.esm.js.map +1 -0
- package/dist/utils/yamlJsonConversion.esm.js +47 -0
- package/dist/utils/yamlJsonConversion.esm.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.esm.js","sources":["../../src/designerFlow/model.ts"],"sourcesContent":["import type { Node } from \"@xyflow/react\";\nimport type {\n TaskStep,\n ScaffolderTaskOutput,\n} from \"@backstage/plugin-scaffolder-common\";\nimport type {\n ActionNodeData,\n OutputNodeData,\n ParametersNodeData,\n TemplateParametersValue,\n} from \"../types/flowNodes\";\nimport { alignNodes } from \"./nodeLayout\";\nimport { normalizeParametersToSections } from \"./parameterTransforms\";\nimport { FLOW_LAYOUT, nodeDefaults } from \"../components/designerFlowConfig\";\n\nconst sanitizeForRfId = (value: string) =>\n value.replace(/[^a-zA-Z0-9-_.:]/g, \"_\");\n\nconst buildRfId = (step: TaskStep | undefined, index: number) => {\n if (step && typeof step.id === \"string\" && step.id.trim().length > 0) {\n return `rf-${sanitizeForRfId(step.id)}-${index}`;\n }\n return `rf-${index + 1}`;\n};\n\nexport const cloneStep = (step: TaskStep): TaskStep =>\n JSON.parse(JSON.stringify(step ?? {})) as TaskStep;\n\nexport const cloneOutput = (\n output: ScaffolderTaskOutput | undefined | null\n): ScaffolderTaskOutput =>\n JSON.parse(JSON.stringify(output ?? {})) as ScaffolderTaskOutput;\n\nexport const cloneParameters = (\n parameters: TemplateParametersValue\n): TemplateParametersValue =>\n parameters === undefined\n ? undefined\n : (JSON.parse(JSON.stringify(parameters)) as TemplateParametersValue);\n\nexport type BuildNodesFromModelOptions = {\n scaffolderActionIds: string[];\n scaffolderActionInputsById: Record<string, Record<string, unknown>>;\n scaffolderActionOutputsById: Record<string, Record<string, unknown>>;\n scaffolderActionInputRequiredById: Record<string, string[]>;\n};\n\nexport const buildNodesFromModel = (\n steps: TaskStep[],\n parameters: TemplateParametersValue,\n output: ScaffolderTaskOutput | undefined | null,\n options: BuildNodesFromModelOptions\n) => {\n const {\n scaffolderActionIds,\n scaffolderActionInputsById,\n scaffolderActionOutputsById,\n scaffolderActionInputRequiredById,\n } = options;\n\n const parameterSections = normalizeParametersToSections(parameters);\n const nodes: Node[] = [];\n\n const rfParametersId = \"rf-parameters\";\n nodes.push({\n id: rfParametersId,\n type: \"parametersNode\",\n position: { x: FLOW_LAYOUT.fixedXPosition, y: 0 },\n data: {\n rfId: rfParametersId,\n parameters: cloneParameters(parameters),\n sections: parameterSections,\n scaffolderActionIds,\n scaffolderActionInputsById,\n scaffolderActionInputRequiredById,\n scaffolderActionOutputsById,\n },\n ...nodeDefaults,\n });\n\n const rfOutputId = \"rf-output\";\n nodes.push({\n id: rfOutputId,\n type: \"outputNode\",\n position: {\n x: FLOW_LAYOUT.fixedXPosition,\n y: FLOW_LAYOUT.verticalSpacing * (steps.length + 1),\n },\n data: {\n rfId: rfOutputId,\n output: cloneOutput(output),\n scaffolderActionIds,\n scaffolderActionInputsById,\n scaffolderActionInputRequiredById,\n scaffolderActionOutputsById,\n } satisfies OutputNodeData,\n ...nodeDefaults,\n });\n\n steps.forEach((step, index) => {\n const rfId = buildRfId(step, index);\n nodes.splice(index + 1, 0, {\n id: rfId,\n type: \"actionNode\",\n position: {\n x: FLOW_LAYOUT.fixedXPosition,\n y: FLOW_LAYOUT.verticalSpacing * (index + 1),\n },\n data: {\n rfId,\n step: cloneStep(step),\n scaffolderActionIds,\n scaffolderActionInputsById,\n scaffolderActionInputRequiredById,\n scaffolderActionOutputsById,\n } satisfies ActionNodeData,\n ...nodeDefaults,\n });\n });\n\n return alignNodes(\n nodes,\n FLOW_LAYOUT.fixedXPosition,\n FLOW_LAYOUT.verticalSpacing\n );\n};\n\nexport const extractStepsFromNodes = (nodes: Node[]): TaskStep[] => {\n const actionNodes = nodes.filter(\n (node) => node.type === \"actionNode\"\n ) as Node<ActionNodeData>[];\n return actionNodes.map((node) => cloneStep(node.data.step));\n};\n\nexport const extractParametersFromNodes = (\n nodes: Node[]\n): TemplateParametersValue => {\n const parametersNode = nodes.find(\n (node) => node.type === \"parametersNode\"\n ) as Node<ParametersNodeData> | undefined;\n if (!parametersNode) {\n return [];\n }\n return cloneParameters(parametersNode.data.parameters);\n};\n\nexport const extractOutputFromNodes = (\n nodes: Node[]\n): ScaffolderTaskOutput | undefined => {\n const outputNode = nodes.find((node) => node.type === \"outputNode\") as\n | Node<OutputNodeData>\n | undefined;\n if (!outputNode) {\n return undefined;\n }\n return cloneOutput(outputNode.data.output);\n};\n\nexport const collectParameterReferences = (\n parameters: TemplateParametersValue | undefined\n): string[] => {\n if (!parameters || !Array.isArray(parameters)) {\n return [];\n }\n return parameters.flatMap((param) =>\n Object.keys((param as any)?.properties ?? {}).map(\n (propKey) => `parameters.${propKey}`\n )\n );\n};\n\nexport const collectStepOutputReferences = (\n nodes: Node[],\n parameterReferences: string[]\n): Record<string, string[]> => {\n const formatRef = (ref: string) => `\\${{ ${ref} }}`;\n\n const actionNodes = nodes.filter(\n (node) => node.type === \"actionNode\"\n ) as Node<ActionNodeData>[];\n const outputNode = nodes.find((node) => node.type === \"outputNode\") as\n | Node<OutputNodeData>\n | undefined;\n\n const references: Record<string, string[]> = {};\n\n actionNodes.forEach((node, index) => {\n const priorSteps = actionNodes\n .slice(0, index)\n .map((n) => n.data?.step?.id)\n .filter(Boolean) as string[];\n const priorStepRefs = priorSteps.map((id) =>\n formatRef(`steps.${id}.output`)\n );\n const priorIds = priorSteps.map((id) => formatRef(`steps.${id}.id`));\n const parameterRefs = parameterReferences.map((ref) => formatRef(ref));\n\n const thisStepId = node.data?.step?.id;\n if (!thisStepId) {\n references[node.id] = [...parameterRefs, ...priorStepRefs, ...priorIds];\n return;\n }\n\n const outputRefs = [\n formatRef(`steps.${thisStepId}.output`),\n ...priorStepRefs,\n ...parameterRefs,\n ];\n references[node.id] = Array.from(new Set(outputRefs));\n });\n\n if (outputNode) {\n const allSteps = actionNodes.map((n) => n.data?.step?.id).filter(Boolean);\n const refs = [\n ...allSteps.map((id) => formatRef(`steps.${id}.output`)),\n ...parameterReferences.map((ref) => formatRef(ref)),\n ];\n references[outputNode.id] = Array.from(new Set(refs));\n }\n\n return references;\n};\n\nexport const stableStringify = (value: unknown) =>\n JSON.stringify(value, (_key, v) => {\n if (Array.isArray(v)) {\n return v;\n }\n if (v && typeof v === \"object\") {\n return Object.keys(v as Record<string, unknown>)\n .sort()\n .reduce<Record<string, unknown>>((acc, k) => {\n acc[k] = (v as Record<string, unknown>)[k];\n return acc;\n }, {});\n }\n return v;\n });\n"],"names":[],"mappings":";;;;AAeA,MAAM,kBAAkB,CAAC,KAAA,KACvB,KAAA,CAAM,OAAA,CAAQ,qBAAqB,GAAG,CAAA;AAExC,MAAM,SAAA,GAAY,CAAC,IAAA,EAA4B,KAAA,KAAkB;AAC/D,EAAA,IAAI,IAAA,IAAQ,OAAO,IAAA,CAAK,EAAA,KAAO,QAAA,IAAY,KAAK,EAAA,CAAG,IAAA,EAAK,CAAE,MAAA,GAAS,CAAA,EAAG;AACpE,IAAA,OAAO,MAAM,eAAA,CAAgB,IAAA,CAAK,EAAE,CAAC,IAAI,KAAK,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,CAAA,GAAA,EAAM,QAAQ,CAAC,CAAA,CAAA;AACxB,CAAA;AAEO,MAAM,SAAA,GAAY,CAAC,IAAA,KACxB,IAAA,CAAK,KAAA,CAAM,KAAK,SAAA,CAAU,IAAA,IAAQ,EAAE,CAAC;AAEhC,MAAM,WAAA,GAAc,CACzB,MAAA,KAEA,IAAA,CAAK,KAAA,CAAM,KAAK,SAAA,CAAU,MAAA,IAAU,EAAE,CAAC;AAElC,MAAM,eAAA,GAAkB,CAC7B,UAAA,KAEA,UAAA,KAAe,MAAA,GACX,MAAA,GACC,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,UAAU,CAAC;AASrC,MAAM,mBAAA,GAAsB,CACjC,KAAA,EACA,UAAA,EACA,QACA,OAAA,KACG;AACH,EAAA,MAAM;AAAA,IACJ,mBAAA;AAAA,IACA,0BAAA;AAAA,IACA,2BAAA;AAAA,IACA;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,iBAAA,GAAoB,8BAA8B,UAAU,CAAA;AAClE,EAAA,MAAM,QAAgB,EAAC;AAEvB,EAAA,MAAM,cAAA,GAAiB,eAAA;AACvB,EAAA,KAAA,CAAM,IAAA,CAAK;AAAA,IACT,EAAA,EAAI,cAAA;AAAA,IACJ,IAAA,EAAM,gBAAA;AAAA,IACN,UAAU,EAAE,CAAA,EAAG,WAAA,CAAY,cAAA,EAAgB,GAAG,CAAA,EAAE;AAAA,IAChD,IAAA,EAAM;AAAA,MACJ,IAAA,EAAM,cAAA;AAAA,MACN,UAAA,EAAY,gBAAgB,UAAU,CAAA;AAAA,MACtC,QAAA,EAAU,iBAAA;AAAA,MACV,mBAAA;AAAA,MACA,0BAAA;AAAA,MACA,iCAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AAED,EAAA,MAAM,UAAA,GAAa,WAAA;AACnB,EAAA,KAAA,CAAM,IAAA,CAAK;AAAA,IACT,EAAA,EAAI,UAAA;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,QAAA,EAAU;AAAA,MACR,GAAG,WAAA,CAAY,cAAA;AAAA,MACf,CAAA,EAAG,WAAA,CAAY,eAAA,IAAmB,KAAA,CAAM,MAAA,GAAS,CAAA;AAAA,KACnD;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,IAAA,EAAM,UAAA;AAAA,MACN,MAAA,EAAQ,YAAY,MAAM,CAAA;AAAA,MAC1B,mBAAA;AAAA,MACA,0BAAA;AAAA,MACA,iCAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AAED,EAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU;AAC7B,IAAA,MAAM,IAAA,GAAO,SAAA,CAAU,IAAA,EAAM,KAAK,CAAA;AAClC,IAAA,KAAA,CAAM,MAAA,CAAO,KAAA,GAAQ,CAAA,EAAG,CAAA,EAAG;AAAA,MACzB,EAAA,EAAI,IAAA;AAAA,MACJ,IAAA,EAAM,YAAA;AAAA,MACN,QAAA,EAAU;AAAA,QACR,GAAG,WAAA,CAAY,cAAA;AAAA,QACf,CAAA,EAAG,WAAA,CAAY,eAAA,IAAmB,KAAA,GAAQ,CAAA;AAAA,OAC5C;AAAA,MACA,IAAA,EAAM;AAAA,QACJ,IAAA;AAAA,QACA,IAAA,EAAM,UAAU,IAAI,CAAA;AAAA,QACpB,mBAAA;AAAA,QACA,0BAAA;AAAA,QACA,iCAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,GAAG;AAAA,KACJ,CAAA;AAAA,EACH,CAAC,CAAA;AAED,EAAA,OAAO,UAAA;AAAA,IACL,KAAA;AAAA,IACA,WAAA,CAAY,cAAA;AAAA,IACZ,WAAA,CAAY;AAAA,GACd;AACF;AAEO,MAAM,qBAAA,GAAwB,CAAC,KAAA,KAA8B;AAClE,EAAA,MAAM,cAAc,KAAA,CAAM,MAAA;AAAA,IACxB,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,KAAS;AAAA,GAC1B;AACA,EAAA,OAAO,WAAA,CAAY,IAAI,CAAC,IAAA,KAAS,UAAU,IAAA,CAAK,IAAA,CAAK,IAAI,CAAC,CAAA;AAC5D;AAEO,MAAM,0BAAA,GAA6B,CACxC,KAAA,KAC4B;AAC5B,EAAA,MAAM,iBAAiB,KAAA,CAAM,IAAA;AAAA,IAC3B,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,KAAS;AAAA,GAC1B;AACA,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,eAAA,CAAgB,cAAA,CAAe,IAAA,CAAK,UAAU,CAAA;AACvD;AAEO,MAAM,sBAAA,GAAyB,CACpC,KAAA,KACqC;AACrC,EAAA,MAAM,aAAa,KAAA,CAAM,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,SAAS,YAAY,CAAA;AAGlE,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,WAAA,CAAY,UAAA,CAAW,IAAA,CAAK,MAAM,CAAA;AAC3C;AAEO,MAAM,0BAAA,GAA6B,CACxC,UAAA,KACa;AACb,EAAA,IAAI,CAAC,UAAA,IAAc,CAAC,KAAA,CAAM,OAAA,CAAQ,UAAU,CAAA,EAAG;AAC7C,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,UAAA,CAAW,OAAA;AAAA,IAAQ,CAAC,UACzB,MAAA,CAAO,IAAA,CAAM,OAAe,UAAA,IAAc,EAAE,CAAA,CAAE,GAAA;AAAA,MAC5C,CAAC,OAAA,KAAY,CAAA,WAAA,EAAc,OAAO,CAAA;AAAA;AACpC,GACF;AACF;AAEO,MAAM,2BAAA,GAA8B,CACzC,KAAA,EACA,mBAAA,KAC6B;AAC7B,EAAA,MAAM,SAAA,GAAY,CAAC,GAAA,KAAgB,CAAA,KAAA,EAAQ,GAAG,CAAA,GAAA,CAAA;AAE9C,EAAA,MAAM,cAAc,KAAA,CAAM,MAAA;AAAA,IACxB,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,KAAS;AAAA,GAC1B;AACA,EAAA,MAAM,aAAa,KAAA,CAAM,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,SAAS,YAAY,CAAA;AAIlE,EAAA,MAAM,aAAuC,EAAC;AAE9C,EAAA,WAAA,CAAY,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU;AACnC,IAAA,MAAM,UAAA,GAAa,WAAA,CAChB,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,CACd,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,IAAA,EAAM,IAAA,EAAM,EAAE,CAAA,CAC3B,OAAO,OAAO,CAAA;AACjB,IAAA,MAAM,gBAAgB,UAAA,CAAW,GAAA;AAAA,MAAI,CAAC,EAAA,KACpC,SAAA,CAAU,CAAA,MAAA,EAAS,EAAE,CAAA,OAAA,CAAS;AAAA,KAChC;AACA,IAAA,MAAM,QAAA,GAAW,WAAW,GAAA,CAAI,CAAC,OAAO,SAAA,CAAU,CAAA,MAAA,EAAS,EAAE,CAAA,GAAA,CAAK,CAAC,CAAA;AACnE,IAAA,MAAM,gBAAgB,mBAAA,CAAoB,GAAA,CAAI,CAAC,GAAA,KAAQ,SAAA,CAAU,GAAG,CAAC,CAAA;AAErE,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,EAAM,IAAA,EAAM,EAAA;AACpC,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,UAAA,CAAW,IAAA,CAAK,EAAE,CAAA,GAAI,CAAC,GAAG,aAAA,EAAe,GAAG,aAAA,EAAe,GAAG,QAAQ,CAAA;AACtE,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa;AAAA,MACjB,SAAA,CAAU,CAAA,MAAA,EAAS,UAAU,CAAA,OAAA,CAAS,CAAA;AAAA,MACtC,GAAG,aAAA;AAAA,MACH,GAAG;AAAA,KACL;AACA,IAAA,UAAA,CAAW,IAAA,CAAK,EAAE,CAAA,GAAI,KAAA,CAAM,KAAK,IAAI,GAAA,CAAI,UAAU,CAAC,CAAA;AAAA,EACtD,CAAC,CAAA;AAED,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAM,QAAA,GAAW,WAAA,CAAY,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,IAAA,EAAM,EAAE,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA;AACxE,IAAA,MAAM,IAAA,GAAO;AAAA,MACX,GAAG,SAAS,GAAA,CAAI,CAAC,OAAO,SAAA,CAAU,CAAA,MAAA,EAAS,EAAE,CAAA,OAAA,CAAS,CAAC,CAAA;AAAA,MACvD,GAAG,mBAAA,CAAoB,GAAA,CAAI,CAAC,GAAA,KAAQ,SAAA,CAAU,GAAG,CAAC;AAAA,KACpD;AACA,IAAA,UAAA,CAAW,UAAA,CAAW,EAAE,CAAA,GAAI,KAAA,CAAM,KAAK,IAAI,GAAA,CAAI,IAAI,CAAC,CAAA;AAAA,EACtD;AAEA,EAAA,OAAO,UAAA;AACT;AAEO,MAAM,eAAA,GAAkB,CAAC,KAAA,KAC9B,IAAA,CAAK,UAAU,KAAA,EAAO,CAAC,MAAM,CAAA,KAAM;AACjC,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG;AACpB,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAA,IAAK,OAAO,CAAA,KAAM,QAAA,EAAU;AAC9B,IAAA,OAAO,MAAA,CAAO,KAAK,CAA4B,CAAA,CAC5C,MAAK,CACL,MAAA,CAAgC,CAAC,GAAA,EAAK,CAAA,KAAM;AAC3C,MAAA,GAAA,CAAI,CAAC,CAAA,GAAK,CAAA,CAA8B,CAAC,CAAA;AACzC,MAAA,OAAO,GAAA;AAAA,IACT,CAAA,EAAG,EAAE,CAAA;AAAA,EACT;AACA,EAAA,OAAO,CAAA;AACT,CAAC;;;;"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { NODE_VERTICAL_SPACING } from '../types/flowNodes.esm.js';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_NODE_HEIGHT = 320;
|
|
4
|
+
const MIN_VERTICAL_GAP = 16;
|
|
5
|
+
const parseNumericHeight = (value) => {
|
|
6
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
if (typeof value === "string") {
|
|
10
|
+
const parsed = Number.parseFloat(value);
|
|
11
|
+
if (!Number.isNaN(parsed) && parsed > 0) {
|
|
12
|
+
return parsed;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
const estimateParametersNodeHeight = (node) => {
|
|
18
|
+
if (node.type !== "parametersNode") {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const data = node.data;
|
|
22
|
+
if (!data) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const sections = data.sections ?? [];
|
|
26
|
+
const PARAMETER_SHELL_HEIGHT = 300;
|
|
27
|
+
const PARAMETER_CARD_BASE = 220;
|
|
28
|
+
const SECTION_BASE = 180;
|
|
29
|
+
const FIELD_HEIGHT = 86;
|
|
30
|
+
if (!sections.length) {
|
|
31
|
+
return PARAMETER_SHELL_HEIGHT + PARAMETER_CARD_BASE + SECTION_BASE;
|
|
32
|
+
}
|
|
33
|
+
const sectionsHeight = sections.reduce((total, section) => {
|
|
34
|
+
const fieldCount = section.fields?.length ?? 0;
|
|
35
|
+
return total + SECTION_BASE + Math.max(fieldCount, 1) * FIELD_HEIGHT;
|
|
36
|
+
}, 0);
|
|
37
|
+
return PARAMETER_SHELL_HEIGHT + PARAMETER_CARD_BASE + sectionsHeight;
|
|
38
|
+
};
|
|
39
|
+
const estimateActionNodeHeight = (node) => {
|
|
40
|
+
if (node.type !== "actionNode") {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const data = node.data;
|
|
44
|
+
if (!data) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const inputsLength = Object.keys(data.step?.input ?? {}).length || 0;
|
|
48
|
+
const INPUT_ROW_HEIGHT = 56;
|
|
49
|
+
const BASE_HEIGHT = 420;
|
|
50
|
+
return BASE_HEIGHT + inputsLength * INPUT_ROW_HEIGHT;
|
|
51
|
+
};
|
|
52
|
+
const estimateOutputNodeHeight = (node) => {
|
|
53
|
+
if (node.type !== "outputNode") {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const data = node.data;
|
|
57
|
+
if (!data) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const linksLength = Array.isArray(data.output?.links) ? data.output.links.length : 0;
|
|
61
|
+
const textLength = Array.isArray(data.output?.text) ? data.output.text.length : 0;
|
|
62
|
+
const ITEM_HEIGHT = 56;
|
|
63
|
+
const BASE_HEIGHT = 320;
|
|
64
|
+
return BASE_HEIGHT + Math.max(linksLength + textLength, 1) * ITEM_HEIGHT;
|
|
65
|
+
};
|
|
66
|
+
const estimateHeightByType = (node) => {
|
|
67
|
+
return estimateParametersNodeHeight(node) ?? estimateActionNodeHeight(node) ?? estimateOutputNodeHeight(node);
|
|
68
|
+
};
|
|
69
|
+
const resolveNodeHeightForTracking = (node) => {
|
|
70
|
+
const explicit = parseNumericHeight(node?.measured?.height);
|
|
71
|
+
if (explicit !== null) {
|
|
72
|
+
return explicit;
|
|
73
|
+
}
|
|
74
|
+
return estimateHeightByType(node);
|
|
75
|
+
};
|
|
76
|
+
const alignNodes = (nodes, fixedXPosition, verticalSpacing) => {
|
|
77
|
+
const parametersNode = nodes.find((node) => node.type === "parametersNode");
|
|
78
|
+
const actionNodes = nodes.filter((node) => node.type === "actionNode");
|
|
79
|
+
const outputNode = nodes.find((node) => node.type === "outputNode");
|
|
80
|
+
let nextY = 0;
|
|
81
|
+
const aligned = [];
|
|
82
|
+
if (parametersNode) {
|
|
83
|
+
aligned.push({
|
|
84
|
+
...parametersNode,
|
|
85
|
+
position: { x: fixedXPosition, y: 0 }
|
|
86
|
+
});
|
|
87
|
+
const height = resolveNodeHeightForTracking(parametersNode) ?? NODE_VERTICAL_SPACING.parametersNode ?? DEFAULT_NODE_HEIGHT;
|
|
88
|
+
nextY += height + verticalSpacing + MIN_VERTICAL_GAP;
|
|
89
|
+
}
|
|
90
|
+
actionNodes.forEach((node, _index) => {
|
|
91
|
+
aligned.push({
|
|
92
|
+
...node,
|
|
93
|
+
position: { x: fixedXPosition, y: nextY }
|
|
94
|
+
});
|
|
95
|
+
const height = resolveNodeHeightForTracking(node) ?? NODE_VERTICAL_SPACING.actionNode ?? DEFAULT_NODE_HEIGHT;
|
|
96
|
+
nextY += height + verticalSpacing + MIN_VERTICAL_GAP;
|
|
97
|
+
});
|
|
98
|
+
if (outputNode) {
|
|
99
|
+
aligned.push({
|
|
100
|
+
...outputNode,
|
|
101
|
+
position: { x: fixedXPosition, y: nextY }
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return aligned;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export { alignNodes, resolveNodeHeightForTracking };
|
|
108
|
+
//# sourceMappingURL=nodeLayout.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeLayout.esm.js","sources":["../../src/designerFlow/nodeLayout.ts"],"sourcesContent":["import type { Node } from \"@xyflow/react\";\nimport type {\n ActionNodeData,\n OutputNodeData,\n ParametersNodeData,\n} from \"../types/flowNodes\";\nimport { NODE_VERTICAL_SPACING } from \"../types/flowNodes\";\n\n// Shared helpers for computing consistent node alignment/spacing in the flow.\n\nconst DEFAULT_NODE_HEIGHT = 320;\nconst MIN_VERTICAL_GAP = 16;\n\nconst parseNumericHeight = (value: unknown): number | null => {\n if (typeof value === \"number\" && Number.isFinite(value) && value > 0) {\n return value;\n }\n if (typeof value === \"string\") {\n const parsed = Number.parseFloat(value);\n if (!Number.isNaN(parsed) && parsed > 0) {\n return parsed;\n }\n }\n return null;\n};\n\nconst estimateParametersNodeHeight = (node: Node): number | null => {\n if (node.type !== \"parametersNode\") {\n return null;\n }\n const data = node.data as ParametersNodeData | undefined;\n if (!data) {\n return null;\n }\n\n const sections = data.sections ?? [];\n const PARAMETER_SHELL_HEIGHT = 300;\n const PARAMETER_CARD_BASE = 220;\n const SECTION_BASE = 180;\n const FIELD_HEIGHT = 86;\n\n if (!sections.length) {\n return PARAMETER_SHELL_HEIGHT + PARAMETER_CARD_BASE + SECTION_BASE;\n }\n\n const sectionsHeight = sections.reduce((total, section) => {\n const fieldCount = section.fields?.length ?? 0;\n return total + SECTION_BASE + Math.max(fieldCount, 1) * FIELD_HEIGHT;\n }, 0);\n\n return PARAMETER_SHELL_HEIGHT + PARAMETER_CARD_BASE + sectionsHeight;\n};\n\nconst estimateActionNodeHeight = (node: Node): number | null => {\n if (node.type !== \"actionNode\") {\n return null;\n }\n const data = node.data as ActionNodeData | undefined;\n if (!data) {\n return null;\n }\n const inputsLength = Object.keys(data.step?.input ?? {}).length || 0;\n const INPUT_ROW_HEIGHT = 56;\n const BASE_HEIGHT = 420;\n return BASE_HEIGHT + inputsLength * INPUT_ROW_HEIGHT;\n};\n\nconst estimateOutputNodeHeight = (node: Node): number | null => {\n if (node.type !== \"outputNode\") {\n return null;\n }\n const data = node.data as OutputNodeData | undefined;\n if (!data) {\n return null;\n }\n const linksLength = Array.isArray(data.output?.links)\n ? data.output.links.length\n : 0;\n const textLength = Array.isArray((data.output as any)?.text)\n ? (data.output as any).text.length\n : 0;\n const ITEM_HEIGHT = 56;\n const BASE_HEIGHT = 320;\n return BASE_HEIGHT + Math.max(linksLength + textLength, 1) * ITEM_HEIGHT;\n};\n\nconst estimateHeightByType = (node: Node): number | null => {\n return (\n estimateParametersNodeHeight(node) ??\n estimateActionNodeHeight(node) ??\n estimateOutputNodeHeight(node)\n );\n};\n\nexport const resolveNodeHeightForTracking = (node: Node): number | null => {\n const explicit = parseNumericHeight(node?.measured?.height);\n if (explicit !== null) {\n return explicit;\n }\n return estimateHeightByType(node);\n};\n\nexport const alignNodes = (\n nodes: Node[],\n fixedXPosition: number,\n verticalSpacing: number\n) => {\n const parametersNode = nodes.find((node) => node.type === \"parametersNode\");\n const actionNodes = nodes.filter((node) => node.type === \"actionNode\");\n const outputNode = nodes.find((node) => node.type === \"outputNode\");\n\n let nextY = 0;\n const aligned: Node[] = [];\n\n if (parametersNode) {\n aligned.push({\n ...parametersNode,\n position: { x: fixedXPosition, y: 0 },\n });\n const height =\n resolveNodeHeightForTracking(parametersNode) ??\n NODE_VERTICAL_SPACING.parametersNode ??\n DEFAULT_NODE_HEIGHT;\n nextY += height + verticalSpacing + MIN_VERTICAL_GAP;\n }\n\n actionNodes.forEach((node, _index) => {\n aligned.push({\n ...node,\n position: { x: fixedXPosition, y: nextY },\n });\n const height =\n resolveNodeHeightForTracking(node) ??\n NODE_VERTICAL_SPACING.actionNode ??\n DEFAULT_NODE_HEIGHT;\n nextY += height + verticalSpacing + MIN_VERTICAL_GAP;\n });\n\n if (outputNode) {\n aligned.push({\n ...outputNode,\n position: { x: fixedXPosition, y: nextY },\n });\n }\n\n return aligned;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const asString = (value) => typeof value === "string" ? value : void 0;
|
|
2
|
+
const asStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string") ? value : void 0;
|
|
3
|
+
const asSchemaRecord = (value) => {
|
|
4
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5
|
+
return void 0;
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
};
|
|
9
|
+
const cloneSchema = (schema) => {
|
|
10
|
+
if (!schema) {
|
|
11
|
+
return void 0;
|
|
12
|
+
}
|
|
13
|
+
return JSON.parse(JSON.stringify(schema));
|
|
14
|
+
};
|
|
15
|
+
const cloneProperties = (properties) => {
|
|
16
|
+
if (!properties) {
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
return JSON.parse(JSON.stringify(properties));
|
|
20
|
+
};
|
|
21
|
+
const buildDefaultSchema = (fieldName) => ({
|
|
22
|
+
title: fieldName || "Field",
|
|
23
|
+
type: "string"
|
|
24
|
+
});
|
|
25
|
+
const buildFieldsForSection = (sectionId, sectionTitle, properties, requiredList) => {
|
|
26
|
+
if (!properties) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
return Object.entries(properties).map(([fieldName, schema], fieldIndex) => {
|
|
30
|
+
const isRequired = Array.isArray(requiredList) && requiredList.includes(fieldName);
|
|
31
|
+
const safeSchema = cloneSchema(schema) ?? buildDefaultSchema(fieldName);
|
|
32
|
+
return {
|
|
33
|
+
id: `${sectionId}-field-${fieldIndex}`,
|
|
34
|
+
fieldName,
|
|
35
|
+
sectionId,
|
|
36
|
+
sectionTitle,
|
|
37
|
+
required: Boolean(isRequired),
|
|
38
|
+
schema: safeSchema
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const sanitizeField = (field, fallbackSectionId, index) => {
|
|
43
|
+
const fieldId = field.id ?? `${fallbackSectionId}-field-${index}`;
|
|
44
|
+
return {
|
|
45
|
+
...field,
|
|
46
|
+
id: fieldId,
|
|
47
|
+
sectionId: field.sectionId ?? fallbackSectionId,
|
|
48
|
+
schema: cloneSchema(field.schema) ?? buildDefaultSchema(field.fieldName)
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const sanitizeSection = (section, index) => {
|
|
52
|
+
const sectionId = section.id ?? `section-${index}`;
|
|
53
|
+
const properties = asSchemaRecord(section.properties);
|
|
54
|
+
const required = asStringArray(section.required);
|
|
55
|
+
const fields = section.fields?.map((field, idx) => sanitizeField(field, sectionId, idx))?.filter(Boolean) ?? [];
|
|
56
|
+
let safeFields = fields;
|
|
57
|
+
if (!fields.length) {
|
|
58
|
+
safeFields = buildFieldsForSection(
|
|
59
|
+
sectionId,
|
|
60
|
+
section.title,
|
|
61
|
+
properties,
|
|
62
|
+
required ?? []
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
...section,
|
|
67
|
+
id: sectionId,
|
|
68
|
+
properties: cloneProperties(properties),
|
|
69
|
+
required: required ?? [],
|
|
70
|
+
fields: safeFields
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
const sanitizeSections = (sections) => sections.map((section, index) => sanitizeSection(section, index));
|
|
74
|
+
const normalizeParametersToSections = (parameters) => {
|
|
75
|
+
if (!Array.isArray(parameters)) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
const unsafe = parameters.filter(
|
|
79
|
+
(param) => param && typeof param === "object"
|
|
80
|
+
);
|
|
81
|
+
return unsafe.map(
|
|
82
|
+
(param, index) => sanitizeSection(
|
|
83
|
+
{
|
|
84
|
+
id: param.id ?? `section-${index}`,
|
|
85
|
+
title: asString(param.title),
|
|
86
|
+
description: asString(param.description),
|
|
87
|
+
required: asStringArray(param.required),
|
|
88
|
+
properties: asSchemaRecord(param.properties),
|
|
89
|
+
fields: []
|
|
90
|
+
},
|
|
91
|
+
index
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
const sectionsToParametersValue = (sections) => {
|
|
96
|
+
if (!sections) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
const normalizedSections = sanitizeSections(sections);
|
|
100
|
+
const result = normalizedSections.map(
|
|
101
|
+
(section, index) => {
|
|
102
|
+
const properties = section.fields?.reduce((acc, field) => {
|
|
103
|
+
if (!field.fieldName) {
|
|
104
|
+
return acc;
|
|
105
|
+
}
|
|
106
|
+
acc[field.fieldName] = cloneSchema(field.schema) ?? buildDefaultSchema(field.fieldName);
|
|
107
|
+
return acc;
|
|
108
|
+
}, {}) ?? {};
|
|
109
|
+
const required = section.fields?.filter((field) => field.required && field.fieldName)?.map((field) => field.fieldName) ?? [];
|
|
110
|
+
const defaultSectionTitle = `Section ${index + 1}`;
|
|
111
|
+
return {
|
|
112
|
+
id: section.id,
|
|
113
|
+
title: section.title ?? defaultSectionTitle,
|
|
114
|
+
description: section.description,
|
|
115
|
+
properties,
|
|
116
|
+
required
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
return result;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export { normalizeParametersToSections, sanitizeSections, sectionsToParametersValue };
|
|
124
|
+
//# sourceMappingURL=parameterTransforms.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parameterTransforms.esm.js","sources":["../../src/designerFlow/parameterTransforms.ts"],"sourcesContent":["import type {\n TemplateParameterSchema,\n TemplateParametersV1beta3,\n} from \"@backstage/plugin-scaffolder-common\";\nimport type {\n ParameterFieldDisplay,\n ParameterSectionDisplay,\n TemplateParametersValue,\n} from \"../types/flowNodes\";\n\ntype ParameterPropertySchema = Record<string, unknown>;\ntype ParameterProperties = Record<string, ParameterPropertySchema>;\n\nconst asString = (value: unknown): string | undefined =>\n typeof value === \"string\" ? value : undefined;\n\nconst asStringArray = (value: unknown): string[] | undefined =>\n Array.isArray(value) && value.every((item) => typeof item === \"string\")\n ? (value as string[])\n : undefined;\n\nconst asSchemaRecord = (value: unknown): ParameterProperties | undefined => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n return value as ParameterProperties;\n};\n\nconst cloneSchema = (\n schema?: ParameterPropertySchema\n): ParameterPropertySchema | undefined => {\n if (!schema) {\n return undefined;\n }\n return JSON.parse(JSON.stringify(schema)) as ParameterPropertySchema;\n};\n\nconst cloneProperties = (\n properties?: ParameterProperties\n): Record<string, Record<string, unknown>> | undefined => {\n if (!properties) {\n return undefined;\n }\n return JSON.parse(JSON.stringify(properties)) as Record<\n string,\n Record<string, unknown>\n >;\n};\n\nconst buildDefaultSchema = (fieldName: string): ParameterPropertySchema => ({\n title: fieldName || \"Field\",\n type: \"string\",\n});\n\nconst buildFieldsForSection = (\n sectionId: string,\n sectionTitle: string | undefined,\n properties?: Record<string, ParameterPropertySchema>,\n requiredList?: string[]\n): ParameterFieldDisplay[] => {\n if (!properties) {\n return [];\n }\n\n return Object.entries(properties).map(([fieldName, schema], fieldIndex) => {\n const isRequired =\n Array.isArray(requiredList) && requiredList.includes(fieldName);\n const safeSchema = cloneSchema(schema) ?? buildDefaultSchema(fieldName);\n return {\n id: `${sectionId}-field-${fieldIndex}`,\n fieldName,\n sectionId,\n sectionTitle,\n required: Boolean(isRequired),\n schema: safeSchema,\n };\n });\n};\n\nconst sanitizeField = (\n field: ParameterFieldDisplay,\n fallbackSectionId: string,\n index: number\n): ParameterFieldDisplay => {\n const fieldId = field.id ?? `${fallbackSectionId}-field-${index}`;\n return {\n ...field,\n id: fieldId,\n sectionId: field.sectionId ?? fallbackSectionId,\n schema: cloneSchema(field.schema) ?? buildDefaultSchema(field.fieldName),\n };\n};\n\nconst sanitizeSection = (\n section: ParameterSectionDisplay,\n index: number\n): ParameterSectionDisplay => {\n const sectionId = section.id ?? `section-${index}`;\n const properties = asSchemaRecord(section.properties);\n const required = asStringArray(section.required);\n const fields =\n section.fields\n ?.map((field, idx) => sanitizeField(field, sectionId, idx))\n ?.filter(Boolean) ?? [];\n\n let safeFields = fields;\n if (!fields.length) {\n safeFields = buildFieldsForSection(\n sectionId,\n section.title,\n properties,\n required ?? []\n );\n }\n\n return {\n ...section,\n id: sectionId,\n properties: cloneProperties(properties),\n required: required ?? [],\n fields: safeFields,\n };\n};\n\nexport const sanitizeSections = (\n sections: ParameterSectionDisplay[]\n): ParameterSectionDisplay[] =>\n sections.map((section, index) => sanitizeSection(section, index));\n\nexport const normalizeParametersToSections = (\n parameters: TemplateParametersValue\n): ParameterSectionDisplay[] => {\n if (!Array.isArray(parameters)) {\n return [];\n }\n\n const unsafe = (parameters as TemplateParameterSchema[]).filter(\n (param) => param && typeof param === \"object\"\n );\n\n return unsafe.map((param, index) =>\n sanitizeSection(\n {\n id: (param as any).id ?? `section-${index}`,\n title: asString((param as any).title),\n description: asString((param as any).description),\n required: asStringArray((param as any).required),\n properties: asSchemaRecord((param as any).properties),\n fields: [],\n },\n index\n )\n );\n};\n\nexport const sectionsToParametersValue = (\n sections: ParameterSectionDisplay[] | undefined\n): TemplateParametersValue => {\n if (!sections) {\n return [];\n }\n\n const normalizedSections = sanitizeSections(sections);\n\n const result: TemplateParametersV1beta3[] = normalizedSections.map(\n (section, index) => {\n const properties =\n section.fields?.reduce<ParameterProperties>((acc, field) => {\n if (!field.fieldName) {\n return acc;\n }\n acc[field.fieldName] =\n cloneSchema(field.schema) ?? buildDefaultSchema(field.fieldName);\n return acc;\n }, {}) ?? {};\n\n const required =\n section.fields\n ?.filter((field) => field.required && field.fieldName)\n ?.map((field) => field.fieldName) ?? [];\n\n const defaultSectionTitle = `Section ${index + 1}`;\n\n return {\n id: section.id,\n title: section.title ?? defaultSectionTitle,\n description: section.description,\n properties: properties as unknown as Record<string, unknown>,\n required,\n } as TemplateParametersV1beta3;\n }\n );\n\n return result;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { stableStringify } from '../model.esm.js';
|
|
2
|
+
|
|
3
|
+
const positionsEqual = (a, b) => a?.x === b?.x && a?.y === b?.y;
|
|
4
|
+
const dimensionsEqual = (a, b) => (a.width ?? null) === (b.width ?? null) && (a.height ?? null) === (b.height ?? null);
|
|
5
|
+
const computeNodeHash = (node) => stableStringify({ type: node.type, data: node.data });
|
|
6
|
+
const computeEdgeHash = (edge) => stableStringify({
|
|
7
|
+
source: edge.source,
|
|
8
|
+
target: edge.target,
|
|
9
|
+
type: edge.type,
|
|
10
|
+
label: edge.label,
|
|
11
|
+
data: edge.data
|
|
12
|
+
});
|
|
13
|
+
const buildNodeHashMap = (nodes) => {
|
|
14
|
+
const next = {};
|
|
15
|
+
nodes.forEach((node) => {
|
|
16
|
+
next[node.id] = computeNodeHash(node);
|
|
17
|
+
});
|
|
18
|
+
return next;
|
|
19
|
+
};
|
|
20
|
+
const buildEdgeHashMap = (edges) => {
|
|
21
|
+
const next = {};
|
|
22
|
+
edges.forEach((edge) => {
|
|
23
|
+
next[edge.id] = computeEdgeHash(edge);
|
|
24
|
+
});
|
|
25
|
+
return next;
|
|
26
|
+
};
|
|
27
|
+
const mergeNodesWithStability = (prevNodes, nextNodes, hashRef) => {
|
|
28
|
+
const prevMap = new Map(prevNodes.map((node) => [node.id, node]));
|
|
29
|
+
const nextHashes = {};
|
|
30
|
+
let allStable = prevNodes.length === nextNodes.length;
|
|
31
|
+
const merged = nextNodes.map((node, index) => {
|
|
32
|
+
const prev = prevMap.get(node.id);
|
|
33
|
+
const nextHash = computeNodeHash(node);
|
|
34
|
+
nextHashes[node.id] = nextHash;
|
|
35
|
+
if (prev && hashRef.current[node.id] === nextHash && positionsEqual(prev.position, node.position) && dimensionsEqual(prev, node)) {
|
|
36
|
+
if (allStable && prevNodes[index] !== prev) {
|
|
37
|
+
allStable = false;
|
|
38
|
+
}
|
|
39
|
+
return prev;
|
|
40
|
+
}
|
|
41
|
+
allStable = false;
|
|
42
|
+
return node;
|
|
43
|
+
});
|
|
44
|
+
hashRef.current = nextHashes;
|
|
45
|
+
return allStable ? prevNodes : merged;
|
|
46
|
+
};
|
|
47
|
+
const mergeEdgesWithStability = (prevEdges, nextEdges, hashRef) => {
|
|
48
|
+
const prevMap = new Map(prevEdges.map((edge) => [edge.id, edge]));
|
|
49
|
+
const nextHashes = {};
|
|
50
|
+
let allStable = prevEdges.length === nextEdges.length;
|
|
51
|
+
const merged = nextEdges.map((edge, index) => {
|
|
52
|
+
const prev = prevMap.get(edge.id);
|
|
53
|
+
const nextHash = computeEdgeHash(edge);
|
|
54
|
+
nextHashes[edge.id] = nextHash;
|
|
55
|
+
if (prev && hashRef.current[edge.id] === nextHash) {
|
|
56
|
+
if (allStable && prevEdges[index] !== prev) {
|
|
57
|
+
allStable = false;
|
|
58
|
+
}
|
|
59
|
+
return prev;
|
|
60
|
+
}
|
|
61
|
+
allStable = false;
|
|
62
|
+
return edge;
|
|
63
|
+
});
|
|
64
|
+
hashRef.current = nextHashes;
|
|
65
|
+
return allStable ? prevEdges : merged;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export { buildEdgeHashMap, buildNodeHashMap, computeEdgeHash, computeNodeHash, mergeEdgesWithStability, mergeNodesWithStability };
|
|
69
|
+
//# sourceMappingURL=stableComparators.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stableComparators.esm.js","sources":["../../../src/designerFlow/utils/stableComparators.ts"],"sourcesContent":["import { Edge, Node, XYPosition } from \"@xyflow/react\";\nimport { stableStringify } from \"../model\";\n\ntype HashMap = Record<string, string>;\n\nconst positionsEqual = (a: XYPosition, b: XYPosition) =>\n a?.x === b?.x && a?.y === b?.y;\n\nconst dimensionsEqual = (a: Node, b: Node) =>\n (a.width ?? null) === (b.width ?? null) &&\n (a.height ?? null) === (b.height ?? null);\n\nexport const computeNodeHash = (node: Node) =>\n stableStringify({ type: node.type, data: node.data });\n\nexport const computeEdgeHash = (edge: Edge) =>\n stableStringify({\n source: edge.source,\n target: edge.target,\n type: edge.type,\n label: edge.label,\n data: edge.data,\n });\n\nexport const buildNodeHashMap = (nodes: Node[]): HashMap => {\n const next: HashMap = {};\n nodes.forEach((node) => {\n next[node.id] = computeNodeHash(node);\n });\n return next;\n};\n\nexport const buildEdgeHashMap = (edges: Edge[]): HashMap => {\n const next: HashMap = {};\n edges.forEach((edge) => {\n next[edge.id] = computeEdgeHash(edge);\n });\n return next;\n};\n\nexport const isNodeEqual = (a: Node, b: Node, prevHash: string | undefined) => {\n if (!a || !b) {\n return false;\n }\n const hashMatches = prevHash === computeNodeHash(b);\n return (\n a.type === b.type &&\n hashMatches &&\n positionsEqual(a.position, b.position) &&\n dimensionsEqual(a, b)\n );\n};\n\nexport const isEdgeEqual = (a: Edge, b: Edge, prevHash: string | undefined) => {\n if (!a || !b) {\n return false;\n }\n const hashMatches = prevHash === computeEdgeHash(b);\n return (\n a.source === b.source &&\n a.target === b.target &&\n a.type === b.type &&\n a.label === b.label &&\n hashMatches\n );\n};\n\nexport const mergeNodesWithStability = (\n prevNodes: Node[],\n nextNodes: Node[],\n hashRef: { current: HashMap }\n) => {\n const prevMap = new Map(prevNodes.map((node) => [node.id, node]));\n const nextHashes: HashMap = {};\n let allStable = prevNodes.length === nextNodes.length;\n\n const merged = nextNodes.map((node, index) => {\n const prev = prevMap.get(node.id);\n const nextHash = computeNodeHash(node);\n nextHashes[node.id] = nextHash;\n if (\n prev &&\n hashRef.current[node.id] === nextHash &&\n positionsEqual(prev.position, node.position) &&\n dimensionsEqual(prev, node)\n ) {\n if (allStable && prevNodes[index] !== prev) {\n allStable = false;\n }\n return prev;\n }\n allStable = false;\n return node;\n });\n\n hashRef.current = nextHashes;\n return allStable ? prevNodes : merged;\n};\n\nexport const mergeEdgesWithStability = (\n prevEdges: Edge[],\n nextEdges: Edge[],\n hashRef: { current: HashMap }\n) => {\n const prevMap = new Map(prevEdges.map((edge) => [edge.id, edge]));\n const nextHashes: HashMap = {};\n let allStable = prevEdges.length === nextEdges.length;\n\n const merged = nextEdges.map((edge, index) => {\n const prev = prevMap.get(edge.id);\n const nextHash = computeEdgeHash(edge);\n nextHashes[edge.id] = nextHash;\n if (prev && hashRef.current[edge.id] === nextHash) {\n if (allStable && prevEdges[index] !== prev) {\n allStable = false;\n }\n return prev;\n }\n allStable = false;\n return edge;\n });\n\n hashRef.current = nextHashes;\n return allStable ? prevEdges : merged;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class ActionNodeCustomizationRegistry {
|
|
2
|
+
schemaDecorators = [];
|
|
3
|
+
fieldsRenderer;
|
|
4
|
+
registerSchemaDecorator(decorator) {
|
|
5
|
+
this.schemaDecorators.push(decorator);
|
|
6
|
+
}
|
|
7
|
+
registerFieldsRenderer(renderer) {
|
|
8
|
+
this.fieldsRenderer = renderer;
|
|
9
|
+
}
|
|
10
|
+
getSchemaDecorators() {
|
|
11
|
+
return [...this.schemaDecorators];
|
|
12
|
+
}
|
|
13
|
+
getFieldsRenderer() {
|
|
14
|
+
return this.fieldsRenderer;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const actionNodeCustomizationRegistry = new ActionNodeCustomizationRegistry();
|
|
18
|
+
|
|
19
|
+
export { actionNodeCustomizationRegistry };
|
|
20
|
+
//# sourceMappingURL=actionNodeCustomization.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionNodeCustomization.esm.js","sources":["../../src/foundation/actionNodeCustomization.ts"],"sourcesContent":["import type { ComponentType } from \"react\";\nimport type { TaskStep } from \"@backstage/plugin-scaffolder-common\";\n\nexport type JsonSchemaProperty = Record<string, unknown>;\n\nexport type ActionSchemaDecorator = (options: {\n actionId: string;\n step: TaskStep;\n schema: Record<string, JsonSchemaProperty>;\n}) => Record<string, JsonSchemaProperty>;\n\nexport type ActionFieldsRendererProps = {\n actionId: string;\n step: TaskStep;\n input?: Record<string, unknown>;\n schema: Record<string, JsonSchemaProperty>;\n onUpdateInput: (key: string, value: unknown) => void;\n};\n\nexport type ActionFieldsRenderer = ComponentType<ActionFieldsRendererProps>;\n\n/**\n * Simple singleton registry used by the Action node to apply schema tweaks\n * and render optional custom UI from downstream packages (e.g. PRO).\n */\nclass ActionNodeCustomizationRegistry {\n private schemaDecorators: ActionSchemaDecorator[] = [];\n private fieldsRenderer: ActionFieldsRenderer | undefined;\n\n registerSchemaDecorator(decorator: ActionSchemaDecorator) {\n this.schemaDecorators.push(decorator);\n }\n\n registerFieldsRenderer(renderer: ActionFieldsRenderer) {\n this.fieldsRenderer = renderer;\n }\n\n getSchemaDecorators() {\n return [...this.schemaDecorators];\n }\n\n getFieldsRenderer(): ActionFieldsRenderer | undefined {\n return this.fieldsRenderer;\n }\n}\n\nexport const actionNodeCustomizationRegistry =\n new ActionNodeCustomizationRegistry();\n"],"names":[],"mappings":"AAyBA,MAAM,+BAAA,CAAgC;AAAA,EAC5B,mBAA4C,EAAC;AAAA,EAC7C,cAAA;AAAA,EAER,wBAAwB,SAAA,EAAkC;AACxD,IAAA,IAAA,CAAK,gBAAA,CAAiB,KAAK,SAAS,CAAA;AAAA,EACtC;AAAA,EAEA,uBAAuB,QAAA,EAAgC;AACrD,IAAA,IAAA,CAAK,cAAA,GAAiB,QAAA;AAAA,EACxB;AAAA,EAEA,mBAAA,GAAsB;AACpB,IAAA,OAAO,CAAC,GAAG,IAAA,CAAK,gBAAgB,CAAA;AAAA,EAClC;AAAA,EAEA,iBAAA,GAAsD;AACpD,IAAA,OAAO,IAAA,CAAK,cAAA;AAAA,EACd;AACF;AAEO,MAAM,+BAAA,GACX,IAAI,+BAAA;;;;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class ActionNodeRegistry {
|
|
2
|
+
nodes = /* @__PURE__ */ new Map();
|
|
3
|
+
/**
|
|
4
|
+
* Register a new action node renderer. Locked nodes cannot be overridden.
|
|
5
|
+
*/
|
|
6
|
+
register(id, component, options = {}) {
|
|
7
|
+
const existing = this.nodes.get(id);
|
|
8
|
+
if (existing?.locked) {
|
|
9
|
+
throw new Error(`Action node '${id}' is locked and cannot be overridden`);
|
|
10
|
+
}
|
|
11
|
+
if (existing && options.locked) {
|
|
12
|
+
throw new Error(`Action node '${id}' is already registered`);
|
|
13
|
+
}
|
|
14
|
+
this.nodes.set(id, {
|
|
15
|
+
id,
|
|
16
|
+
component,
|
|
17
|
+
locked: Boolean(options.locked)
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
get(id) {
|
|
21
|
+
return this.nodes.get(id)?.component;
|
|
22
|
+
}
|
|
23
|
+
list() {
|
|
24
|
+
return Array.from(this.nodes.values());
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const actionNodeRegistry = new ActionNodeRegistry();
|
|
28
|
+
|
|
29
|
+
export { ActionNodeRegistry, actionNodeRegistry };
|
|
30
|
+
//# sourceMappingURL=actionNodeRegistry.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionNodeRegistry.esm.js","sources":["../../src/foundation/actionNodeRegistry.ts"],"sourcesContent":["import type { ComponentType } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { RegisteredActionNode } from \"./types\";\n\nexport class ActionNodeRegistry {\n private readonly nodes = new Map<string, RegisteredActionNode>();\n\n /**\n * Register a new action node renderer. Locked nodes cannot be overridden.\n */\n register(\n id: string,\n component: ComponentType<NodeProps>,\n options: { locked?: boolean } = {}\n ) {\n const existing = this.nodes.get(id);\n if (existing?.locked) {\n throw new Error(`Action node '${id}' is locked and cannot be overridden`);\n }\n if (existing && options.locked) {\n throw new Error(`Action node '${id}' is already registered`);\n }\n\n this.nodes.set(id, {\n id,\n component,\n locked: Boolean(options.locked),\n });\n }\n\n get(id: string): ComponentType<NodeProps> | undefined {\n return this.nodes.get(id)?.component;\n }\n\n list(): RegisteredActionNode[] {\n return Array.from(this.nodes.values());\n }\n}\n\n/**\n * Shared registry instance to keep the common action nodes \"final\".\n * PRO can append new nodes by registering under a different id.\n */\nexport const actionNodeRegistry = new ActionNodeRegistry();\n"],"names":[],"mappings":"AAIO,MAAM,kBAAA,CAAmB;AAAA,EACb,KAAA,uBAAY,GAAA,EAAkC;AAAA;AAAA;AAAA;AAAA,EAK/D,QAAA,CACE,EAAA,EACA,SAAA,EACA,OAAA,GAAgC,EAAC,EACjC;AACA,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA;AAClC,IAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,aAAA,EAAgB,EAAE,CAAA,oCAAA,CAAsC,CAAA;AAAA,IAC1E;AACA,IAAA,IAAI,QAAA,IAAY,QAAQ,MAAA,EAAQ;AAC9B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,aAAA,EAAgB,EAAE,CAAA,uBAAA,CAAyB,CAAA;AAAA,IAC7D;AAEA,IAAA,IAAA,CAAK,KAAA,CAAM,IAAI,EAAA,EAAI;AAAA,MACjB,EAAA;AAAA,MACA,SAAA;AAAA,MACA,MAAA,EAAQ,OAAA,CAAQ,OAAA,CAAQ,MAAM;AAAA,KAC/B,CAAA;AAAA,EACH;AAAA,EAEA,IAAI,EAAA,EAAkD;AACpD,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,EAAG,SAAA;AAAA,EAC7B;AAAA,EAEA,IAAA,GAA+B;AAC7B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AAAA,EACvC;AACF;AAMO,MAAM,kBAAA,GAAqB,IAAI,kBAAA;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"featureFlags.esm.js","sources":["../../src/foundation/featureFlags.ts"],"sourcesContent":["import type { FeatureFlagClient } from \"./types\";\n\n/**\n * Default flag client used by OSS; PRO can swap for a richer provider.\n */\nexport const noopFeatureFlags: FeatureFlagClient = {\n isEnabled: () => false,\n};\n"],"names":[],"mappings":"AAKO,MAAM,gBAAA,GAAsC;AAAA,EACjD,WAAW,MAAM;AACnB;;;;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class TemplateSourceRegistry {
|
|
2
|
+
providers = /* @__PURE__ */ new Map();
|
|
3
|
+
register(provider) {
|
|
4
|
+
if (this.providers.has(provider.id)) {
|
|
5
|
+
throw new Error(`Template source '${provider.id}' already registered`);
|
|
6
|
+
}
|
|
7
|
+
this.providers.set(provider.id, provider);
|
|
8
|
+
}
|
|
9
|
+
list() {
|
|
10
|
+
return Array.from(this.providers.values());
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const templateSourceRegistry = new TemplateSourceRegistry();
|
|
14
|
+
|
|
15
|
+
export { templateSourceRegistry };
|
|
16
|
+
//# sourceMappingURL=templateSources.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templateSources.esm.js","sources":["../../src/foundation/templateSources.ts"],"sourcesContent":["import type { TemplateSourceProvider } from \"./types\";\n\nclass TemplateSourceRegistry {\n private readonly providers = new Map<string, TemplateSourceProvider>();\n\n register(provider: TemplateSourceProvider) {\n if (this.providers.has(provider.id)) {\n throw new Error(`Template source '${provider.id}' already registered`);\n }\n this.providers.set(provider.id, provider);\n }\n\n list(): TemplateSourceProvider[] {\n return Array.from(this.providers.values());\n }\n}\n\n/**\n * Registry that lets OSS and PRO expose additional template pickers\n * (catalog, git, SaaS, etc.) without changing the core UI.\n */\nexport const templateSourceRegistry = new TemplateSourceRegistry();\n"],"names":[],"mappings":"AAEA,MAAM,sBAAA,CAAuB;AAAA,EACV,SAAA,uBAAgB,GAAA,EAAoC;AAAA,EAErE,SAAS,QAAA,EAAkC;AACzC,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,EAAE,CAAA,EAAG;AACnC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,QAAA,CAAS,EAAE,CAAA,oBAAA,CAAsB,CAAA;AAAA,IACvE;AACA,IAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,QAAQ,CAAA;AAAA,EAC1C;AAAA,EAEA,IAAA,GAAiC;AAC/B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA;AAAA,EAC3C;AACF;AAMO,MAAM,sBAAA,GAAyB,IAAI,sBAAA;;;;"}
|