Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b21ea0f
feat(sdk): variables by type and handle update with fixed imports
szymon-t-sc Aug 13, 2026
00cf36a
chore(sdk): better typing for getVariableReferences
szymon-t-sc Aug 13, 2026
53acf52
chore(sdk): naming, linting, restoring css variables
szymon-t-sc Aug 13, 2026
3226034
feat(sdk): better variable logic by sourceHandle
szymon-t-sc Aug 14, 2026
7ba3900
chore(sdk): branch sync
szymon-t-sc Aug 14, 2026
f716ffa
test(sdk): mock updated
szymon-t-sc Aug 14, 2026
06c9a90
fix(sdk): refreshing variables on init & controls after edge creation
szymon-t-sc Aug 14, 2026
11eb69e
fix(sdk): dark-mode in variable preview
szymon-t-sc Aug 14, 2026
f3585f6
feat(sdk): output depending on value
szymon-t-sc Aug 14, 2026
efcee63
chore(sdk): better type for Timestamp
szymon-t-sc Aug 14, 2026
8024a46
feat(sdk): dynamic select
szymon-t-sc Aug 14, 2026
9f22a8c
feat(sdk): exposing variables api
szymon-t-sc Aug 20, 2026
fc6c3df
fix(sdk): setDiagramModel refreshes variable suggestions B1
szymon-t-sc Aug 26, 2026
eac7baf
feat(sdk): variables using JSONSchema7
szymon-t-sc Aug 26, 2026
481db80
feat(sdk): generating suggestions from JsonSchema7
szymon-t-sc Aug 26, 2026
4d5c51e
feat(sdk): better from builder variant
szymon-t-sc Aug 26, 2026
6e30e06
chore(sdk): ouput variables in additional files
szymon-t-sc Aug 26, 2026
9e0e941
chore(sdk): support for deprecated
szymon-t-sc Aug 27, 2026
bb6316b
chore(sdk): less exports
szymon-t-sc Aug 27, 2026
8e8cb99
fix(sdk): wrong match onBlur in text-variable
szymon-t-sc Aug 27, 2026
3e2efe8
docs(sdk): chagngset added
szymon-t-sc Aug 28, 2026
4a630c5
docs(sdk): use-variable-picker dock updated
szymon-t-sc Aug 28, 2026
0f4cbea
fix(sdk): correct node label for common suggestions
szymon-t-sc Aug 28, 2026
b92bf14
docs(sdk): migration startegy for deprecated
szymon-t-sc Aug 28, 2026
47e9a62
fix(sdk): broken string for missing
szymon-t-sc Aug 28, 2026
748119a
chore(sdk): typos fixed
szymon-t-sc Aug 28, 2026
0a116b9
Merge branch 'main' of https://github.com/synergycodes/workflowbuilde…
szymon-t-sc Aug 28, 2026
db512e6
fix(sdk): variable-select blur action fix
szymon-t-sc Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sdk-variable-dynamic-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@workflowbuilder/sdk': minor
---

Added a new 'VariableDynamic' control that dynamically builds a control matching the variable's type. It toggles between a regular input and a variable picker limited to variables of the matching type; only a single variable can be set.
5 changes: 5 additions & 0 deletions .changeset/sdk-variables-json-schema.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@workflowbuilder/sdk': patch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump says patch, content says feature

Per-handle variables + JSON Schema outputs is a new capability, so this should be minor. No practical effect on the released version (the other changesets already force a minor), but the CHANGELOG entry will land in the wrong section.

---

Variables now support returning different values for different source handles. Variables are now defined using a JSON schema rather than a flattened list, providing a foundation for future validation.
2 changes: 1 addition & 1 deletion apps/demo/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Each node type lives in `src/app/data/nodes/<node-name>/`. Canonical pattern is

