@notmrabhi/flowforge 0.1.35 → 0.1.37

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/dist/canvas.d.ts CHANGED
@@ -24,6 +24,38 @@ export declare interface AddStepContext {
24
24
  branch?: string;
25
25
  }
26
26
 
27
+ /**
28
+ * Wire shape the backend `/api/v1/workflow-template` endpoint is expected
29
+ * to return. Top-level fields mirror the persistence model; everything
30
+ * UI-related lives under `templateUI`. Use with `templateRegistry.registerFromApi(list)`.
31
+ */
32
+ export declare interface ApiWorkflowTemplate {
33
+ key: string;
34
+ name: string;
35
+ state?: string;
36
+ description?: string;
37
+ allowedTasks?: string[];
38
+ allowedSources?: string[];
39
+ configuration?: Record<string, unknown>;
40
+ templateUI?: Partial<Omit<WorkflowTemplate, 'triggerKey' | 'label' | 'description' | 'availableTasks'>>;
41
+ }
42
+
43
+ /**
44
+ * Wire shape the backend `/api/v1/workflow-template` endpoint is expected
45
+ * to return. Top-level fields mirror the persistence model; everything
46
+ * UI-related lives under `templateUI`. Use with `templateRegistry.registerFromApi(list)`.
47
+ */
48
+ declare interface ApiWorkflowTemplate_2 {
49
+ key: string;
50
+ name: string;
51
+ state?: string;
52
+ description?: string;
53
+ allowedTasks?: string[];
54
+ allowedSources?: string[];
55
+ configuration?: Record<string, unknown>;
56
+ templateUI?: Partial<Omit<WorkflowTemplate_3, 'triggerKey' | 'label' | 'description' | 'availableTasks'>>;
57
+ }
58
+
27
59
  export declare const ApprovalNode: ({ id, data }: NodeProps) => JSX_2.Element;
28
60
 
