Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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
6 changes: 4 additions & 2 deletions apps/ai-studio/src/nodes/ai-agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ export const aiAgentPaletteItem: PaletteItem<AiAgentSchema> = {
// Lets `{{ nodes.<id>.response }}` references resolve to a real mention instead of a "missing mention" pill.
outputSchema: {
type: 'default',
properties: {
response: { type: 'string', label: 'Response', description: 'The text generated by the AI model' },
bySourceHandle: {
success: {
response: { type: 'string', label: 'Response', description: 'The text generated by the AI model' },
},
},
},
};
17 changes: 15 additions & 2 deletions apps/demo/src/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import type {
WorkflowBuilderNodeTemplates,
WorkflowBuilderReactFlowProps,
} from '@workflowbuilder/sdk';
import { SnackbarType } from '@workflowbuilder/ui';

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

import { showSnackbar } from '../../../../packages/sdk/src/utils/show-snackbar';
import { DashedEdge } from './components/dashed-edge/dashed-edge';
import { MultiPortNodeTemplate } from './components/multi-port-node/multi-port-node-template';
import { demoPaletteItems } from './data/palette';
Expand Down Expand Up @@ -35,8 +37,19 @@ const edgeTemplates = {
dashed: DashedEdge,
} satisfies WorkflowBuilderEdgeTemplates;

// A trigger is a workflow entry point, so it can never be a connection target.
const isValidConnection: WorkflowBuilderIsValidConnection = ({ targetNode }) => targetNode.data.type !== 'trigger';
const isValidConnection: WorkflowBuilderIsValidConnection = ({ targetNode }) => {
// A trigger is a workflow entry point, so it can never be a connection target.
if (targetNode.data.type === 'trigger') {
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
13 changes: 9 additions & 4 deletions apps/demo/src/app/data/nodes/action/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@ export const action: PaletteItem<ActionNodeSchema> = {
uischema,
outputSchema: {
type: 'default',
properties: {
status: { type: 'string', label: 'Status', description: 'Execution status: success, failure, or skipped' },
result: { type: 'object', label: 'Result', description: 'The data returned by the action' },
errorMessage: { type: 'string', label: 'Error Message', description: 'Error details if the action failed' },
bySourceHandle: {
success: {
status: { type: 'string', label: 'Status', description: 'Execution status: success, failure, or skipped' },
// TODO: outputSchema and schema properties should support the full JsonSchema7 type imported from @jsonforms/core to build suggestions not only for objects but also for their variables.
Comment thread
szymon-t-sc marked this conversation as resolved.
Outdated
result: { type: 'object', label: 'Result', description: 'The data returned by the action' },
},
error: {
errorMessage: { type: 'string', label: 'Error Message', description: 'Error details if the action failed' },
},
},
},
};
8 changes: 4 additions & 4 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 Down
10 changes: 6 additions & 4 deletions apps/demo/src/app/data/nodes/ai-agent/ai-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ export const aiAgent: PaletteItem = {
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' },
bySourceHandle: {
success: {
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' },
},
},
},
};
14 changes: 8 additions & 6 deletions apps/demo/src/app/data/nodes/conditional/conditional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ export const conditional: PaletteItem<ConditionalNodeSchema> = {
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',
bySourceHandle: {
success: {
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',
},
},
},
},
Expand Down
8 changes: 5 additions & 3 deletions apps/demo/src/app/data/nodes/decision/decision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ export const decision: PaletteItem<DecisionNodeSchema> = {
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' },
bySourceHandle: {
every: {
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' },
},
},
},
};
8 changes: 5 additions & 3 deletions apps/demo/src/app/data/nodes/delay/delay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ export const delay: PaletteItem<DelayNodeSchema> = {
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' },
bySourceHandle: {
success: {
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' },
},
},
},
};
14 changes: 10 additions & 4 deletions apps/demo/src/app/data/nodes/notification/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ export const notification: PaletteItem<NotificationNodeSchema> = {
uischema,
outputSchema: {
type: 'default',
properties: {
sent: { type: 'boolean', label: 'Sent', description: 'Whether the notification was sent successfully' },
sentAt: { type: 'string', label: 'Sent At', description: 'ISO 8601 date-time when the notification was sent' },
recipient: { type: 'string', label: 'Recipient', description: 'The email address the notification was sent to' },
bySourceHandle: {
success: {
sent: { type: 'boolean', label: 'Sent', description: 'Whether the notification was sent successfully' },
sentAt: { type: 'string', label: 'Sent At', description: 'ISO 8601 date-time when the notification was sent' },
recipient: {
type: 'string',
label: 'Recipient',
description: 'The email address the notification was sent to',
},
},
},
},
};
64 changes: 58 additions & 6 deletions apps/demo/src/app/data/nodes/trigger/trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,63 @@ export const triggerNode: PaletteItem<TriggerNodeSchema> = {
schema,
uischema,
outputSchema: {
type: 'default',
properties: {
eventType: { type: 'string', label: 'Event Type', description: 'The type of event that started the workflow' },
timestamp: { type: 'string', label: 'Timestamp', description: 'ISO 8601 date-time when the trigger fired' },
payload: { type: 'object', label: 'Payload', description: 'The raw event data received by the trigger' },
},
type: 'variant',
variants: [
{
variantRule: undefined,
bySourceHandle: {
every: {
eventType: {
type: 'string',
label: 'Event Type',
description: 'The type of event that started the workflow',
},
timestamp: { type: 'string', label: 'Timestamp', description: 'ISO 8601 date-time when the trigger fired' },
},
},
},
{
variantRule: {
dataPropertyName: 'type',
dataPropertyValue: 'timeBasedTrigger',
},
bySourceHandle: {
success: {
allDay: {
type: 'boolean',
label: 'All day event',
description: 'The type of event that started the workflow',
},
startDate: {
type: 'date',
label: 'Start date',
description: 'The date when the event was scheduled to start',
},
endDate: {
type: 'date',
label: 'End date',
description: 'The date when the event was scheduled to end',
},
},
},
},
{
variantRule: {
dataPropertyName: 'type',
dataPropertyValue: 'eventBasedTrigger',
},
bySourceHandle: {
success: {
typeOfEventType: {
type: 'string',
label: 'Type of event type',
description: 'For example: form submission, user action etc.',
},
},
},
},
],
},
};

// payload: { type: 'object', label: 'Payload', description: 'The raw event data received by the trigger' },
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { Icon } from '@workflow-builder/icons';

import styles from '../../app-bar.module.css';

import { openModalWorkflowSettings } from '../../../../features/variables/modals/modal-settings';
import { useStore } from '../../../../store/store';
import { withOptionalComponentPlugins } from '../../../plugins-core/adapters/adapter-components';
import { openModalWorkflowSettings } from '../../../variables/modals/global/modal-settings';

/**
* Props accepted by {@link ProjectSelection}. Use this when typing a
Expand Down
3 changes: 3 additions & 0 deletions packages/sdk/src/features/diagram/diagram.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type { WorkflowBuilderReactFlowProps } from '../../workflow-builder-root/
import { trackFutureChange } from '../changes-tracker/stores/use-changes-tracker-store';
import { useDeleteConfirmation } from '../modals/delete-confirmation/use-delete-confirmation';
import { withOptionalComponentPlugins } from '../plugins-core/adapters/adapter-components';
import useRefreshVariables from '../variables/hooks/use-refresh-variables';
import { deleteKeyCode } from './const';
import { SNAP_GRID, SNAP_IS_ACTIVE } from './diagram.const';
import { TemporaryEdge } from './edges/temporary-edge/temporary-edge';
Expand Down Expand Up @@ -126,6 +127,8 @@ function DiagramContainerComponent({ edgeTypes = {} }: DiagramContainerProps) {
[onDropFromPalette],
);

useRefreshVariables();

const { onConnect, onConnectStart, onConnectEnd } = useConnect();

const onNodeDragStop = useCallback(() => {
Expand Down
6 changes: 6 additions & 0 deletions packages/sdk/src/features/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ export const en = {
variableNotFound: 'Variable not found.',
removeVariableWarning: 'Deleting this variable will permanently remove its configuration.',
removeVariableIsBlocked: 'The variable is used in the following nodes and cannot be deleted.',
addVariableToContinue: 'Add a variable to continue',
missingMentionNodePrefix: 'Missing node',
missingMentionNodeVariablePrefix: 'Missing variable',
},
loader: {
text: 'Loading...',
Expand Down Expand Up @@ -181,7 +184,10 @@ export const en = {
wrongDiagramFormat: 'Wrong diagram format',
contentCopied: 'Content copied to clipboard',
variablesListIsEmpty: 'The list of available variables is empty.',
variableNameAlreadyExists: 'A variable with this name already exists.',
variableWasNotFound: 'This variable was not found.',
cantEditReadOnlyMode: 'Editing is blocked in read-only mode.',
notValidConnection: 'That connection is blocked.',
},
workflowsSettings: {
modalTitle: 'Settings',
Expand Down
6 changes: 6 additions & 0 deletions packages/sdk/src/features/i18n/locales/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ export const pl = {
variableNotFound: 'Nie znaleziono zmiennej.',
removeVariableWarning: 'Usunięcie tej zmiennej trwale usunie jej konfigurację.',
removeVariableIsBlocked: 'Ta zmienna jest używana w następujących węzłach i nie może zostać usunięta.',
addVariableToContinue: 'Dodaj zmienną aby kontynuować',
missingMentionNodePrefix: 'Brak węzła',
missingMentionNodeVariablePrefix: 'Brak zmiennej',
},
loader: {
text: 'Ładowanie...',
Expand Down Expand Up @@ -145,7 +148,10 @@ export const pl = {
wrongDiagramFormat: 'Nieprawidłowy format diagramu',
contentCopied: 'Treść skopiowana do schowka',
variablesListIsEmpty: 'Lista dostępnych zmiennych jest pusta.',
variableNameAlreadyExists: 'Zmienna o tej nazwie już istnieje.',
variableWasNotFound: 'Nie znaleziono tej zmiennej.',
cantEditReadOnlyMode: 'Edycja jest zablokowana w trybie tylko do odczytu.',
notValidConnection: 'To połączenie jest zablokowane.',
},
aiTools: {
title: 'Narzędzia agenta AI',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import styles from './dependencies.module.css';

import { FormControlWithLabel } from '../../../../../components/form/form-control-with-label/form-control-with-label';
import { useSingleSelectedElement } from '../../../../../features/properties-bar/use-single-selected-element';
import { conditionsToDependencies } from '../../../../../features/variables/actions/conditions';
import { VariableText } from '../../../../../features/variables/components/variable-text/variable-text';
import { useAvailableVariables } from '../../../../../features/variables/hooks/use-available-variables';
import type { DynamicCondition } from '../../../../../types/controls';
import { noop } from '../../../../../utils/noop';
import { conditionsToDependencies } from '../../../utils/conditional-transform';

type Props = {
conditions: DynamicCondition[];
Expand All @@ -23,12 +23,13 @@ export function Dependencies({ conditions, onClick, disabled = false, hasError }
}, [conditions]);

const selection = useSingleSelectedElement();
const suggestionGroups = useAvailableVariables(selection?.node?.id);
const { suggestionGroups, totalVariables } = useAvailableVariables(selection?.node?.id);

return (
<FormControlWithLabel label="conditions.dependencies">
<span className={styles['button']} onClick={disabled ? noop : onClick}>
<VariableText
key={totalVariables}
className={styles['list']}
value={dependencies.join(' ')}
onChange={noop}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import { Icon } from '@workflow-builder/icons';

import styles from './conditions-form-field.module.css';

import { type ConditionErrors, getConditionErrors } from '../../../../../features/variables/actions/conditions';
import { getStringType } from '../../../../../features/variables/actions/get-string-type';
import { DynamicTypedVariableOrInput } from '../../../../../features/variables/components/dynamic-typed-variable-or-input/dynamic-typed-variable-or-input';
import { VariableText } from '../../../../../features/variables/components/variable-text/variable-text';
import type { VariableSuggestionGroup } from '../../../../../features/variables/components/variable-text/variable-text.types';
import {
type ComparisonOperator,
LOGICAL_OPERATOR,
comparisonOperatorsByPrimitiveType,
} from '../../../../../features/variables/constants';
import type { VariableTypePrimitive } from '../../../../../node/node-output-schema';
import type { DynamicCondition } from '../../../../../types/controls';
import { getStringVariableTypeIfPossible } from '../../../../variables/actions/get-string-variable-type-if-possible';
import { type ConditionErrors, getConditionErrors } from '../../../../variables/utils/form-validation/conditions';

type ConditionsFormFieldProps = {
condition: Partial<DynamicCondition>;
Expand All @@ -34,7 +35,7 @@ const getTypeOptions = (
xType: VariableTypePrimitive;
comparisonsOperators: ComparisonOperator[];
} => {
const xType = getStringType(value);
const xType = getStringVariableTypeIfPossible(value);
const comparisonsOperators: ComparisonOperator[] = comparisonOperatorsByPrimitiveType[xType] || [];

return {
Expand Down Expand Up @@ -78,11 +79,11 @@ export function ConditionsFormField(props: ConditionsFormFieldProps) {
<SegmentPicker
className={styles['segment-picker']}
size="xx-small"
value={condition.logicalOperator || 'AND'}
value={condition.logicalOperator || LOGICAL_OPERATOR.AND}
onChange={(_, value) => handleChange('logicalOperator', value)}
>
<SegmentPicker.Item value="AND">{t('conditions.compare.all')}</SegmentPicker.Item>
<SegmentPicker.Item value="OR">{t('conditions.compare.one')}</SegmentPicker.Item>
<SegmentPicker.Item value={LOGICAL_OPERATOR.AND}>{t('conditions.compare.all')}</SegmentPicker.Item>
<SegmentPicker.Item value={LOGICAL_OPERATOR.OR}>{t('conditions.compare.one')}</SegmentPicker.Item>
</SegmentPicker>
</div>
)}
Expand Down
Loading
Loading