| File | Purpose |
| ---------------------------- | ------------------------------------------------------------------------------------- |
| `<node-name>.ts` | `PaletteItem<Schema>` — label, type, icon, defaults, schemas, optional `outputSchema` |
| `<node-name>.ts` | `PaletteItem<Schema>` — label, type, icon, defaults, schemas, optional `schemaOutput` |
| `schema.ts` | JSON Schema with `satisfies NodeSchema`; spreads `sharedProperties` from the SDK |
| `uischema.ts` | UI Schema using `getScope<Schema>` for type-safe scopes |
| `default-properties-data.ts` | Defaults aligned with the schema |
Expand Down
15 changes: 14 additions & 1 deletion apps/demo/src/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type {
WorkflowBuilderNodeTemplates,
WorkflowBuilderReactFlowProps,
} from '@workflowbuilder/sdk';
import { showSnackbar } from '@workflowbuilder/sdk';
import { SnackbarType } from '@workflowbuilder/ui';

import '@workflowbuilder/sdk/style.css';

Expand Down Expand Up @@ -36,7 +38,18 @@ const edgeTemplates = {
} satisfies WorkflowBuilderEdgeTemplates;

// A start node is where the run begins, so it can never be a connection target.
const isValidConnection: WorkflowBuilderIsValidConnection = ({ targetNode }) => !targetNode.data.isStartNode;
const isValidConnection: WorkflowBuilderIsValidConnection = ({ targetNode }) => {
if (targetNode.data.isStartNode) {
showSnackbar({
title: 'notValidConnection',
variant: SnackbarType.WARNING,
});

return false;
}

return true;
};