29
61
  export declare interface BpmnElement {
@@ -727,13 +759,40 @@ declare interface SubWorkflowPreviewDrawerProps {
727
759
 
728
760
  declare class TemplateRegistry {
729
761
  private templates;
762
+ /**
763
+ * Register a template. Normalises `allowedTasks` (the backend's name) →
764
+ * `availableTasks` (FlowForge's canonical name) so consumers can pass
765
+ * either without rewriting.
766
+ */
730
767
  register(template: WorkflowTemplate_3): this;
768
+ /**
769
+ * Register a list of templates fetched from `GET /api/v1/workflow-template`.
770
+ *
771
+ * The API shape is:
772
+ * {
773
+ * key, name, description, allowedTasks, allowedSources,
774
+ * configuration, // runtime BPMN — ignored by the canvas
775
+ * templateUI: { // ← UI bag, spread onto the template
776
+ * triggerCategory, icon, tags, category, author, popularity,
777
+ * source, product, taskLabels, maxTasks, skeletonState, …
778
+ * }
779
+ * }
780
+ *
781
+ * Anything in `templateUI` overrides the top-level shorthand where there's
782
+ * an overlap. Bad rows (missing `key`) are skipped with a DEV warning
783
+ * rather than throwing, so one broken template doesn't blank the picker.
784
+ *
785
+ * Returns `this` for chaining and the count of templates registered.
786
+ */
787
+ registerFromApi(list: ApiWorkflowTemplate_2[]): this;
731
788
  lookup(triggerKey: string): WorkflowTemplate_3 | undefined;
732
789
  list(): WorkflowTemplate_3[];
733
790
  listByCategory(category: string): WorkflowTemplate_3[];
734
791
  listByTag(tag: string): WorkflowTemplate_3[];
735
792
  search(query: string): WorkflowTemplate_3[];
736
793
  categories(): string[];
794
+ /** Remove every template — useful before re-loading from backend. */
795
+ clear(): this;
737
796
  }
738
797
 
739
798
  export declare const TriggerNode: ({ data }: NodeProps) => JSX_2.Element;
@@ -776,7 +835,13 @@ export declare interface WorkflowTemplate {
776
835
  description?: string;
777
836
  icon?: ReactNode;
778
837
  triggerCategory?: 'event' | 'scheduler' | 'webhook' | string;
838
+ /**
839
+ * Task IDs (descriptor types) that can be inserted into this workflow.
840
+ * `allowedTasks` is accepted as an alias for backend payloads that use
841
+ * that name — TemplateRegistry.register() normalises them.
842
+ */
779
843
  availableTasks?: string[];
844
+ allowedTasks?: string[];
780
845
  maxTasks?: number;
781
846
  taskLabels?: Record<string, string>;
782
847
  fixedNodes?: FixedNode_3[];
@@ -802,7 +867,13 @@ declare interface WorkflowTemplate_2 {
802
867
  description?: string;
803
868
  icon?: ReactNode;
804
869
  triggerCategory?: 'event' | 'scheduler' | 'webhook' | string;
870
+ /**
871
+ * Task IDs (descriptor types) that can be inserted into this workflow.
872
+ * `allowedTasks` is accepted as an alias for backend payloads that use
873
+ * that name — TemplateRegistry.register() normalises them.
874
+ */
805
875
  availableTasks?: string[];
876
+ allowedTasks?: string[];
806
877
  maxTasks?: number;
807
878
  taskLabels?: Record<string, string>;
808
879
  fixedNodes?: FixedNode[];
@@ -828,7 +899,13 @@ declare interface WorkflowTemplate_3 {
828
899
  description?: string;
829
900
  icon?: ReactNode;
830
901
  triggerCategory?: 'event' | 'scheduler' | 'webhook' | string;
902
+ /**
903
+ * Task IDs (descriptor types) that can be inserted into this workflow.
904
+ * `allowedTasks` is accepted as an alias for backend payloads that use
905
+ * that name — TemplateRegistry.register() normalises them.
906
+ */
831
907
  availableTasks?: string[];
908
+ allowedTasks?: string[];
832
909
  maxTasks?: number;
833
910
  taskLabels?: Record<string, string>;
834
911
  fixedNodes?: FixedNode_2[];
package/dist/canvas.js CHANGED
@@ -1,7 +1,7 @@
1
- import { F as a, S as s, F as r, W as t, a as l, b as n, o as d, u as i, w as f } from "./templateSkeletons-DCvfog6-.js";
1
+ import { F as a, S as s, F as r, W as t, a as l, b as n, o as d, u as i, w as f } from "./templateSkeletons-BB6jQ9r5.js";
2
2
  import { d as w } from "./messages-CO299wPN.js";
3
3
  import { l as p, s as b } from "./bpmn-CtfWDaOY.js";
4
- import { A as F, b as N, E as m, c as u, F as S, R as T, S as c, T as v, W as x, e as A } from "./GatewayBranchEdge-Dxoy5B1A.js";
4
+ import { A as F, b as N, E as m, c as u, F as S, R as T, S as c, T as v, W as x, e as A } from "./GatewayBranchEdge-Diid9GtB.js";
5
5
  export {
6
6
  F as ActionNode,
7
7
  N as ApprovalNode,
package/dist/core.d.ts CHANGED
@@ -1,6 +1,22 @@
1
1
  import { AnySchema } from 'yup';
2
2
  import { ReactNode } from 'react';
3
3
 
4
+ /**
5
+ * Wire shape the backend `/api/v1/workflow-template` endpoint is expected
6
+ * to return. Top-level fields mirror the persistence model; everything
7
+ * UI-related lives under `templateUI`. Use with `templateRegistry.registerFromApi(list)`.
8
+ */
9
+ export declare interface ApiWorkflowTemplate {
10
+ key: string;
11
+ name: string;
12
+ state?: string;
13
+ description?: string;
14
+ allowedTasks?: string[];
15
+ allowedSources?: string[];
16
+ configuration?: Record<string, unknown>;
17
+ templateUI?: Partial<Omit<WorkflowTemplate, 'triggerKey' | 'label' | 'description' | 'availableTasks'>>;
18
+ }
19
+
4
20
  /**
5
21
  * Base defaults shared by every node descriptor. A new node only has to specify
6
22
  * what makes it different — these fill in the rest.
@@ -350,13 +366,40 @@ export declare interface SubWorkflowDescriptorOptions {
350
366
 
351
367
  export declare class TemplateRegistry {
352
368
  private templates;
369
+ /**
370
+ * Register a template. Normalises `allowedTasks` (the backend's name) →
371
+ * `availableTasks` (FlowForge's canonical name) so consumers can pass
372
+ * either without rewriting.
373
+ */
353
374
  register(template: WorkflowTemplate): this;
375
+ /**
376
+ * Register a list of templates fetched from `GET /api/v1/workflow-template`.
377
+ *
378
+ * The API shape is:
379
+ * {
380
+ * key, name, description, allowedTasks, allowedSources,
381
+ * configuration, // runtime BPMN — ignored by the canvas
382
+ * templateUI: { // ← UI bag, spread onto the template
383
+ * triggerCategory, icon, tags, category, author, popularity,
384
+ * source, product, taskLabels, maxTasks, skeletonState, …
385
+ * }
386
+ * }
387
+ *
388
+ * Anything in `templateUI` overrides the top-level shorthand where there's
389
+ * an overlap. Bad rows (missing `key`) are skipped with a DEV warning
390
+ * rather than throwing, so one broken template doesn't blank the picker.
391
+ *
392
+ * Returns `this` for chaining and the count of templates registered.
393
+ */
394
+ registerFromApi(list: ApiWorkflowTemplate[]): this;
354
395
  lookup(triggerKey: string): WorkflowTemplate | undefined;
355
396
  list(): WorkflowTemplate[];
356
397
  listByCategory(category: string): WorkflowTemplate[];
357
398
  listByTag(tag: string): WorkflowTemplate[];
358
399
  search(query: string): WorkflowTemplate[];
359
400
  categories(): string[];
401
+ /** Remove every template — useful before re-loading from backend. */
402
+ clear(): this;
360
403
  }
361
404
 
362
405
  export declare const templateRegistry: TemplateRegistry;
@@ -376,7 +419,13 @@ export declare interface WorkflowTemplate {
376
419
  description?: string;
377
420
  icon?: ReactNode;
378
421
  triggerCategory?: 'event' | 'scheduler' | 'webhook' | string;
422
+ /**
423
+ * Task IDs (descriptor types) that can be inserted into this workflow.
424
+ * `allowedTasks` is accepted as an alias for backend payloads that use
425
+ * that name — TemplateRegistry.register() normalises them.
426
+ */
379
427
  availableTasks?: string[];
428
+ allowedTasks?: string[];
380
429
  maxTasks?: number;
381
430
  taskLabels?: Record<string, string>;
382
431
  fixedNodes?: FixedNode[];
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./GatewayBranchEdge-9YF32wwN.js");exports.ActionNode=e.ActionNode;exports.AddTriggerNode=e.AddTriggerNode;exports.ApprovalNode=e.ApprovalNode;exports.DelayNode=e.DelayNode;exports.EdgeWithPlusLabel=e.EdgeWithPlusLabel;exports.EndNode=e.EndNode;exports.FilterNode=e.FilterNode;exports.GatewayBranchEdge=e.GatewayBranchEdge;exports.LabelPlusEdge=e.LabelPlusEdge;exports.NotificationNode=e.NotificationNode;exports.PlainEdge=e.PlainEdge;exports.PlusEdge=e.PlusEdge;exports.StartNode=e.StartNode;exports.TriggerNode=e.TriggerNode;exports.builtInNodeTypes=e.builtInNodeTypes;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./GatewayBranchEdge-DNSPjIZw.js");exports.ActionNode=e.ActionNode;exports.AddTriggerNode=e.AddTriggerNode;exports.ApprovalNode=e.ApprovalNode;exports.DelayNode=e.DelayNode;exports.EdgeWithPlusLabel=e.EdgeWithPlusLabel;exports.EndNode=e.EndNode;exports.FilterNode=e.FilterNode;exports.GatewayBranchEdge=e.GatewayBranchEdge;exports.LabelPlusEdge=e.LabelPlusEdge;exports.NotificationNode=e.NotificationNode;exports.PlainEdge=e.PlainEdge;exports.PlusEdge=e.PlusEdge;exports.StartNode=e.StartNode;exports.TriggerNode=e.TriggerNode;exports.builtInNodeTypes=e.builtInNodeTypes;
2
2
  //# sourceMappingURL=defaultUi.cjs.map
package/dist/defaultUi.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as d, a as s, b as o, D as N, E as i, c as l, F as r, G as t, L as g, N as E, P as n, d as P, S as b, T as c, e as p } from "./GatewayBranchEdge-Dxoy5B1A.js";
1
+ import { A as d, a as s, b as o, D as N, E as i, c as l, F as r, G as t, L as g, N as E, P as n, d as P, S as b, T as c, e as p } from "./GatewayBranchEdge-Diid9GtB.js";
2
2
  export {
3
3
  d as ActionNode,
4
4
  s as AddTriggerNode,
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-CqMPyOkL.js"),a=require("./SchemaBuilderDrawer-CiSdfXzJ.js");require("react/jsx-runtime");require("react");require("@mui/material");require("react-icons/md");const r=require("./nodeRegistry.cjs"),l=require("./templateRegistry.cjs"),i=require("./templateSkeletons-BTC2fk5u.js"),d=require("./messages-O9Tw_XXR.js"),n=require("./bpmn-CcuE2X_Q.js"),o=require("./GatewayBranchEdge-9YF32wwN.js");class u{constructor(){this.channels=new Map}register(t,s){this.channels.set(t,s)}get(t){return this.channels.get(t)}list(){return Array.from(this.channels.entries()).map(([t,s])=>({key:t,...s}))}has(t){return this.channels.has(t)}}const c=new u;exports.DynamicFormRenderer=e.DynamicFormRenderer;exports.FF=e.FF;exports.FlowForgeRegistry=e.FlowForgeRegistry;exports.FlowForm=e.FlowForm;exports.FormulaInput=e.FormulaInput;exports.InfiniteSelectField=e.InfiniteSelectField;exports.TablePickerField=e.TablePickerField;exports.VariablePicker=e.VariablePicker;exports.VariablePickerProvider=e.VariablePickerProvider;exports.astHasRefs=e.astHasRefs;exports.astToTokens=e.astToTokens;exports.buildEvaluationPayload=e.buildEvaluationPayload;exports.buildFieldConfig=e.buildFieldConfig;exports.buildFormulaPath=e.buildFormulaPath;exports.buildSelectStyles=e.buildSelectStyles;exports.buildValidationSchema=e.buildValidationSchema;exports.dataSourceRegistry=e.dataSourceRegistry;exports.errorTextStyle=e.errorTextStyle;exports.extractLabel=e.extractLabel;exports.fieldRegistry=e.fieldRegistry;exports.hasFormulaTokens=e.hasFormulaTokens;exports.helperTextStyle=e.helperTextStyle;exports.inputStyle=e.inputStyle;exports.isFormula=e.isFormula;exports.parseToAST=e.parseToAST;exports.serializeAST=e.serializeAST;exports.serializeASTAsConfig=e.serializeASTAsConfig;exports.serializeConditionExpressions=e.serializeConditionExpressions;exports.stripFormulaTokens=e.stripFormulaTokens;exports.tokenize=e.tokenize;exports.unwrapFormula=e.unwrapFormula;exports.useVariablePickerContext=e.useVariablePickerContext;exports.wrapFormula=e.wrapFormula;exports.FIELD_TYPE_OPTIONS=a.FIELD_TYPE_OPTIONS;exports.SchemaBuilder=a.SchemaBuilder;exports.SchemaBuilderDrawer=a.SchemaBuilderDrawer;exports.useFlowForm=a.useFlowForm;exports.NodeTypeRegistry=r.NodeTypeRegistry;exports.baseNodeDefaults=r.baseNodeDefaults;exports.conditionBranchDescriptor=r.conditionBranchDescriptor;exports.defineNode=r.defineNode;exports.endEventDescriptor=r.endEventDescriptor;exports.makeSubWorkflowDescriptor=r.makeSubWorkflowDescriptor;exports.nodeTypeRegistry=r.nodeTypeRegistry;exports.notificationDescriptor=r.notificationDescriptor;exports.restApiDescriptor=r.restApiDescriptor;exports.startEventDescriptor=r.startEventDescriptor;exports.subWorkflowDescriptor=r.subWorkflowDescriptor;exports.webhookTriggerDescriptor=r.webhookTriggerDescriptor;exports.webhookTriggerTemplate=r.webhookTriggerTemplate;exports.TemplateRegistry=l.TemplateRegistry;exports.templateRegistry=l.templateRegistry;exports.FlowForgeCanvas=i.FlowForgeCanvas;exports.SubWorkflowPreviewDrawer=i.SubWorkflowPreviewDrawer;exports.WorkflowCanvas=i.FlowForgeCanvas;exports.WorkflowExecutionHistory=i.WorkflowExecutionHistory;exports.WorkflowTemplateLibrary=i.WorkflowTemplateLibrary;exports.accessRequestSkeleton=i.accessRequestSkeleton;exports.offboardingSkeleton=i.offboardingSkeleton;exports.userOnboardingSkeleton=i.userOnboardingSkeleton;exports.webhookIntegrationSkeleton=i.webhookIntegrationSkeleton;exports.defaultFlowForgeMessages=d.defaultFlowForgeMessages;exports.loadWorkflowFromBpmn=n.loadWorkflowFromBpmn;exports.saveWorkflowToBpmn=n.saveWorkflowToBpmn;exports.ActionNode=o.ActionNode;exports.ApprovalNode=o.ApprovalNode;exports.EdgeWithPlusLabel=o.EdgeWithPlusLabel;exports.EndNode=o.EndNode;exports.FilterNode=o.FilterNode;exports.RestApiNode=o.RestApiNode;exports.StartNode=o.StartNode;exports.TriggerNode=o.TriggerNode;exports.WebhookTriggerNode=o.WebhookTriggerNode;exports.builtInNodeTypes=o.builtInNodeTypes;exports.notificationChannelRegistry=c;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-CqMPyOkL.js"),a=require("./SchemaBuilderDrawer-CiSdfXzJ.js");require("react/jsx-runtime");require("react");require("@mui/material");require("react-icons/md");const r=require("./nodeRegistry.cjs"),l=require("./templateRegistry.cjs"),i=require("./templateSkeletons-BkdRPbV0.js"),d=require("./messages-O9Tw_XXR.js"),n=require("./bpmn-CcuE2X_Q.js"),o=require("./GatewayBranchEdge-DNSPjIZw.js");class u{constructor(){this.channels=new Map}register(t,s){this.channels.set(t,s)}get(t){return this.channels.get(t)}list(){return Array.from(this.channels.entries()).map(([t,s])=>({key:t,...s}))}has(t){return this.channels.has(t)}}const c=new u;exports.DynamicFormRenderer=e.DynamicFormRenderer;exports.FF=e.FF;exports.FlowForgeRegistry=e.FlowForgeRegistry;exports.FlowForm=e.FlowForm;exports.FormulaInput=e.FormulaInput;exports.InfiniteSelectField=e.InfiniteSelectField;exports.TablePickerField=e.TablePickerField;exports.VariablePicker=e.VariablePicker;exports.VariablePickerProvider=e.VariablePickerProvider;exports.astHasRefs=e.astHasRefs;exports.astToTokens=e.astToTokens;exports.buildEvaluationPayload=e.buildEvaluationPayload;exports.buildFieldConfig=e.buildFieldConfig;exports.buildFormulaPath=e.buildFormulaPath;exports.buildSelectStyles=e.buildSelectStyles;exports.buildValidationSchema=e.buildValidationSchema;exports.dataSourceRegistry=e.dataSourceRegistry;exports.errorTextStyle=e.errorTextStyle;exports.extractLabel=e.extractLabel;exports.fieldRegistry=e.fieldRegistry;exports.hasFormulaTokens=e.hasFormulaTokens;exports.helperTextStyle=e.helperTextStyle;exports.inputStyle=e.inputStyle;exports.isFormula=e.isFormula;exports.parseToAST=e.parseToAST;exports.serializeAST=e.serializeAST;exports.serializeASTAsConfig=e.serializeASTAsConfig;exports.serializeConditionExpressions=e.serializeConditionExpressions;exports.stripFormulaTokens=e.stripFormulaTokens;exports.tokenize=e.tokenize;exports.unwrapFormula=e.unwrapFormula;exports.useVariablePickerContext=e.useVariablePickerContext;exports.wrapFormula=e.wrapFormula;exports.FIELD_TYPE_OPTIONS=a.FIELD_TYPE_OPTIONS;exports.SchemaBuilder=a.SchemaBuilder;exports.SchemaBuilderDrawer=a.SchemaBuilderDrawer;exports.useFlowForm=a.useFlowForm;exports.NodeTypeRegistry=r.NodeTypeRegistry;exports.baseNodeDefaults=r.baseNodeDefaults;exports.conditionBranchDescriptor=r.conditionBranchDescriptor;exports.defineNode=r.defineNode;exports.endEventDescriptor=r.endEventDescriptor;exports.makeSubWorkflowDescriptor=r.makeSubWorkflowDescriptor;exports.nodeTypeRegistry=r.nodeTypeRegistry;exports.notificationDescriptor=r.notificationDescriptor;exports.restApiDescriptor=r.restApiDescriptor;exports.startEventDescriptor=r.startEventDescriptor;exports.subWorkflowDescriptor=r.subWorkflowDescriptor;exports.webhookTriggerDescriptor=r.webhookTriggerDescriptor;exports.webhookTriggerTemplate=r.webhookTriggerTemplate;exports.TemplateRegistry=l.TemplateRegistry;exports.templateRegistry=l.templateRegistry;exports.FlowForgeCanvas=i.FlowForgeCanvas;exports.SubWorkflowPreviewDrawer=i.SubWorkflowPreviewDrawer;exports.WorkflowCanvas=i.FlowForgeCanvas;exports.WorkflowExecutionHistory=i.WorkflowExecutionHistory;exports.WorkflowTemplateLibrary=i.WorkflowTemplateLibrary;exports.accessRequestSkeleton=i.accessRequestSkeleton;exports.offboardingSkeleton=i.offboardingSkeleton;exports.userOnboardingSkeleton=i.userOnboardingSkeleton;exports.webhookIntegrationSkeleton=i.webhookIntegrationSkeleton;exports.defaultFlowForgeMessages=d.defaultFlowForgeMessages;exports.loadWorkflowFromBpmn=n.loadWorkflowFromBpmn;exports.saveWorkflowToBpmn=n.saveWorkflowToBpmn;exports.ActionNode=o.ActionNode;exports.ApprovalNode=o.ApprovalNode;exports.EdgeWithPlusLabel=o.EdgeWithPlusLabel;exports.EndNode=o.EndNode;exports.FilterNode=o.FilterNode;exports.RestApiNode=o.RestApiNode;exports.StartNode=o.StartNode;exports.TriggerNode=o.TriggerNode;exports.WebhookTriggerNode=o.WebhookTriggerNode;exports.builtInNodeTypes=o.builtInNodeTypes;exports.notificationChannelRegistry=c;
2
2
  //# sourceMappingURL=index.cjs.map
package/dist/index.d.ts CHANGED
@@ -41,6 +41,22 @@ export declare interface AddStepContext {
41
41
  branch?: string;
42
42
  }
43
43
 
44
+ /**
45
+ * Wire shape the backend `/api/v1/workflow-template` endpoint is expected
46
+ * to return. Top-level fields mirror the persistence model; everything
47
+ * UI-related lives under `templateUI`. Use with `templateRegistry.registerFromApi(list)`.
48
+ */
49
+ export declare interface ApiWorkflowTemplate {
50
+ key: string;
51
+ name: string;
52
+ state?: string;
53
+ description?: string;
54
+ allowedTasks?: string[];
55
+ allowedSources?: string[];
56
+ configuration?: Record<string, unknown>;
57
+ templateUI?: Partial<Omit<WorkflowTemplate, 'triggerKey' | 'label' | 'description' | 'availableTasks'>>;
58
+ }
59
+
44
60
  export declare const ApprovalNode: ({ id, data }: NodeProps) => JSX_2.Element;
45
61
 
46
62
  /** True if the AST contains at least one non-text node. */
@@ -1290,13 +1306,40 @@ export declare interface TabsFieldDescriptor extends FieldDescriptor {
1290
1306
 
1291
1307
  export declare class TemplateRegistry {
1292
1308
  private templates;
1309
+ /**
1310
+ * Register a template. Normalises `allowedTasks` (the backend's name) →
1311
+ * `availableTasks` (FlowForge's canonical name) so consumers can pass
1312
+ * either without rewriting.
1313
+ */
1293
1314
  register(template: WorkflowTemplate): this;
1315
+ /**
1316
+ * Register a list of templates fetched from `GET /api/v1/workflow-template`.
1317
+ *
1318
+ * The API shape is:
1319
+ * {
1320
+ * key, name, description, allowedTasks, allowedSources,
1321
+ * configuration, // runtime BPMN — ignored by the canvas
1322
+ * templateUI: { // ← UI bag, spread onto the template
1323
+ * triggerCategory, icon, tags, category, author, popularity,
1324
+ * source, product, taskLabels, maxTasks, skeletonState, …
1325
+ * }
1326
+ * }
1327
+ *
1328
+ * Anything in `templateUI` overrides the top-level shorthand where there's
1329
+ * an overlap. Bad rows (missing `key`) are skipped with a DEV warning
1330
+ * rather than throwing, so one broken template doesn't blank the picker.
1331
+ *
1332
+ * Returns `this` for chaining and the count of templates registered.
1333
+ */
1334
+ registerFromApi(list: ApiWorkflowTemplate[]): this;
1294
1335
  lookup(triggerKey: string): WorkflowTemplate | undefined;
1295
1336
  list(): WorkflowTemplate[];
1296
1337
  listByCategory(category: string): WorkflowTemplate[];
1297
1338
  listByTag(tag: string): WorkflowTemplate[];
1298
1339
  search(query: string): WorkflowTemplate[];
1299
1340
  categories(): string[];
1341
+ /** Remove every template — useful before re-loading from backend. */
1342
+ clear(): this;
1300
1343
  }
1301
1344
 
1302
1345
  export declare const templateRegistry: TemplateRegistry;
@@ -1468,7 +1511,13 @@ export declare interface WorkflowTemplate {
1468
1511
  description?: string;
1469
1512
  icon?: ReactNode;
1470
1513
  triggerCategory?: 'event' | 'scheduler' | 'webhook' | string;
1514
+ /**
1515
+ * Task IDs (descriptor types) that can be inserted into this workflow.
1516
+ * `allowedTasks` is accepted as an alias for backend payloads that use
1517
+ * that name — TemplateRegistry.register() normalises them.
1518
+ */
1471
1519
  availableTasks?: string[];
1520
+ allowedTasks?: string[];
1472
1521
  maxTasks?: number;
1473
1522
  taskLabels?: Record<string, string>;
1474
1523
  fixedNodes?: FixedNode[];
package/dist/index.js CHANGED
@@ -6,10 +6,10 @@ import "@mui/material";
6
6
  import "react-icons/md";
7
7
  import { NodeTypeRegistry as U, baseNodeDefaults as X, conditionBranchDescriptor as Z, defineNode as $, endEventDescriptor as ee, makeSubWorkflowDescriptor as ae, nodeTypeRegistry as se, notificationDescriptor as re, restApiDescriptor as oe, startEventDescriptor as te, subWorkflowDescriptor as ie, webhookTriggerDescriptor as le, webhookTriggerTemplate as ne } from "./nodeRegistry.js";
8
8
  import { TemplateRegistry as de, templateRegistry as ce } from "./templateRegistry.js";
9
- import { F as me, S as fe, F as ge, W as Fe, a as he, b as be, o as ke, u as Te, w as we } from "./templateSkeletons-DCvfog6-.js";
9
+ import { F as me, S as fe, F as ge, W as Fe, a as he, b as be, o as ke, u as Te, w as we } from "./templateSkeletons-BB6jQ9r5.js";
10
10
  import { d as ye } from "./messages-CO299wPN.js";
11
11
  import { l as De, s as Ne } from "./bpmn-CtfWDaOY.js";
12
- import { A as We, b as Ae, E as Pe, c as ve, F as Ee, R as Ce, S as Ie, T as Be, W as ze, e as Ve } from "./GatewayBranchEdge-Dxoy5B1A.js";
12
+ import { A as We, b as Ae, E as Pe, c as ve, F as Ee, R as Ce, S as Ie, T as Be, W as ze, e as Ve } from "./GatewayBranchEdge-Diid9GtB.js";
13
13
  class s {
14
14
  constructor() {
15
15
  this.channels = /* @__PURE__ */ new Map();
@@ -336,7 +336,13 @@ declare interface WorkflowTemplate {
336
336
  description?: string;
337
337
  icon?: ReactNode;
338
338
  triggerCategory?: 'event' | 'scheduler' | 'webhook' | string;
339
+ /**
340
+ * Task IDs (descriptor types) that can be inserted into this workflow.
341
+ * `allowedTasks` is accepted as an alias for backend payloads that use
342
+ * that name — TemplateRegistry.register() normalises them.
343
+ */
339
344
  availableTasks?: string[];
345
+ allowedTasks?: string[];
340
346
  maxTasks?: number;
341
347
  taskLabels?: Record<string, string>;
342
348
  fixedNodes?: FixedNode[];
package/dist/style.css CHANGED
@@ -1,4 +1,4 @@
1
- .react-flow{direction:ltr}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;cursor:-webkit-grab;cursor:grab}.react-flow__pane.selection{cursor:pointer}.react-flow__pane.dragging{cursor:-webkit-grabbing;cursor:grabbing}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow .react-flow__edges{pointer-events:none;overflow:visible}.react-flow__edge-path,.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.react-flow__edge{pointer-events:visibleStroke;cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;-webkit-animation:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path,.react-flow__edge:focus-visible .react-flow__edge-path{stroke:#555}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-textbg{fill:#fff}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__connectionline{z-index:1001}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:-webkit-grab;cursor:grab}.react-flow__node.dragging{cursor:-webkit-grabbing;cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:-webkit-grab;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background:#1a192b;border:1px solid white;border-radius:100%}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:-4px;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{top:50%;left:-4px;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.center{left:50%;transform:translate(-50%)}.react-flow__attribution{font-size:10px;background:#ffffff80;padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@-webkit-keyframes dashdraw{0%{stroke-dashoffset:10}}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:3px;width:150px;font-size:12px;color:#222;text-align:center;border-width:1px;border-style:solid;border-color:#1a192b;background-color:#fff}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-group{background-color:#f0f0f040}.react-flow__nodesselection-rect,.react-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls{box-shadow:0 0 2px 1px #00000014}.react-flow__controls-button{border:none;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;padding:5px}.react-flow__controls-button:hover{background:#f4f4f4}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__minimap{background-color:#fff}.react-flow__minimap svg{display:block}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:4px;height:4px;border:1px solid #fff;border-radius:1px;background-color:#3367d9;transform:translate(-50%,-50%)}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:#3367d9;border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.ff-form-grid,.ff-form-row{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;column-gap:16px}.ff-form-grid{padding-left:4px;padding-right:4px}.ff-form-grid input::placeholder,.ff-form-grid textarea::placeholder{color:#00000061;opacity:1}.ff-form-grid input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([class*=ff-select]):focus,.ff-form-grid textarea:not(.cm-content):not([class*=cm-]):focus{outline:none;border-color:#86b7fe!important;box-shadow:0 0 0 3px #0d6efd2e!important}.ff-form-grid input[class*=ff-select]:focus{outline:none!important;box-shadow:none!important;border:none!important}.ff-form-grid input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([class*=ff-select]){height:38px;padding:0 12px;font-size:14px;font-family:inherit;border:1px solid #ced4da;border-radius:6px;box-sizing:border-box;transition:border-color .15s,box-shadow .15s;width:100%;background:#fff}.ff-form-grid textarea:not(.cm-content):not([class*=cm-]){height:auto;min-height:76px;padding:8px 12px;font-size:14px;font-family:inherit;border:1px solid #ced4da;border-radius:6px;box-sizing:border-box;transition:border-color .15s,box-shadow .15s;width:100%;background:#fff;resize:vertical}.ff-form-grid input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([class*=ff-select]):disabled,.ff-form-grid textarea:not(.cm-content):not([class*=cm-]):disabled{background:#f8f9fa;color:#00000061;cursor:not-allowed}.ff-form-col-1{flex:1 0 calc(8.333333% - 14.667px);max-width:100%}.ff-form-col-2{flex:1 0 calc(16.666667% - 13.333px);max-width:100%}.ff-form-col-3{flex:1 0 calc(25% - 12px);max-width:100%}.ff-form-col-4{flex:1 0 calc(33.333333% - 10.667px);max-width:100%}.ff-form-col-5{flex:1 0 calc(41.666667% - 9.333px);max-width:100%}.ff-form-col-6{flex:1 0 calc(50% - 8px);max-width:100%}.ff-form-col-7{flex:1 0 calc(58.333333% - 6.667px);max-width:100%}.ff-form-col-8{flex:1 0 calc(66.666667% - 5.333px);max-width:100%}.ff-form-col-9{flex:1 0 calc(75% - 4px);max-width:100%}.ff-form-col-10{flex:1 0 calc(83.333333% - 2.667px);max-width:100%}.ff-form-col-11{flex:1 0 calc(91.666667% - 1.333px);max-width:100%}.ff-form-col-12{flex:1 0 100%;max-width:100%}.ff-form-hidden{display:none!important}.ff-form-mb-0{margin-bottom:0!important}.ff-form-mb-1{margin-bottom:4px!important}.ff-form-mb-4{margin-bottom:32px!important}.ff-form-mt-1{margin-top:4px!important}.ff-form-ms-2{margin-left:8px!important}.ff-form-ps-1{padding-left:4px!important}.ff-form-p-0{padding:0!important}.ff-form-d-flex{display:flex!important}.ff-form-align-start{align-items:flex-start!important}.ff-form-align-center{align-items:center!important}.ff-form-justify-between{justify-content:space-between!important}.ff-form-flex-wrap{flex-wrap:wrap!important}.ff-form-flex-grow-1{flex-grow:1!important}.ff-form-flex-shrink-0{flex-shrink:0!important}.ff-form-gap-1{gap:4px!important}.ff-form-gap-2{gap:8px!important}.ff-form-w-100{width:100%!important}.ff-form-text-12{font-size:12px!important}.ff-form-text-14{font-size:14px!important}.ff-form-text-dark{color:#212121!important}.ff-form-text-danger{color:#dc3545!important}.ff-form-text-primary{color:#0d6efd!important}.ff-form-text-body-tertiary{color:#6c757d!important}.ff-form-fw-medium{font-weight:500!important}.ff-form-text-capitalize{text-transform:capitalize!important}.ff-form-shadow-none{box-shadow:none!important}.ff-form-bg-light{background-color:#f8f9fa!important}.ff-form-divider{margin-top:4px;margin-bottom:4px}.flowforge-canvas .react-flow,.flowforge-canvas .react-flow__renderer,.flowforge-canvas .react-flow__viewport,.flowforge-canvas .react-flow__pane{width:100%!important;height:100%!important}.flowforge-canvas .react-flow__node{width:fit-content!important;max-width:none!important;min-width:0;padding:0;background:transparent;border:none;box-shadow:none}.flowforge-canvas .react-flow__edge,.flowforge-canvas .react-flow__edgeupdater{pointer-events:auto}.flowforge-canvas .react-flow__handle,.flowforge-canvas .react-flow__handle:before,.flowforge-canvas .react-flow__handle:after{opacity:0!important;visibility:hidden!important;background:transparent!important;background-color:transparent!important;border:none!important;border-color:transparent!important;box-shadow:none!important;outline:none!important}.flowforge-canvas .xyflow__handle,.flowforge-canvas .xyflow__handle:before,.flowforge-canvas .xyflow__handle:after{opacity:0!important;visibility:hidden!important;background:transparent!important;border:none!important}.flowforge-canvas{line-height:1.5}.schema-builder-root{display:flex;flex-direction:column}.schema-builder-header{display:flex;align-items:center;margin-bottom:12px}.schema-builder-actions{display:flex;gap:8px;margin-left:auto}.schema-builder-empty-state{border:1.5px dashed rgba(0,0,0,.08);border-radius:12px;padding:64px 32px;text-align:center;background-color:#fafafa;display:flex;flex-direction:column;align-items:center;gap:20px}.schema-builder-empty-icon{color:#94a3b8;margin-bottom:4px}.schema-builder-empty-title{font-size:13px;font-weight:400;color:#334155;max-width:400px;line-height:1.5;margin-bottom:8px}.schema-builder-empty-actions{display:flex;flex-direction:column;align-items:center;gap:12px}.sb-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:500;cursor:pointer;transition:all .2s;border:1px solid transparent}.sb-btn-outline{border-color:#e2e8f0;background:#fff;color:#475569}.sb-btn-outline:hover{background:#f1f5f9;border-color:#cbd5e1}.sb-btn-primary{background:#6366f1;color:#fff;box-shadow:0 1px 3px #6366f14d}.sb-btn-primary:hover{background:#4f46e5}.sb-btn-big{padding:10px 32px;font-size:14px;font-weight:600;border-color:#1e293b;color:#1e293b}.sb-btn-big:hover{background:#f8fafc}.setup-manual-text{font-size:13px;color:#64748b;display:flex;align-items:center;gap:4px}.setup-manual-link{color:#64748b;cursor:pointer;text-decoration:underline}.setup-manual-link:hover{color:#6366f1}.sb-field-row{display:flex;align-items:center;gap:12px;padding:8px 16px;border:1px solid #e2e8f0;border-radius:8px;background-color:#fff;cursor:pointer;transition:all .15s;margin-bottom:8px}.sb-field-row:hover{border-color:#cbd5e1;box-shadow:0 2px 8px #0000000a;background-color:#f8fafc}.sb-field-type-badge{font-size:10px;font-weight:700;padding:2px 8px;border-radius:4px;background-color:#eef2ff;color:#6366f1;flex-shrink:0;white-space:nowrap;text-transform:uppercase}.sb-field-info{flex:1;min-width:0}.sb-field-label{font-size:13px;font-weight:600;color:#0f172a;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sb-field-meta{font-size:11px;color:#94a3b8;font-family:monospace}.sb-field-actions{display:flex;align-items:center;gap:4px}.sb-icon-btn{background:none;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:5px;padding:0;color:#94a3b8;transition:all .12s}.sb-icon-btn:hover{background-color:#f1f5f9;color:#475569}.sb-icon-btn-danger:hover{background-color:#fee2e2;color:#dc2626}.edge-plus-circle{fill:#fff;stroke:#b0bec5;stroke-width:1.5;transition:stroke .15s,fill .15s}.plus-line{stroke:#757575;transition:stroke .15s}.edge-plus-tooltip{opacity:0;transition:opacity .15s;pointer-events:none}.edge-plus-tooltip .tooltip-bg{fill:#424242}.edge-plus-svg:hover .edge-plus-circle{fill:var(--ff-primary, #1dbf60);stroke:var(--ff-primary, #1dbf60)}.edge-plus-svg:hover .plus-line{stroke:#fff}.edge-plus-svg:hover .edge-plus-tooltip{opacity:1}.edge-plus-html:hover .edge-plus-circle{fill:#1dbf60;stroke:#1dbf60}.edge-plus-html:hover .plus-line{stroke:#fff}.edge-plus-html:hover .edge-plus-tooltip{opacity:1}.ff-d-flex{display:flex!important}.ff-d-inline-flex{display:inline-flex!important}.ff-flex-column{flex-direction:column!important}.ff-flex-wrap{flex-wrap:wrap!important}.ff-align-items-center{align-items:center!important}.ff-align-items-start{align-items:flex-start!important}.ff-justify-content-between{justify-content:space-between!important}.ff-justify-content-start{justify-content:flex-start!important}.ff-justify-content-center{justify-content:center!important}.ff-flex-grow-1{flex-grow:1!important}.ff-flex-shrink-0{flex-shrink:0!important}.ff-gap-1{gap:4px!important}.ff-gap-2{gap:8px!important}.ff-gap-3{gap:16px!important}.ff-m-0{margin:0!important}.ff-mx-1{margin-left:4px!important;margin-right:4px!important}.ff-mx-2{margin-left:8px!important;margin-right:8px!important}.ff-ms-1{margin-left:4px!important}.ff-ms-2{margin-left:8px!important}.ff-me-1{margin-right:4px!important}.ff-me-2{margin-right:8px!important}.ff-mt-1{margin-top:4px!important}.ff-mt-2{margin-top:8px!important}.ff-mb-0{margin-bottom:0!important}.ff-mb-1{margin-bottom:4px!important}.ff-mb-2{margin-bottom:8px!important}.ff-mb-3{margin-bottom:16px!important}.ff-p-2{padding:8px!important}.ff-p-3{padding:16px!important}.ff-px-1{padding-left:4px!important;padding-right:4px!important}.ff-px-2{padding-left:8px!important;padding-right:8px!important}.ff-py-1{padding-top:4px!important;padding-bottom:4px!important}.ff-py-2{padding-top:8px!important;padding-bottom:8px!important}.ff-py-3{padding-top:16px!important;padding-bottom:16px!important}.ff-rounded{border-radius:var(--ff-radius, 6px)!important}.ff-rounded-1{border-radius:4px!important}.ff-rounded-circle{border-radius:50%!important}.ff-rounded-pill{border-radius:999px!important}.ff-border{border:1px solid var(--ff-border, #dee2e6)!important}.ff-badge{display:inline-block;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline}.ff-bg-dark{background-color:#212529!important}.ff-bg-primary{background-color:#0d6efd!important}.ff-bg-light{background-color:#f8f9fa!important}.ff-text-white{color:#fff!important}.ff-text-muted{color:var(--ff-muted, #9ca3af)!important}.ff-text-dark{color:var(--ff-text, #212121)!important}.ff-text-black{color:#000!important}.ff-text-warning{color:#ffc107!important}.ff-text-secondary{color:#6c757d!important}.ff-text-center{text-align:center!important}.ff-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ff-fw-medium{font-weight:500!important}.ff-fw-bold{font-weight:700!important}/*!
1
+ .react-flow{direction:ltr}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;cursor:-webkit-grab;cursor:grab}.react-flow__pane.selection{cursor:pointer}.react-flow__pane.dragging{cursor:-webkit-grabbing;cursor:grabbing}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow .react-flow__edges{pointer-events:none;overflow:visible}.react-flow__edge-path,.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.react-flow__edge{pointer-events:visibleStroke;cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;-webkit-animation:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path,.react-flow__edge:focus-visible .react-flow__edge-path{stroke:#555}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-textbg{fill:#fff}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__connectionline{z-index:1001}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:-webkit-grab;cursor:grab}.react-flow__node.dragging{cursor:-webkit-grabbing;cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:-webkit-grab;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background:#1a192b;border:1px solid white;border-radius:100%}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:-4px;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{top:50%;left:-4px;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.center{left:50%;transform:translate(-50%)}.react-flow__attribution{font-size:10px;background:#ffffff80;padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@-webkit-keyframes dashdraw{0%{stroke-dashoffset:10}}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:3px;width:150px;font-size:12px;color:#222;text-align:center;border-width:1px;border-style:solid;border-color:#1a192b;background-color:#fff}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-group{background-color:#f0f0f040}.react-flow__nodesselection-rect,.react-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls{box-shadow:0 0 2px 1px #00000014}.react-flow__controls-button{border:none;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;padding:5px}.react-flow__controls-button:hover{background:#f4f4f4}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__minimap{background-color:#fff}.react-flow__minimap svg{display:block}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:4px;height:4px;border:1px solid #fff;border-radius:1px;background-color:#3367d9;transform:translate(-50%,-50%)}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:#3367d9;border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.ff-form-grid,.ff-form-row{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;column-gap:16px}.ff-form-grid{padding-left:4px;padding-right:4px}.ff-form-grid input::placeholder,.ff-form-grid textarea::placeholder{color:#00000061;opacity:1}.ff-form-grid input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([class*=ff-select]):focus,.ff-form-grid textarea:not(.cm-content):not([class*=cm-]):focus{outline:none;border-color:#86b7fe!important;box-shadow:0 0 0 3px #0d6efd2e!important}.ff-form-grid input[class*=ff-select]:focus{outline:none!important;box-shadow:none!important;border:none!important}.ff-form-grid input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([class*=ff-select]){height:38px;padding:0 12px;font-size:14px;font-family:inherit;border:1px solid #ced4da;border-radius:6px;box-sizing:border-box;transition:border-color .15s,box-shadow .15s;width:100%;background:#fff}.ff-form-grid textarea:not(.cm-content):not([class*=cm-]){height:auto;min-height:76px;padding:8px 12px;font-size:14px;font-family:inherit;border:1px solid #ced4da;border-radius:6px;box-sizing:border-box;transition:border-color .15s,box-shadow .15s;width:100%;background:#fff;resize:vertical}.ff-form-grid input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([class*=ff-select]):disabled,.ff-form-grid textarea:not(.cm-content):not([class*=cm-]):disabled{background:#f8f9fa;color:#00000061;cursor:not-allowed}.ff-form-col-1{flex:1 0 calc(8.333333% - 14.667px);max-width:100%}.ff-form-col-2{flex:1 0 calc(16.666667% - 13.333px);max-width:100%}.ff-form-col-3{flex:1 0 calc(25% - 12px);max-width:100%}.ff-form-col-4{flex:1 0 calc(33.333333% - 10.667px);max-width:100%}.ff-form-col-5{flex:1 0 calc(41.666667% - 9.333px);max-width:100%}.ff-form-col-6{flex:1 0 calc(50% - 8px);max-width:100%}.ff-form-col-7{flex:1 0 calc(58.333333% - 6.667px);max-width:100%}.ff-form-col-8{flex:1 0 calc(66.666667% - 5.333px);max-width:100%}.ff-form-col-9{flex:1 0 calc(75% - 4px);max-width:100%}.ff-form-col-10{flex:1 0 calc(83.333333% - 2.667px);max-width:100%}.ff-form-col-11{flex:1 0 calc(91.666667% - 1.333px);max-width:100%}.ff-form-col-12{flex:1 0 100%;max-width:100%}.ff-form-hidden{display:none!important}.ff-form-mb-0{margin-bottom:0!important}.ff-form-mb-1{margin-bottom:4px!important}.ff-form-mb-4{margin-bottom:32px!important}.ff-form-mt-1{margin-top:4px!important}.ff-form-ms-2{margin-left:8px!important}.ff-form-ps-1{padding-left:4px!important}.ff-form-p-0{padding:0!important}.ff-form-d-flex{display:flex!important}.ff-form-align-start{align-items:flex-start!important}.ff-form-align-center{align-items:center!important}.ff-form-justify-between{justify-content:space-between!important}.ff-form-flex-wrap{flex-wrap:wrap!important}.ff-form-flex-grow-1{flex-grow:1!important}.ff-form-flex-shrink-0{flex-shrink:0!important}.ff-form-gap-1{gap:4px!important}.ff-form-gap-2{gap:8px!important}.ff-form-w-100{width:100%!important}.ff-form-text-12{font-size:12px!important}.ff-form-text-14{font-size:14px!important}.ff-form-text-dark{color:#212121!important}.ff-form-text-danger{color:#dc3545!important}.ff-form-text-primary{color:#0d6efd!important}.ff-form-text-body-tertiary{color:#6c757d!important}.ff-form-fw-medium{font-weight:500!important}.ff-form-text-capitalize{text-transform:capitalize!important}.ff-form-shadow-none{box-shadow:none!important}.ff-form-bg-light{background-color:#f8f9fa!important}.ff-form-divider{margin-top:4px;margin-bottom:4px}.flowforge-canvas .react-flow,.flowforge-canvas .react-flow__renderer,.flowforge-canvas .react-flow__viewport,.flowforge-canvas .react-flow__pane{width:100%!important;height:100%!important}.flowforge-canvas .react-flow__node{width:fit-content!important;max-width:none!important;min-width:0;padding:0;background:transparent;border:none;box-shadow:none;display:block!important;justify-content:flex-start!important;align-items:stretch!important;text-align:left!important}.flowforge-canvas .react-flow__edge,.flowforge-canvas .react-flow__edgeupdater{pointer-events:auto}.flowforge-canvas{--xy-handle-background-color: transparent !important;--xy-handle-border-color: transparent !important;--xy-handle-background-color-default: transparent !important;--xy-handle-border-color-default: transparent !important}.flowforge-canvas .react-flow__handle,.flowforge-canvas .react-flow__handle:before,.flowforge-canvas .react-flow__handle:after{opacity:0!important;visibility:hidden!important;background:transparent!important;background-color:transparent!important;border:none!important;border-color:transparent!important;box-shadow:none!important;outline:none!important;width:1px!important;height:1px!important}.flowforge-canvas .xyflow__handle,.flowforge-canvas .xyflow__handle:before,.flowforge-canvas .xyflow__handle:after{opacity:0!important;visibility:hidden!important;background:transparent!important;border:none!important}.flowforge-canvas{line-height:1.5}.schema-builder-root{display:flex;flex-direction:column}.schema-builder-header{display:flex;align-items:center;margin-bottom:12px}.schema-builder-actions{display:flex;gap:8px;margin-left:auto}.schema-builder-empty-state{border:1.5px dashed rgba(0,0,0,.08);border-radius:12px;padding:64px 32px;text-align:center;background-color:#fafafa;display:flex;flex-direction:column;align-items:center;gap:20px}.schema-builder-empty-icon{color:#94a3b8;margin-bottom:4px}.schema-builder-empty-title{font-size:13px;font-weight:400;color:#334155;max-width:400px;line-height:1.5;margin-bottom:8px}.schema-builder-empty-actions{display:flex;flex-direction:column;align-items:center;gap:12px}.sb-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:500;cursor:pointer;transition:all .2s;border:1px solid transparent}.sb-btn-outline{border-color:#e2e8f0;background:#fff;color:#475569}.sb-btn-outline:hover{background:#f1f5f9;border-color:#cbd5e1}.sb-btn-primary{background:#6366f1;color:#fff;box-shadow:0 1px 3px #6366f14d}.sb-btn-primary:hover{background:#4f46e5}.sb-btn-big{padding:10px 32px;font-size:14px;font-weight:600;border-color:#1e293b;color:#1e293b}.sb-btn-big:hover{background:#f8fafc}.setup-manual-text{font-size:13px;color:#64748b;display:flex;align-items:center;gap:4px}.setup-manual-link{color:#64748b;cursor:pointer;text-decoration:underline}.setup-manual-link:hover{color:#6366f1}.sb-field-row{display:flex;align-items:center;gap:12px;padding:8px 16px;border:1px solid #e2e8f0;border-radius:8px;background-color:#fff;cursor:pointer;transition:all .15s;margin-bottom:8px}.sb-field-row:hover{border-color:#cbd5e1;box-shadow:0 2px 8px #0000000a;background-color:#f8fafc}.sb-field-type-badge{font-size:10px;font-weight:700;padding:2px 8px;border-radius:4px;background-color:#eef2ff;color:#6366f1;flex-shrink:0;white-space:nowrap;text-transform:uppercase}.sb-field-info{flex:1;min-width:0}.sb-field-label{font-size:13px;font-weight:600;color:#0f172a;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sb-field-meta{font-size:11px;color:#94a3b8;font-family:monospace}.sb-field-actions{display:flex;align-items:center;gap:4px}.sb-icon-btn{background:none;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:5px;padding:0;color:#94a3b8;transition:all .12s}.sb-icon-btn:hover{background-color:#f1f5f9;color:#475569}.sb-icon-btn-danger:hover{background-color:#fee2e2;color:#dc2626}.edge-plus-circle{fill:#fff;stroke:#b0bec5;stroke-width:1.5;transition:stroke .15s,fill .15s}.plus-line{stroke:#757575;transition:stroke .15s}.edge-plus-tooltip{opacity:0;transition:opacity .15s;pointer-events:none}.edge-plus-tooltip .tooltip-bg{fill:#424242}.edge-plus-svg:hover .edge-plus-circle{fill:var(--ff-primary, #1dbf60);stroke:var(--ff-primary, #1dbf60)}.edge-plus-svg:hover .plus-line{stroke:#fff}.edge-plus-svg:hover .edge-plus-tooltip{opacity:1}.edge-plus-html:hover .edge-plus-circle{fill:#1dbf60;stroke:#1dbf60}.edge-plus-html:hover .plus-line{stroke:#fff}.edge-plus-html:hover .edge-plus-tooltip{opacity:1}.ff-d-flex{display:flex!important}.ff-d-inline-flex{display:inline-flex!important}.ff-flex-column{flex-direction:column!important}.ff-flex-wrap{flex-wrap:wrap!important}.ff-align-items-center{align-items:center!important}.ff-align-items-start{align-items:flex-start!important}.ff-justify-content-between{justify-content:space-between!important}.ff-justify-content-start{justify-content:flex-start!important}.ff-justify-content-center{justify-content:center!important}.ff-flex-grow-1{flex-grow:1!important}.ff-flex-shrink-0{flex-shrink:0!important}.ff-gap-1{gap:4px!important}.ff-gap-2{gap:8px!important}.ff-gap-3{gap:16px!important}.ff-m-0{margin:0!important}.ff-mx-1{margin-left:4px!important;margin-right:4px!important}.ff-mx-2{margin-left:8px!important;margin-right:8px!important}.ff-ms-1{margin-left:4px!important}.ff-ms-2{margin-left:8px!important}.ff-me-1{margin-right:4px!important}.ff-me-2{margin-right:8px!important}.ff-mt-1{margin-top:4px!important}.ff-mt-2{margin-top:8px!important}.ff-mb-0{margin-bottom:0!important}.ff-mb-1{margin-bottom:4px!important}.ff-mb-2{margin-bottom:8px!important}.ff-mb-3{margin-bottom:16px!important}.ff-p-2{padding:8px!important}.ff-p-3{padding:16px!important}.ff-px-1{padding-left:4px!important;padding-right:4px!important}.ff-px-2{padding-left:8px!important;padding-right:8px!important}.ff-py-1{padding-top:4px!important;padding-bottom:4px!important}.ff-py-2{padding-top:8px!important;padding-bottom:8px!important}.ff-py-3{padding-top:16px!important;padding-bottom:16px!important}.ff-rounded{border-radius:var(--ff-radius, 6px)!important}.ff-rounded-1{border-radius:4px!important}.ff-rounded-circle{border-radius:50%!important}.ff-rounded-pill{border-radius:999px!important}.ff-border{border:1px solid var(--ff-border, #dee2e6)!important}.ff-badge{display:inline-block;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline}.ff-bg-dark{background-color:#212529!important}.ff-bg-primary{background-color:#0d6efd!important}.ff-bg-light{background-color:#f8f9fa!important}.ff-text-white{color:#fff!important}.ff-text-muted{color:var(--ff-muted, #9ca3af)!important}.ff-text-dark{color:var(--ff-text, #212121)!important}.ff-text-black{color:#000!important}.ff-text-warning{color:#ffc107!important}.ff-text-secondary{color:#6c757d!important}.ff-text-center{text-align:center!important}.ff-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ff-fw-medium{font-weight:500!important}.ff-fw-bold{font-weight:700!important}/*!
2
2
  * Quill Editor v1.3.7
3
3
  * https://quilljs.com/
4
4
  * Copyright (c) 2014, Jason Chen
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class o{constructor(){this.templates=new Map}register(e){return this.templates.set(e.triggerKey,e),this}lookup(e){return this.templates.get(e)}list(){return[...this.templates.values()]}listByCategory(e){return this.list().filter(t=>t.category===e)}listByTag(e){return this.list().filter(t=>{var s;return(s=t.tags)==null?void 0:s.includes(e)})}search(e){const t=e.toLowerCase();return this.list().filter(s=>{var r,i,a;return s.label.toLowerCase().includes(t)||((r=s.description)==null?void 0:r.toLowerCase().includes(t))||((i=s.tags)==null?void 0:i.some(l=>l.toLowerCase().includes(t)))||((a=s.category)==null?void 0:a.toLowerCase().includes(t))})}categories(){const e=new Set;return this.list().forEach(t=>{t.category&&e.add(t.category)}),Array.from(e)}}const c=new o;exports.TemplateRegistry=o;exports.templateRegistry=c;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class l{constructor(){this.templates=new Map}register(t){const e={...t,availableTasks:t.availableTasks??t.allowedTasks};return this.templates.set(e.triggerKey,e),this}registerFromApi(t){for(const e of t??[])e!=null&&e.key&&this.register({triggerKey:e.key,label:e.name??e.key,description:e.description,availableTasks:e.allowedTasks,...e.templateUI??{}});return this}lookup(t){return this.templates.get(t)}list(){return[...this.templates.values()]}listByCategory(t){return this.list().filter(e=>e.category===t)}listByTag(t){return this.list().filter(e=>{var s;return(s=e.tags)==null?void 0:s.includes(t)})}search(t){const e=t.toLowerCase();return this.list().filter(s=>{var r,i,a;return s.label.toLowerCase().includes(e)||((r=s.description)==null?void 0:r.toLowerCase().includes(e))||((i=s.tags)==null?void 0:i.some(o=>o.toLowerCase().includes(e)))||((a=s.category)==null?void 0:a.toLowerCase().includes(e))})}categories(){const t=new Set;return this.list().forEach(e=>{e.category&&t.add(e.category)}),Array.from(t)}clear(){return this.templates.clear(),this}}const n=new l;exports.TemplateRegistry=l;exports.templateRegistry=n;
2
2
  //# sourceMappingURL=templateRegistry.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"templateRegistry.cjs","sources":["../src/templateRegistry/index.ts"],"sourcesContent":["import { WorkflowTemplate } from '../WorkflowCanvas/types';\r\n\r\nexport class TemplateRegistry {\r\n private templates = new Map<string, WorkflowTemplate>();\r\n\r\n register(template: WorkflowTemplate): this {\r\n this.templates.set(template.triggerKey, template);\r\n return this;\r\n }\r\n\r\n lookup(triggerKey: string): WorkflowTemplate | undefined {\r\n return this.templates.get(triggerKey);\r\n }\r\n\r\n list(): WorkflowTemplate[] {\r\n return [...this.templates.values()];\r\n }\r\n\r\n listByCategory(category: string): WorkflowTemplate[] {\r\n return this.list().filter((t) => t.category === category);\r\n }\r\n\r\n listByTag(tag: string): WorkflowTemplate[] {\r\n return this.list().filter((t) => t.tags?.includes(tag));\r\n }\r\n\r\n search(query: string): WorkflowTemplate[] {\r\n const q = query.toLowerCase();\r\n return this.list().filter(\r\n (t) =>\r\n t.label.toLowerCase().includes(q) ||\r\n t.description?.toLowerCase().includes(q) ||\r\n t.tags?.some((tag) => tag.toLowerCase().includes(q)) ||\r\n t.category?.toLowerCase().includes(q),\r\n );\r\n }\r\n\r\n categories(): string[] {\r\n const cats = new Set<string>();\r\n this.list().forEach((t) => { if (t.category) cats.add(t.category); });\r\n return Array.from(cats);\r\n }\r\n}\r\n\r\nexport const templateRegistry = new TemplateRegistry();\r\nexport type { WorkflowTemplate };\r\n"],"names":["TemplateRegistry","template","triggerKey","category","tag","_a","query","q","t","_b","_c","cats","templateRegistry"],"mappings":"gFAEO,MAAMA,CAAiB,CAAvB,aAAA,CACL,KAAQ,cAAgB,GAA8B,CAEtD,SAASC,EAAkC,CACzC,YAAK,UAAU,IAAIA,EAAS,WAAYA,CAAQ,EACzC,IACT,CAEA,OAAOC,EAAkD,CACvD,OAAO,KAAK,UAAU,IAAIA,CAAU,CACtC,CAEA,MAA2B,CACzB,MAAO,CAAC,GAAG,KAAK,UAAU,QAAQ,CACpC,CAEA,eAAeC,EAAsC,CACnD,OAAO,KAAK,OAAO,OAAQ,GAAM,EAAE,WAAaA,CAAQ,CAC1D,CAEA,UAAUC,EAAiC,CACzC,OAAO,KAAK,KAAA,EAAO,OAAQ,UAAM,OAAAC,EAAA,EAAE,OAAF,YAAAA,EAAQ,SAASD,GAAI,CACxD,CAEA,OAAOE,EAAmC,CACxC,MAAMC,EAAID,EAAM,YAAA,EAChB,OAAO,KAAK,OAAO,OAChBE,GAAA,WACC,OAAAA,EAAE,MAAM,cAAc,SAASD,CAAC,KAChCF,EAAAG,EAAE,cAAF,YAAAH,EAAe,cAAc,SAASE,OACtCE,EAAAD,EAAE,OAAF,YAAAC,EAAQ,KAAML,GAAQA,EAAI,cAAc,SAASG,CAAC,OAClDG,EAAAF,EAAE,WAAF,YAAAE,EAAY,cAAc,SAASH,IAAC,CAE1C,CAEA,YAAuB,CACrB,MAAMI,MAAW,IACjB,YAAK,KAAA,EAAO,QAAS,GAAM,CAAM,EAAE,UAAUA,EAAK,IAAI,EAAE,QAAQ,CAAG,CAAC,EAC7D,MAAM,KAAKA,CAAI,CACxB,CACF,CAEO,MAAMC,EAAmB,IAAIZ"}
1
+ {"version":3,"file":"templateRegistry.cjs","sources":["../src/templateRegistry/index.ts"],"sourcesContent":["import type { WorkflowTemplate, ApiWorkflowTemplate } from '../WorkflowCanvas/types';\n\nexport class TemplateRegistry {\n private templates = new Map<string, WorkflowTemplate>();\n\n /**\n * Register a template. Normalises `allowedTasks` (the backend's name) →\n * `availableTasks` (FlowForge's canonical name) so consumers can pass\n * either without rewriting.\n */\n register(template: WorkflowTemplate): this {\n const normalised: WorkflowTemplate = {\n ...template,\n availableTasks: template.availableTasks ?? template.allowedTasks,\n };\n this.templates.set(normalised.triggerKey, normalised);\n return this;\n }\n\n /**\n * Register a list of templates fetched from `GET /api/v1/workflow-template`.\n *\n * The API shape is:\n * {\n * key, name, description, allowedTasks, allowedSources,\n * configuration, // runtime BPMN — ignored by the canvas\n * templateUI: { // ← UI bag, spread onto the template\n * triggerCategory, icon, tags, category, author, popularity,\n * source, product, taskLabels, maxTasks, skeletonState, …\n * }\n * }\n *\n * Anything in `templateUI` overrides the top-level shorthand where there's\n * an overlap. Bad rows (missing `key`) are skipped with a DEV warning\n * rather than throwing, so one broken template doesn't blank the picker.\n *\n * Returns `this` for chaining and the count of templates registered.\n */\n registerFromApi(list: ApiWorkflowTemplate[]): this {\n for (const t of list ?? []) {\n if (!t?.key) {\n if (import.meta.env?.DEV) {\n // eslint-disable-next-line no-console\n console.warn('[FlowForge] templateRegistry.registerFromApi: skipped row without `key`', t);\n }\n continue;\n }\n this.register({\n triggerKey: t.key,\n label: t.name ?? t.key,\n description: t.description,\n availableTasks: t.allowedTasks,\n ...(t.templateUI ?? {}),\n } as WorkflowTemplate);\n }\n return this;\n }\n\n lookup(triggerKey: string): WorkflowTemplate | undefined {\n return this.templates.get(triggerKey);\n }\n\n list(): WorkflowTemplate[] {\n return [...this.templates.values()];\n }\n\n listByCategory(category: string): WorkflowTemplate[] {\n return this.list().filter((t) => t.category === category);\n }\n\n listByTag(tag: string): WorkflowTemplate[] {\n return this.list().filter((t) => t.tags?.includes(tag));\n }\n\n search(query: string): WorkflowTemplate[] {\n const q = query.toLowerCase();\n return this.list().filter(\n (t) =>\n t.label.toLowerCase().includes(q) ||\n t.description?.toLowerCase().includes(q) ||\n t.tags?.some((tag) => tag.toLowerCase().includes(q)) ||\n t.category?.toLowerCase().includes(q),\n );\n }\n\n categories(): string[] {\n const cats = new Set<string>();\n this.list().forEach((t) => { if (t.category) cats.add(t.category); });\n return Array.from(cats);\n }\n\n /** Remove every template — useful before re-loading from backend. */\n clear(): this {\n this.templates.clear();\n return this;\n }\n}\n\nexport const templateRegistry = new TemplateRegistry();\nexport type { WorkflowTemplate, ApiWorkflowTemplate };\n"],"names":["TemplateRegistry","template","normalised","list","t","triggerKey","category","tag","_a","query","q","_b","_c","cats","templateRegistry"],"mappings":"gFAEO,MAAMA,CAAiB,CAAvB,aAAA,CACL,KAAQ,cAAgB,GAA8B,CAOtD,SAASC,EAAkC,CACzC,MAAMC,EAA+B,CACnC,GAAGD,EACH,eAAgBA,EAAS,gBAAkBA,EAAS,YAAA,EAEtD,YAAK,UAAU,IAAIC,EAAW,WAAYA,CAAU,EAC7C,IACT,CAqBA,gBAAgBC,EAAmC,CACjD,UAAWC,KAAKD,GAAQ,GACjBC,GAAA,MAAAA,EAAG,KAOR,KAAK,SAAS,CACZ,WAAYA,EAAE,IACd,MAAOA,EAAE,MAAQA,EAAE,IACnB,YAAaA,EAAE,YACf,eAAgBA,EAAE,aAClB,GAAIA,EAAE,YAAc,CAAA,CAAC,CACF,EAEvB,OAAO,IACT,CAEA,OAAOC,EAAkD,CACvD,OAAO,KAAK,UAAU,IAAIA,CAAU,CACtC,CAEA,MAA2B,CACzB,MAAO,CAAC,GAAG,KAAK,UAAU,QAAQ,CACpC,CAEA,eAAeC,EAAsC,CACnD,OAAO,KAAK,OAAO,OAAQF,GAAMA,EAAE,WAAaE,CAAQ,CAC1D,CAEA,UAAUC,EAAiC,CACzC,OAAO,KAAK,KAAA,EAAO,OAAQH,UAAM,OAAAI,EAAAJ,EAAE,OAAF,YAAAI,EAAQ,SAASD,GAAI,CACxD,CAEA,OAAOE,EAAmC,CACxC,MAAMC,EAAID,EAAM,YAAA,EAChB,OAAO,KAAK,OAAO,OAChBL,GAAA,WACC,OAAAA,EAAE,MAAM,cAAc,SAASM,CAAC,KAChCF,EAAAJ,EAAE,cAAF,YAAAI,EAAe,cAAc,SAASE,OACtCC,EAAAP,EAAE,OAAF,YAAAO,EAAQ,KAAMJ,GAAQA,EAAI,cAAc,SAASG,CAAC,OAClDE,EAAAR,EAAE,WAAF,YAAAQ,EAAY,cAAc,SAASF,IAAC,CAE1C,CAEA,YAAuB,CACrB,MAAMG,MAAW,IACjB,YAAK,KAAA,EAAO,QAAST,GAAM,CAAMA,EAAE,UAAUS,EAAK,IAAIT,EAAE,QAAQ,CAAG,CAAC,EAC7D,MAAM,KAAKS,CAAI,CACxB,CAGA,OAAc,CACZ,YAAK,UAAU,MAAA,EACR,IACT,CACF,CAEO,MAAMC,EAAmB,IAAId"}
@@ -1,5 +1,21 @@
1
1
  import { ReactNode } from 'react';
2
2
 
3
+ /**
4
+ * Wire shape the backend `/api/v1/workflow-template` endpoint is expected
5
+ * to return. Top-level fields mirror the persistence model; everything
6
+ * UI-related lives under `templateUI`. Use with `templateRegistry.registerFromApi(list)`.
7
+ */
8
+ export declare interface ApiWorkflowTemplate {
9
+ key: string;
10
+ name: string;
11
+ state?: string;
12
+ description?: string;
13
+ allowedTasks?: string[];
14
+ allowedSources?: string[];
15
+ configuration?: Record<string, unknown>;
16
+ templateUI?: Partial<Omit<WorkflowTemplate, 'triggerKey' | 'label' | 'description' | 'availableTasks'>>;
17
+ }
18
+
3
19
  declare type BranchChain = CanvasSlot[];
4
20
 
5
21
  declare interface BranchMap {
@@ -38,13 +54,40 @@ declare type SlotKind = 'start' | 'end' | 'addTrigger' | 'triggerFixed' | 'userT
38
54
 
39
55
  export declare class TemplateRegistry {
40
56
  private templates;
57
+ /**
58
+ * Register a template. Normalises `allowedTasks` (the backend's name) →
59
+ * `availableTasks` (FlowForge's canonical name) so consumers can pass
60
+ * either without rewriting.
61
+ */
41
62
  register(template: WorkflowTemplate): this;
63
+ /**
64
+ * Register a list of templates fetched from `GET /api/v1/workflow-template`.
65
+ *
66
+ * The API shape is:
67
+ * {
68
+ * key, name, description, allowedTasks, allowedSources,
69
+ * configuration, // runtime BPMN — ignored by the canvas
70
+ * templateUI: { // ← UI bag, spread onto the template
71
+ * triggerCategory, icon, tags, category, author, popularity,
72
+ * source, product, taskLabels, maxTasks, skeletonState, …
73
+ * }
74
+ * }
75
+ *
76
+ * Anything in `templateUI` overrides the top-level shorthand where there's
77
+ * an overlap. Bad rows (missing `key`) are skipped with a DEV warning
78
+ * rather than throwing, so one broken template doesn't blank the picker.
79
+ *
80
+ * Returns `this` for chaining and the count of templates registered.
81
+ */
82
+ registerFromApi(list: ApiWorkflowTemplate[]): this;
42
83
  lookup(triggerKey: string): WorkflowTemplate | undefined;
43
84
  list(): WorkflowTemplate[];
44
85
  listByCategory(category: string): WorkflowTemplate[];
45
86
  listByTag(tag: string): WorkflowTemplate[];
46
87
  search(query: string): WorkflowTemplate[];
47
88
  categories(): string[];
89
+ /** Remove every template — useful before re-loading from backend. */
90
+ clear(): this;
48
91
  }
49
92
 
50
93
  export declare const templateRegistry: TemplateRegistry;
@@ -60,7 +103,13 @@ export declare interface WorkflowTemplate {
60
103
  description?: string;
61
104
  icon?: ReactNode;
62
105
  triggerCategory?: 'event' | 'scheduler' | 'webhook' | string;
106
+ /**
107
+ * Task IDs (descriptor types) that can be inserted into this workflow.
108
+ * `allowedTasks` is accepted as an alias for backend payloads that use
109
+ * that name — TemplateRegistry.register() normalises them.
110
+ */
63
111
  availableTasks?: string[];
112
+ allowedTasks?: string[];
64
113
  maxTasks?: number;
65
114
  taskLabels?: Record<string, string>;
66
115
  fixedNodes?: FixedNode[];