Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion DECISION-LOGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- _07.08.2026_: [Keep the postcss box-sizing plugin over lint-based or selector-based alternatives](./packages/ui/postcss-box-sizing.decision-log.md)
- _24.08.2026_: [`incomplete` as a third terminal state, distinct from `failed` and from a stall](./packages/execution-core/terminal-states.decision-log.md)
- _31.08.2026_: [Ship common font faces inline and the rest as assets](./packages/ui/font-assets.decision-log.md)
- _07.09.2026 (shape), 08.09.2026 (names), 10.09.2026 (endpoint), 17.09.2026 (ports), 21.09.2026 (outcome)_: [Decision request as versioned data on a node](./apps/backend/decision-request.decision-log.md)
- _07.09.2026 (shape), 08.09.2026 (names), 10.09.2026 (endpoint), 17.09.2026 (ports), 21.09.2026 (outcome), 29.09.2026 (failure policy, edit shape)_: [Decision request as versioned data on a node](./apps/backend/decision-request.decision-log.md)
- _07.09.2026 (revised 14.09.2026, 15.09.2026 and 16.09.2026)_: [Derive the ConnectableItem width from the real container insets](./packages/sdk/src/features/diagram/nodes/components/connectable-item/connectable-item-width.decision-log.md)
- _08.09.2026 (pause), 21.09.2026 (outcome)_: [Durable pause, the Temporal side of the human-in-the-loop seam](./packages/temporal/src/workflow/durable-pause.decision-log.md)
- _01.10.2026_: [One model for the built-in interface: state, actions, builtInControls, …Content, …MenuItem](./packages/sdk/src/features/ui-extensions/ui-extensions.decision-log.md)
12 changes: 7 additions & 5 deletions apps/demo/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ Nodes are registered in `src/app/data/palette.ts` (flat array of `PaletteItem`).

Plugins live in `src/app/plugins/<plugin-name>/` and register via SDK decorators inside `<plugin-name>/plugin-exports.ts`:

| Decorator | Purpose |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `registerComponentDecorator(name, opts)` | Inject UI or hooks into a known slot (`OptionalHooks`, `OptionalAppChildren`, `OptionalNodeContent`, `OptionalAppBarTools`, …) |
| `registerFunctionDecorator(name, opts)` | Intercept a registered function (e.g. `getPaletteData`, `getTemplates`) before/after |
| `registerPluginTranslation(resource)` | Add i18next strings under the `plugins.<name>` namespace |
| Decorator | Purpose |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `registerComponentDecorator(name, opts)` | Inject UI or hooks into a known slot (`OptionalHooks`, `OptionalAppChildren`, `OptionalNodeContent`, `OptionalEdgeProperties`, …) |
| `registerFunctionDecorator(name, opts)` | Intercept a registered function (e.g. `getPaletteData`, `getTemplates`) before/after |
| `registerPluginTranslation(resource)` | Add i18next strings under the `plugins.<name>` namespace |

Plugin signature is `() => void` and the function runs once on first mount of `<WorkflowBuilder.Root plugins={[...]} />` (invoked synchronously inside a `useRef`-guarded first-render branch; deduplicated by `name` on strict-mode double-invoke).

To add UI to the app bar, the palette or the properties panel, prefer the `…Content` / `…MenuItem` components and `builtInControls` over a decorator - see the SDK's [Built-in interface: hide, move, add](https://www.workflowbuilder.io/docs/guides/build-a-plugin/#built-in-interface-hide-move-add). The slots `OptionalAppBarTools`, `OptionalAppBarControls` and `OptionalFooterContent`, and the `getControlsDotsItems` function decorator, still work but are deprecated in favor of that model.

Reference plugins:

- `flow-runner/` — in-browser execution via callable logic registry (Zustand)
Expand Down
52 changes: 41 additions & 11 deletions apps/demo/src/app/plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,61 @@ You can compare it with your local version.