// Advanced escape hatch: forward extra ReactFlow props (SDK-owned props can't be set here).
const reactFlowProps = {
Expand Down
5 changes: 4 additions & 1 deletion apps/demo/src/app/data/nodes/action/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { PaletteItem } from '@workflowbuilder/sdk';

import { defaultPropertiesData } from './default-properties-data';
import { type ActionNodeSchema, schema } from './schema';
// import { schemaOutput } from './schema-output';
import { uischema } from './uischema';

export const action: PaletteItem<ActionNodeSchema> = {
Expand All @@ -11,7 +12,8 @@ export const action: PaletteItem<ActionNodeSchema> = {
description: 'node.action.description',
defaultPropertiesData,
schema,
uischema,
// schemaOutput,
// Example of a deprecated response. Use schemaOutput instead.
outputSchema: {
type: 'default',
properties: {
Expand All @@ -20,4 +22,5 @@ export const action: PaletteItem<ActionNodeSchema> = {
errorMessage: { type: 'string', label: 'Error Message', description: 'Error details if the action failed' },
},
},
uischema,
};
34 changes: 34 additions & 0 deletions apps/demo/src/app/data/nodes/action/schema-output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { NodeSchemaOutput } from '@workflowbuilder/sdk';

export const schemaOutput: NodeSchemaOutput = {
type: 'default',
bySourceHandle: {
success: {
type: 'object',
properties: {
result: {
type: 'object',
title: 'Result',
description: 'The data returned by the action',
properties: {
status: {
type: 'string',
title: 'Status',
description: 'Execution status: success, failure, or skipped',
},
},
},
},
},
error: {
type: 'object',
properties: {
errorMessage: {
type: 'string',
title: 'Error Message',
description: 'Error details if the action failed',
},
},
},
},
};
11 changes: 6 additions & 5 deletions apps/demo/src/app/data/nodes/action/uischema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,16 @@ const sendEmailProperties: ActionNodeUISchema = {
placeholder: 'manager@example.com',
},
{
type: 'Text',
type: 'VariableText',
scope: scope('properties.sendEmail.properties.subject'),
label: 'Subject',
placeholder: 'Type your subject here...',
placeholder: 'Type your subject here... Use {{ to insert variables',
},
{
type: 'TextArea',
type: 'VariableTextArea',
scope: scope('properties.sendEmail.properties.body'),
label: 'Email Body',
placeholder: 'Type your message here...',
placeholder: 'Type your message here... Use {{ to insert variables',
minRows: 5,
},
{
Expand All @@ -81,7 +81,8 @@ const sendEmailProperties: ActionNodeUISchema = {
elements: [
{ type: 'Label', text: 'Number of retries' },
{
type: 'Text',
type: 'VariableDynamic',
variableType: 'number',
scope: scope('properties.sendEmail.properties.retries'),
rule: {
effect: 'DISABLE',
Expand Down
10 changes: 2 additions & 8 deletions apps/demo/src/app/data/nodes/ai-agent/ai-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { PaletteItem } from '@workflowbuilder/sdk';

import { defaultPropertiesData } from './default-properties-data';
import { schema } from './schema';
import { schemaOutput } from './schema-output';
import { uischema } from './uischema';

export const aiAgent: PaletteItem = {
Expand All @@ -13,13 +14,6 @@ export const aiAgent: PaletteItem = {
templateType: NodeType.AiNode,
defaultPropertiesData,
schema,
schemaOutput,
uischema,
outputSchema: {
type: 'default',
properties: {
response: { type: 'string', label: 'Response', description: 'The text generated by the AI model' },
tokensUsed: { type: 'number', label: 'Tokens Used', description: 'Total number of tokens consumed' },
model: { type: 'string', label: 'Model', description: 'The AI model that was used' },
},
},
};
27 changes: 27 additions & 0 deletions apps/demo/src/app/data/nodes/ai-agent/schema-output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { NodeSchemaOutput } from '@workflowbuilder/sdk';

export const schemaOutput: NodeSchemaOutput = {
type: 'default',
bySourceHandle: {
success: {
type: 'object',
properties: {
response: {
type: 'string',
title: 'Response',
description: 'The text generated by the AI model',
},
tokensUsed: {
type: 'number',
title: 'Tokens Used',
description: 'Total number of tokens consumed',
},
model: {
type: 'string',
title: 'Model',
description: 'The AI model that was used',
},
},
},
},
};
13 changes: 2 additions & 11 deletions apps/demo/src/app/data/nodes/conditional/conditional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { PaletteItem } from '@workflowbuilder/sdk';

import { defaultPropertiesData } from './default-properties-data';
import { type ConditionalNodeSchema, schema } from './schema';
import { schemaOutput } from './schema-output';
import { uischema } from './uischema';

export const conditional: PaletteItem<ConditionalNodeSchema> = {
Expand All @@ -11,16 +12,6 @@ export const conditional: PaletteItem<ConditionalNodeSchema> = {
icon: 'ListChecks',
defaultPropertiesData,
schema,
schemaOutput,
uischema,
outputSchema: {
type: 'default',
properties: {
result: { type: 'boolean', label: 'Result', description: 'Whether the condition evaluated to true or false' },
matchedCondition: {
type: 'string',
label: 'Matched Condition',
description: 'The condition expression that matched',
},
},
},
};
22 changes: 22 additions & 0 deletions apps/demo/src/app/data/nodes/conditional/schema-output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { NodeSchemaOutput } from '@workflowbuilder/sdk';

export const schemaOutput: NodeSchemaOutput = {
type: 'default',
bySourceHandle: {
success: {
type: 'object',
properties: {
result: {
type: 'boolean',
title: 'Result',
description: 'Whether the condition evaluated to true or false',
},
matchedCondition: {
type: 'string',
title: 'Matched Condition',
description: 'The condition expression that matched',
},
},
},
},
};
9 changes: 2 additions & 7 deletions apps/demo/src/app/data/nodes/decision/decision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { PaletteItem } from '@workflowbuilder/sdk';

import { defaultPropertiesData } from './default-properties-data';
import { type DecisionNodeSchema, schema } from './schema';
import { schemaOutput } from './schema-output';
import { uischema } from './uischema';

export const decision: PaletteItem<DecisionNodeSchema> = {
Expand All @@ -13,12 +14,6 @@ export const decision: PaletteItem<DecisionNodeSchema> = {
templateType: NodeType.DecisionNode,
defaultPropertiesData,
schema,
schemaOutput,
uischema,
outputSchema: {
type: 'default',
properties: {
selectedBranch: { type: 'string', label: 'Selected Branch', description: 'Label of the branch that was taken' },
branchIndex: { type: 'number', label: 'Branch Index', description: 'Zero-based index of the selected branch' },
},
},
};
22 changes: 22 additions & 0 deletions apps/demo/src/app/data/nodes/decision/schema-output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { NodeSchemaOutput } from '@workflowbuilder/sdk';

export const schemaOutput: NodeSchemaOutput = {
type: 'default',
bySourceHandle: {
every: {
type: 'object',
properties: {
selectedBranch: {
type: 'string',
title: 'Selected Branch',
description: 'Label of the branch that was taken',
},
branchIndex: {
type: 'number',
title: 'Branch Index',
description: 'Zero-based index of the selected branch',
},
},
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export const defaultPropertiesData: Required<NodeDataProperties<DelayNodeSchema>
expression: 'order.processing_time * 2',
},
type: delayTypeOptions.fixed.value,
untilDate: '',
};
9 changes: 2 additions & 7 deletions apps/demo/src/app/data/nodes/delay/delay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { PaletteItem } from '@workflowbuilder/sdk';

import { defaultPropertiesData } from './default-properties-data';
import { type DelayNodeSchema, schema } from './schema';
import { schemaOutput } from './schema-output';
import { uischema } from './uischema';

export const delay: PaletteItem<DelayNodeSchema> = {
Expand All @@ -11,12 +12,6 @@ export const delay: PaletteItem<DelayNodeSchema> = {
icon: 'Timer',
defaultPropertiesData,
schema,
schemaOutput,
uischema,
outputSchema: {
type: 'default',
properties: {
resumedAt: { type: 'string', label: 'Resumed At', description: 'ISO 8601 date-time when the delay ended' },
delayDuration: { type: 'number', label: 'Delay Duration', description: 'Actual wait time in milliseconds' },
},
},
};
23 changes: 23 additions & 0 deletions apps/demo/src/app/data/nodes/delay/schema-output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { NodeSchemaOutput } from '@workflowbuilder/sdk';

export const schemaOutput: NodeSchemaOutput = {
type: 'default',
bySourceHandle: {
success: {
type: 'object',
properties: {
resumedAt: {
type: 'string',
format: 'date-time',
title: 'Resumed At',
description: 'ISO 8601 date-time when the delay ended',
},
delayDuration: {
type: 'number',
title: 'Delay Duration',
description: 'Actual wait time in milliseconds',
},
},
},
},
};
3 changes: 3 additions & 0 deletions apps/demo/src/app/data/nodes/delay/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export const schema = {
},
},
},
untilDate: {
type: 'string',
},
},
...conditionalValidation,
} satisfies NodeSchema;
Expand Down
21 changes: 21 additions & 0 deletions apps/demo/src/app/data/nodes/delay/uischema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ const dynamicDelayProperties: PaletteItem<DelayNodeSchema>['uischema'] = {
],
};

const untilSpecificProperties: PaletteItem<DelayNodeSchema>['uischema'] = {
rule: {
effect: 'SHOW',
condition: {
scope: scope('properties.type'),
schema: { const: delayTypeOptions.untilSpecific.value },
},
},
type: 'Accordion',
label: 'Date/Time',
elements: [
{
type: 'VariableDynamic',
scope: scope('properties.untilDate'),
label: 'Wait until',
variableType: 'date',
},
],
};

export const uischema: UISchema = {
type: 'VerticalLayout',
elements: [
Expand All @@ -102,5 +122,6 @@ export const uischema: UISchema = {
...(generalInformation ? [generalInformation] : []),
fixedDelayProperties,
dynamicDelayProperties,
untilSpecificProperties,
],
};
Loading
Loading