aspnetzero-workflow-designer 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +245 -3
- package/dist/index.d.ts +1806 -0
- package/dist/workflow-designer.js +25927 -0
- package/dist/workflow-designer.js.map +1 -0
- package/dist/workflow-designer.umd.cjs +3381 -0
- package/dist/workflow-designer.umd.cjs.map +1 -0
- package/package.json +41 -6
package/README.md
CHANGED
|
@@ -1,3 +1,245 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# aspnetzero-workflow-designer
|
|
2
|
+
|
|
3
|
+
Framework-neutral custom elements for the ASP.NET Zero workflow & approval builder.
|
|
4
|
+
One implementation, wrapped by Angular, React and ASP.NET Core MVC — so the three UIs cannot drift apart.
|
|
5
|
+
|
|
6
|
+
## Elements
|
|
7
|
+
|
|
8
|
+
| Tag | Purpose |
|
|
9
|
+
|---|---|
|
|
10
|
+
| `<workflow-designer>` | Graph editor for `WorkflowGraphDocument` (steps, transitions, layout) |
|
|
11
|
+
| `<workflow-form-builder>` | Form editor for `WorkflowFormDocument` (sections, fields, validation) |
|
|
12
|
+
|
|
13
|
+
Both are registered automatically on import.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import 'aspnetzero-workflow-designer';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## The host contract
|
|
20
|
+
|
|
21
|
+
The component is **pure**: documents in, documents out. It never knows the host's auth token, tenant id
|
|
22
|
+
or API base URL, and it makes no HTTP calls of its own. Everything reaches it through properties, and
|
|
23
|
+
everything leaves it through events.
|
|
24
|
+
|
|
25
|
+
### Properties (set as JS properties, not attributes)
|
|
26
|
+
|
|
27
|
+
| Property | Type | Purpose |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `document` | `WorkflowGraphDocument` / `WorkflowFormDocument` | The canonical document to edit |
|
|
30
|
+
| `localization` | `Record<string, string>` | Host's localization dictionary |
|
|
31
|
+
| `theme` | `WorkflowThemeTokens` | Colour and font tokens; mapped to CSS custom properties |
|
|
32
|
+
| `permissions` | `{ canEdit?, canPublish?, canSimulate? }` | `canEdit: false` puts the editor in read-only mode |
|
|
33
|
+
| `capabilities` | `{ maxSteps?, maxFormFields?, publicFormEnabled?, ... }` | Edition limits and feature switches; see [Capabilities](#capabilities) |
|
|
34
|
+
| `lookups` | `{ users?, roles?, organizationUnits?, ... }` | Async callbacks the host provides for pickers |
|
|
35
|
+
| `validationIssues` | `WorkflowValidationIssue[]` | Server validation results; rendered inline on the offending node/field |
|
|
36
|
+
| `form` (designer only) | `WorkflowFormDocument` | The workflow's form, so conditions and mappings can pick its fields |
|
|
37
|
+
| `formBuilder` (designer only) | `WorkflowFormBuilderElement` | The `<workflow-form-builder>` editing the same form, so `focusValidationIssue` can hand field issues to it |
|
|
38
|
+
|
|
39
|
+
Hosts may re-assign any of these as often as they like (React effects, Angular change detection). A value
|
|
40
|
+
whose content equals the previous one is accepted without a re-render, and `document` is compared with the
|
|
41
|
+
document the element last emitted, so handing back the `document-change` detail is a no-op. When a real
|
|
42
|
+
change does re-render the element while the user is typing, the focused input keeps its focus, caret and
|
|
43
|
+
not yet committed text.
|
|
44
|
+
|
|
45
|
+
### Capabilities
|
|
46
|
+
|
|
47
|
+
Every boolean switch except `publicFormEnabled` counts as available unless the host sets it to `false`.
|
|
48
|
+
|
|
49
|
+
| Capability | Meaning |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `maxSteps`, `maxFormFields` | Edition limits; the editors refuse to add beyond them |
|
|
52
|
+
| `advancedApprovalsEnabled`, `externalActionsEnabled`, `eventWaitEnabled`, `slackEnabled`, `teamsEnabled` | Hide the steps and inputs that need the feature when `false` |
|
|
53
|
+
| `attachmentsEnabled` | `false` hides the file attachment field and the attachment inputs |
|
|
54
|
+
| `publicFormEnabled` | **Opt-in.** Files can only be collected on a public form, so the form builder offers the file attachment field only when this is `true` (and `attachmentsEnabled` is not `false`). Leaving it out means "not a public form". A file attachment field already on such a form stays, with an inline warning on its card. |
|
|
55
|
+
|
|
56
|
+
Assigning a new `capabilities` object to the live element re-renders the palettes.
|
|
57
|
+
|
|
58
|
+
### Lookups and the assistant
|
|
59
|
+
|
|
60
|
+
The element never lets a host callback fail loudly: a rejected or throwing lookup yields an empty list, and
|
|
61
|
+
an identical lookup (same provider, filter and context) that is still in flight is shared rather than sent
|
|
62
|
+
again, so re-renders and quickly opened dropdowns do not flood the host. The assistant buttons
|
|
63
|
+
(`suggestCondition`, `summarizeWorkflow`) are disabled while their request runs. A result with
|
|
64
|
+
`succeeded: false` shows its `failureReason` inline as a soft warning (hosts should resolve with that
|
|
65
|
+
shape for "assistant not available" or rate limits rather than reject); a rejected request shows a generic
|
|
66
|
+
inline warning.
|
|
67
|
+
|
|
68
|
+
### Theming and sizing
|
|
69
|
+
|
|
70
|
+
The canvas is SVG drawn from JavaScript, so node, port, label, execution and heat-map colours are derived
|
|
71
|
+
from the resolved theme tokens (`--wf-surface`, `--wf-text`, `--wf-primary`, `--wf-success`,
|
|
72
|
+
`--wf-warning`, `--wf-danger`, ...; by default the Bootstrap/Metronic `--bs-*` variables). Status colours
|
|
73
|
+
are tinted over the surface colour, so a dark theme gets dark nodes. Changing `theme` or the document's
|
|
74
|
+
`data-bs-theme`/`data-theme` attribute redraws the canvas.
|
|
75
|
+
|
|
76
|
+
The editor needs at least `--wf-designer-min-height` (default `560px`); read-only views (instance
|
|
77
|
+
timeline, template preview, heat map) need only `--wf-designer-readonly-min-height` (default `320px`), so
|
|
78
|
+
they fit a shorter host box. The minimap stays inside the canvas and is hidden when the canvas is too
|
|
79
|
+
small to hold it.
|
|
80
|
+
|
|
81
|
+
### Events
|
|
82
|
+
|
|
83
|
+
| Event | Detail | Meaning |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `document-change` | `{ document, isDirty }` | The user edited the document |
|
|
86
|
+
| `selection-change` | `{ nodeId? , fieldId? }` | Selection moved |
|
|
87
|
+
| `command` | `{ command: 'save' \| 'validate' \| 'simulate' \| 'publish' }` | The user asked the host to run a host-owned action |
|
|
88
|
+
|
|
89
|
+
| `issue-focus` | `WorkflowIssueFocusDetail` = `{ tab: 'flow' \| 'form' \| 'trigger', issue, nodeId?, edgeId?, branchId?, fieldId?, inputName? }` | `focusValidationIssue` resolved an issue; show this host tab |
|
|
90
|
+
|
|
91
|
+
The host owns save/validate/simulate/publish. The component only *asks*.
|
|
92
|
+
|
|
93
|
+
### Methods
|
|
94
|
+
|
|
95
|
+
| Method | Element | Purpose |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `focusValidationIssue(issue: WorkflowValidationIssue): boolean` | both | Shows what a validation issue is about (see below) |
|
|
98
|
+
|
|
99
|
+
`focusValidationIssue` takes one of the objects the host passes through `validationIssues` (`code`,
|
|
100
|
+
`nodeId`, `edgeId`, `fieldId`, `branchId`) and returns `true` when something was focused:
|
|
101
|
+
|
|
102
|
+
- On `<workflow-designer>`, a step, transition or branch issue selects it on the canvas, opens the
|
|
103
|
+
inspector tab holding the setting the issue's code names (an `SlaDurationInvalid` issue opens
|
|
104
|
+
*Service level*, an `ApprovalNodeTargetMissing` issue *Assignment*, and so on) and pans the canvas
|
|
105
|
+
until the step is visible. A field issue is handed to the element in `formBuilder` when the host set
|
|
106
|
+
one; a start-trigger issue (`ResponsibleUser...`, `StartTrigger...`, public form slug and embed origin
|
|
107
|
+
codes) is left to the host's trigger tab. In every case the element dispatches `issue-focus` whose
|
|
108
|
+
`tab` says which of the host's tabs (`flow`, `form`, `trigger`) holds the issue — the element has no
|
|
109
|
+
tabs of its own, so the host switches.
|
|
110
|
+
- On `<workflow-form-builder>`, a field issue selects the field, scrolls its row into view and
|
|
111
|
+
dispatches `issue-focus` with `tab: 'form'`.
|
|
112
|
+
- Ids neither document knows return `false` and dispatch nothing, so a stale issue list is harmless.
|
|
113
|
+
- Calling it before the element has rendered (not yet connected, or the document not yet set) is fine:
|
|
114
|
+
the focus is applied by the first render. Ids are still checked against the documents the element
|
|
115
|
+
holds at call time, so set `document` (and `form`) first.
|
|
116
|
+
|
|
117
|
+
The inline issue list in the designer's inspector uses the same method: every issue is a button
|
|
118
|
+
(keyboard reachable) that opens the tab holding the setting it is about.
|
|
119
|
+
|
|
120
|
+
A typical host wiring:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
designer.formBuilder = formBuilder;
|
|
124
|
+
designer.addEventListener('issue-focus', (event) => showTab(event.detail.tab));
|
|
125
|
+
|
|
126
|
+
issueRow.addEventListener('click', () => designer.focusValidationIssue(issue));
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Canonical schema
|
|
130
|
+
|
|
131
|
+
`src/schema/workflow-schema.ts` mirrors the product-owned C# contract
|
|
132
|
+
(`WorkflowGraphDocument`, `WorkflowFormDocument` and friends) — **not** any graph library's internal model.
|
|
133
|
+
Swapping the rendering library must never change the persisted JSON.
|
|
134
|
+
|
|
135
|
+
## Example
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<workflow-designer id="designer"></workflow-designer>
|
|
139
|
+
<script type="module">
|
|
140
|
+
import 'aspnetzero-workflow-designer';
|
|
141
|
+
|
|
142
|
+
const designer = document.getElementById('designer');
|
|
143
|
+
|
|
144
|
+
designer.localization = { WorkflowNodeType_Approval: 'Onay' };
|
|
145
|
+
designer.permissions = { canEdit: true };
|
|
146
|
+
designer.capabilities = { maxSteps: 40 };
|
|
147
|
+
designer.document = serverGraphDocument;
|
|
148
|
+
|
|
149
|
+
designer.addEventListener('document-change', (event) => {
|
|
150
|
+
draft.graph = event.detail.document;
|
|
151
|
+
});
|
|
152
|
+
</script>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Development
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npm install
|
|
159
|
+
npm run dev # demo page at demo/index.html
|
|
160
|
+
npm run typecheck
|
|
161
|
+
npm test # vitest suite under test/
|
|
162
|
+
npm run build # ESM + UMD + rolled-up .d.ts into dist/
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Rendering uses [AntV X6](https://x6.antv.antgroup.com/) — a vanilla-JS graph library, chosen precisely
|
|
166
|
+
because it carries no framework dependency and therefore works identically inside all three host UIs.
|
|
167
|
+
|
|
168
|
+
### How the hosts get the designer
|
|
169
|
+
|
|
170
|
+
The hosts never use this folder. All three install the published `aspnetzero-workflow-designer` package
|
|
171
|
+
from npm, so the three UIs run the same build:
|
|
172
|
+
|
|
173
|
+
| Host | How it gets the designer |
|
|
174
|
+
|---|---|
|
|
175
|
+
| Angular (`angular/`) | `aspnetzero-workflow-designer` dependency, imports the ESM build |
|
|
176
|
+
| React (`react/`) | `aspnetzero-workflow-designer` dependency, imports the ESM build |
|
|
177
|
+
| ASP.NET Core MVC (`Web.Mvc`) | `aspnetzero-workflow-designer` dependency; `bundles.json` turns `dist/workflow-designer.umd.cjs` into `_Bundles/workflow-designer.min.js` |
|
|
178
|
+
|
|
179
|
+
### Releasing a change
|
|
180
|
+
|
|
181
|
+
1. Change the package, then run `npm test` and `npm run build`.
|
|
182
|
+
2. Raise `version` in `package.json` (a new step kind or input is a minor version, a fix a patch).
|
|
183
|
+
3. Run `npm publish`. `prepublishOnly` runs the tests and the build again, so a broken package is not
|
|
184
|
+
published.
|
|
185
|
+
4. In `angular/`, `react/` and `aspnet-core/src/MyCompanyName.AbpZeroTemplate.Web.Mvc/`, run
|
|
186
|
+
`pnpm update aspnetzero-workflow-designer` and commit the lockfiles with the server change that
|
|
187
|
+
needed the new version.
|
|
188
|
+
|
|
189
|
+
`WorkflowNodeTypeContract_Tests` and the other contract tests in the server test project read this
|
|
190
|
+
folder's `src/`, so the server and the designer can not drift apart unnoticed.
|
|
191
|
+
|
|
192
|
+
### Trying a change in a host before publishing
|
|
193
|
+
|
|
194
|
+
Point a host at this folder for the time being:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
cd angular # or react
|
|
198
|
+
pnpm link ../workflow-designer
|
|
199
|
+
|
|
200
|
+
cd aspnet-core/src/MyCompanyName.AbpZeroTemplate.Web.Mvc
|
|
201
|
+
pnpm link ../../../workflow-designer
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The host now reads this folder's `dist/`, so run `npm run build` here after each change (MVC also needs
|
|
205
|
+
`npm run create-bundles`). `pnpm link` adds a `link:` override to the host's `pnpm-workspace.yaml` and
|
|
206
|
+
changes its `pnpm-lock.yaml`; do not commit those. To go back to the published package, revert both files
|
|
207
|
+
and run `pnpm install`.
|
|
208
|
+
|
|
209
|
+
## Status
|
|
210
|
+
|
|
211
|
+
What the package implements today:
|
|
212
|
+
|
|
213
|
+
**Workflow designer**
|
|
214
|
+
|
|
215
|
+
- Node palette (click or drag onto the canvas), canvas with pan/zoom/grid, zoom to fit, minimap,
|
|
216
|
+
snaplines, auto layout and an outline panel.
|
|
217
|
+
- Node add/move/select/delete, multi-select, edge drawing with automatic edge-kind assignment per source
|
|
218
|
+
node type, parallel fan-out nodes paired with their join node.
|
|
219
|
+
- Undo/redo and copy/paste (toolbar and keyboard shortcuts).
|
|
220
|
+
- A descriptor-driven properties inspector, grouped into tabs by input category (for example
|
|
221
|
+
Assignment, Behaviour, Service level, Delivery), with editors resolved by `uiHint` through the input
|
|
222
|
+
editor registry.
|
|
223
|
+
- Condition branches: add, remove and reorder branches, and a condition builder over form fields,
|
|
224
|
+
variables and step outputs; optional assistant suggestions through `lookups.suggestCondition`.
|
|
225
|
+
- Assignee pickers (requester's manager, user, role, organization unit, fallback role) wired to the
|
|
226
|
+
host lookups (`lookups.optionsProvider`, or the older `users`/`roles`/`organizationUnits` callbacks).
|
|
227
|
+
- SLA editing (the "Service level" tab; "Escalate after" and "Escalate to" appear once escalation is
|
|
228
|
+
switched on), notification recipients, chat channels (Slack / Teams) with
|
|
229
|
+
adaptive card editing, secret pickers, action parameter and event payload mapping tables.
|
|
230
|
+
- Workflow variables panel, inline validation issues, and an optional assistant workflow summary
|
|
231
|
+
(`lookups.summarizeWorkflow`).
|
|
232
|
+
|
|
233
|
+
**Form builder**
|
|
234
|
+
|
|
235
|
+
- Field palette, field add/reorder/remove, sections (add, rename, remove; removing a section moves its
|
|
236
|
+
fields to the section above it), repeater fields with row fields and calculated fields.
|
|
237
|
+
- The file attachment field only on public forms (`capabilities.publicFormEnabled: true`).
|
|
238
|
+
- A descriptor-driven properties panel for label/key/required/validation, and a row-per-option editor
|
|
239
|
+
for single and multi select options.
|
|
240
|
+
- A new field's key is derived from its label (`Total amount` becomes `totalAmount`; accented and
|
|
241
|
+
Turkish letters are folded to ASCII, a key starts with a letter and is made unique with `2`, `3`, ...)
|
|
242
|
+
and keeps following the label until the user edits the key by hand. Keys that arrived with the
|
|
243
|
+
document are never changed.
|
|
244
|
+
- A palette note that signed-in requesters attach files from the request page, since the file
|
|
245
|
+
attachment field exists only for public forms.
|