If you want to see how the plugin logic works in a smaller example, we have prepared a showcase repository: https://github.com/synergycodes/optional-plugins-demo

> **Note:** `OptionalAppBarTools`, `OptionalAppBarControls` and `OptionalFooterContent` (used as example slots in some of the sections below) are deprecated in favor of the SDK's `…Content` components (`AppBarToolsContent`, `AppBarControlsContent`, `PaletteFooterContent`, …) and `builtInControls`. They keep working. See [Built-in interface: hide, move, add](https://www.workflowbuilder.io/docs/guides/build-a-plugin/#built-in-interface-hide-move-add) for the current way to add UI to the app bar, the palette or the properties panel.

## How to add plugin?

1. Create your plugin directory, for example: `plugins/example`.
2. Add your `<ExampleComponent />` to `plugins/example/components/example-component.tsx`.
3. In `plugins/example/plugin-exports` import dependencies and add:
2. Add your `<ExampleComponent />` to `plugins/example/components/example-component.tsx`:

```tsx
export function ExampleComponent() {
return <button>Example</button>;
}
```

3. Add `<ExampleControls />` to `plugins/example/components/example-controls/example-controls.tsx`, placing `ExampleComponent` where you want it to show up:

```tsx
import { PaletteFooterContent } from '@workflowbuilder/sdk';

import { ExampleComponent } from '../example-component';

export function ExampleControls() {
return (
<PaletteFooterContent>
<ExampleComponent />
</PaletteFooterContent>
);
}
```

4. In `plugins/example/plugin-exports.ts`, mount it through `OptionalAppChildren` (a plugin file is `.ts`, so the JSX itself lives in the `.tsx` components above):

```ts
registerComponentDecorator('OptionalFooterContent', {
content: ExampleComponent,
place: 'after',
});
import { registerComponentDecorator } from '@workflowbuilder/sdk';

import { ExampleControls } from './components/example-controls/example-controls';

export function plugin(): void {
registerComponentDecorator('OptionalAppChildren', {
content: ExampleControls,
});
}
```

4. Import your plugin to `apps/demo/src/app/features/plugins-core/index.ts` with line `import '@/plugins/example/plugin-exports';`
5. Refresh the page.
5. Import your plugin into `apps/demo/src/app/app.tsx` and add it to the `plugins` array passed to `<WorkflowBuilder.Root>`, the same way the existing plugins there are wired in: `import { plugin as examplePlugin } from './plugins/example/plugin-exports';`, then add `examplePlugin` to the `plugins={[...]}` list.
6. Refresh the page.

Your component should now be displayed in the left sidebar (palette) footer.
Your component should now be displayed in the left sidebar (palette) footer, before the built-in Templates button.

### How to remove plugin?

Simply remove the folder of your plugin and restart the application. It will still work with empty stubs instead of registration.

#### How to remove "Fallback used for missing plugin..."?

Go to `apps/demo/src/app/features/plugins-core/index.ts` and remove the import there.
Go to `apps/demo/src/app/app.tsx` and remove the plugin's import and its entry from the `plugins` array.

### How do I change the position of a plugin?

Expand Down Expand Up @@ -135,4 +165,4 @@ if (hasRegisteredComponentDecorator('OptionalAppBarControls', 'TreeButton')) {
}
```

The order in which plugins are imported in @features/plugins-core/index is important.
The order in which plugins are listed in `app.tsx`'s `plugins` array is important.
2 changes: 1 addition & 1 deletion apps/demo/src/app/plugins/help/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Removal of this plugin will result in an application without the watermark in th

The application can run without this folder by using stub files.

If you want to remove references to the stubs, you can also delete the line where it was imported from: `apps/demo/src/app/features/plugins-core/index.ts`
If you want to remove references to the stubs, you can also delete the line where it is registered: `helpPlugin` in the `plugins` array of `apps/demo/src/app/app.tsx`, together with its import.
Loading
Loading