@formicoidea/labre-framework-bpmn 0.41.0 → 0.43.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/LICENSE +384 -0
- package/dist/actions.js +7 -23
- package/dist/commands.js +201 -39
- package/dist/consts.d.ts +34 -2
- package/dist/consts.js +38 -2
- package/dist/element-view.js +1 -1
- package/dist/export.d.ts +13 -1
- package/dist/export.js +19 -5
- package/dist/import.d.ts +10 -0
- package/dist/import.js +26 -1
- package/dist/interchange.d.ts +34 -0
- package/dist/interchange.js +99 -7
- package/dist/node/node-renderer.js +22 -32
- package/dist/presets.js +4 -3
- package/dist/templates/index.d.ts +1 -1
- package/dist/templates/index.js +7 -6
- package/dist/toolbar/bpmn-senior-button.d.ts +2 -0
- package/dist/toolbar/bpmn-senior-button.js +6 -2
- package/dist/toolbar/config.d.ts +22 -11
- package/dist/toolbar/config.js +39 -39
- package/dist/toolbar/icons.d.ts +9 -2
- package/dist/toolbar/icons.js +9 -6
- package/dist/toolbar/palette.d.ts +23 -0
- package/dist/toolbar/palette.js +65 -0
- package/dist/translations.js +13 -2
- package/dist/view.js +18 -14
- package/package.json +2 -2
package/dist/commands.js
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
|
+
import { StrokeStyle } from '@formicoidea/labre-core/model';
|
|
1
2
|
import { activateBpmnAssociation, activateBpmnMessageFlow, activateBpmnSequenceFlow, addBpmnLane, bpmnLanesOf, bpmnPoolsForLaneEdit, bpmnPoolsSelected, createBpmnNode, createBpmnPool, exportBpmnXmlFile, importBpmnSvgFile, importBpmnXmlFile, removeBpmnLane, } from './actions.js';
|
|
2
|
-
import {
|
|
3
|
+
import { BPMN_EDGE_STYLE, NODE_FILL, NODE_SIZE, } from './consts.js';
|
|
4
|
+
import { bpmnNodeProps } from './presets.js';
|
|
5
|
+
import { BPMN_ROLE, BPMN_ROLE_OF_KIND } from './roles.js';
|
|
6
|
+
import { bpmnAssociationIcon, bpmnCallActivityIcon, bpmnDataObjectIcon, bpmnDataStoreIcon, bpmnEndIcon, bpmnEndMessageIcon, bpmnEndTerminateIcon, bpmnExportXmlIcon, bpmnGatewayIcon, bpmnGatewayParallelIcon, bpmnGroupIcon, bpmnImportSvgIcon, bpmnImportXmlIcon, bpmnLaneAddIcon, bpmnLaneRemoveIcon, bpmnMessageIcon, bpmnPoolIcon, bpmnSequenceIcon, bpmnStartIcon, bpmnStartMessageIcon, bpmnStartTimerIcon, bpmnSubProcessIcon, bpmnTaskIcon, bpmnTaskServiceIcon, bpmnTaskUserIcon, bpmnTextAnnotationIcon, bpmnToolbarIcon, } from './toolbar/icons.js';
|
|
7
|
+
/**
|
|
8
|
+
* What a spec DOES — its own gesture, or the one its {@link Spec.node} implies.
|
|
9
|
+
*
|
|
10
|
+
* Total over {@link SPECS} by inspection, and loud rather than silent if it
|
|
11
|
+
* ever stops being: a spec that drew nothing would be a button that does
|
|
12
|
+
* nothing, which is worse than a module that refuses to load.
|
|
13
|
+
*/
|
|
14
|
+
function gestureOf(spec) {
|
|
15
|
+
if (spec.run)
|
|
16
|
+
return spec.run;
|
|
17
|
+
const kind = spec.node;
|
|
18
|
+
if (!kind) {
|
|
19
|
+
throw new Error(`bpmn: "${spec.id}" declares neither a node kind nor a run`);
|
|
20
|
+
}
|
|
21
|
+
return std => createBpmnNode(std, kind);
|
|
22
|
+
}
|
|
3
23
|
/**
|
|
4
24
|
* Declaration order is DISPLAY order, and past the cap it is also the COLD
|
|
5
25
|
* START — which is why it leads with the canonical core rather than with the
|
|
@@ -40,7 +60,7 @@ const SPECS = [
|
|
|
40
60
|
category: 'events',
|
|
41
61
|
senior: true,
|
|
42
62
|
element: 'node:startEvent',
|
|
43
|
-
|
|
63
|
+
node: 'startEvent',
|
|
44
64
|
},
|
|
45
65
|
{
|
|
46
66
|
id: 'addEndEvent',
|
|
@@ -50,7 +70,7 @@ const SPECS = [
|
|
|
50
70
|
category: 'events',
|
|
51
71
|
senior: true,
|
|
52
72
|
element: 'node:endEvent',
|
|
53
|
-
|
|
73
|
+
node: 'endEvent',
|
|
54
74
|
},
|
|
55
75
|
{
|
|
56
76
|
id: 'addTask',
|
|
@@ -60,7 +80,7 @@ const SPECS = [
|
|
|
60
80
|
category: 'activities',
|
|
61
81
|
senior: true,
|
|
62
82
|
element: 'node:task',
|
|
63
|
-
|
|
83
|
+
node: 'task',
|
|
64
84
|
},
|
|
65
85
|
{
|
|
66
86
|
id: 'addExclusiveGateway',
|
|
@@ -70,7 +90,7 @@ const SPECS = [
|
|
|
70
90
|
category: 'gateways',
|
|
71
91
|
senior: true,
|
|
72
92
|
element: 'node:gatewayExclusive',
|
|
73
|
-
|
|
93
|
+
node: 'gatewayExclusive',
|
|
74
94
|
},
|
|
75
95
|
{
|
|
76
96
|
id: 'sequenceFlowTool',
|
|
@@ -80,6 +100,7 @@ const SPECS = [
|
|
|
80
100
|
category: 'flows',
|
|
81
101
|
senior: true,
|
|
82
102
|
element: 'connector:sequence',
|
|
103
|
+
edge: 'sequenceFlow',
|
|
83
104
|
run: activateBpmnSequenceFlow,
|
|
84
105
|
},
|
|
85
106
|
{
|
|
@@ -104,6 +125,7 @@ const SPECS = [
|
|
|
104
125
|
category: 'flows',
|
|
105
126
|
senior: true,
|
|
106
127
|
element: 'connector:message',
|
|
128
|
+
edge: 'messageFlow',
|
|
107
129
|
run: activateBpmnMessageFlow,
|
|
108
130
|
},
|
|
109
131
|
/* ── Activities: the typed tasks and the two that stand for a process ─ */
|
|
@@ -115,7 +137,7 @@ const SPECS = [
|
|
|
115
137
|
category: 'activities',
|
|
116
138
|
senior: true,
|
|
117
139
|
element: 'node:taskUser',
|
|
118
|
-
|
|
140
|
+
node: 'taskUser',
|
|
119
141
|
},
|
|
120
142
|
{
|
|
121
143
|
id: 'addServiceTask',
|
|
@@ -125,7 +147,7 @@ const SPECS = [
|
|
|
125
147
|
category: 'activities',
|
|
126
148
|
senior: true,
|
|
127
149
|
element: 'node:taskService',
|
|
128
|
-
|
|
150
|
+
node: 'taskService',
|
|
129
151
|
},
|
|
130
152
|
{
|
|
131
153
|
id: 'addSubProcess',
|
|
@@ -135,7 +157,7 @@ const SPECS = [
|
|
|
135
157
|
category: 'activities',
|
|
136
158
|
senior: true,
|
|
137
159
|
element: 'node:subProcess',
|
|
138
|
-
|
|
160
|
+
node: 'subProcess',
|
|
139
161
|
},
|
|
140
162
|
{
|
|
141
163
|
id: 'addCallActivity',
|
|
@@ -145,7 +167,7 @@ const SPECS = [
|
|
|
145
167
|
category: 'activities',
|
|
146
168
|
senior: true,
|
|
147
169
|
element: 'node:callActivity',
|
|
148
|
-
|
|
170
|
+
node: 'callActivity',
|
|
149
171
|
},
|
|
150
172
|
/* ── The other gateway ──────────────────────────────────────────────── */
|
|
151
173
|
{
|
|
@@ -159,7 +181,7 @@ const SPECS = [
|
|
|
159
181
|
category: 'gateways',
|
|
160
182
|
senior: true,
|
|
161
183
|
element: 'node:gatewayParallel',
|
|
162
|
-
|
|
184
|
+
node: 'gatewayParallel',
|
|
163
185
|
},
|
|
164
186
|
/* ── Event variants: what TRIGGERS a start, what an end does on the way
|
|
165
187
|
out. Refinements of the two plain events above, so they follow them. ─ */
|
|
@@ -171,7 +193,7 @@ const SPECS = [
|
|
|
171
193
|
category: 'events',
|
|
172
194
|
senior: false,
|
|
173
195
|
element: 'node:startEventMessage',
|
|
174
|
-
|
|
196
|
+
node: 'startEventMessage',
|
|
175
197
|
},
|
|
176
198
|
{
|
|
177
199
|
id: 'addTimerStartEvent',
|
|
@@ -181,7 +203,7 @@ const SPECS = [
|
|
|
181
203
|
category: 'events',
|
|
182
204
|
senior: false,
|
|
183
205
|
element: 'node:startEventTimer',
|
|
184
|
-
|
|
206
|
+
node: 'startEventTimer',
|
|
185
207
|
},
|
|
186
208
|
{
|
|
187
209
|
id: 'addMessageEndEvent',
|
|
@@ -191,7 +213,7 @@ const SPECS = [
|
|
|
191
213
|
category: 'events',
|
|
192
214
|
senior: false,
|
|
193
215
|
element: 'node:endEventMessage',
|
|
194
|
-
|
|
216
|
+
node: 'endEventMessage',
|
|
195
217
|
},
|
|
196
218
|
{
|
|
197
219
|
id: 'addTerminateEndEvent',
|
|
@@ -201,7 +223,7 @@ const SPECS = [
|
|
|
201
223
|
category: 'events',
|
|
202
224
|
senior: false,
|
|
203
225
|
element: 'node:endEventTerminate',
|
|
204
|
-
|
|
226
|
+
node: 'endEventTerminate',
|
|
205
227
|
},
|
|
206
228
|
/* ── The last connecting object ─────────────────────────────────────── */
|
|
207
229
|
{
|
|
@@ -212,6 +234,7 @@ const SPECS = [
|
|
|
212
234
|
category: 'flows',
|
|
213
235
|
senior: false,
|
|
214
236
|
element: 'connector:association',
|
|
237
|
+
edge: 'association',
|
|
215
238
|
run: activateBpmnAssociation,
|
|
216
239
|
},
|
|
217
240
|
/* ── Data ───────────────────────────────────────────────────────────── */
|
|
@@ -223,7 +246,7 @@ const SPECS = [
|
|
|
223
246
|
category: 'data',
|
|
224
247
|
senior: true,
|
|
225
248
|
element: 'node:dataObject',
|
|
226
|
-
|
|
249
|
+
node: 'dataObject',
|
|
227
250
|
},
|
|
228
251
|
{
|
|
229
252
|
id: 'addDataStore',
|
|
@@ -233,7 +256,7 @@ const SPECS = [
|
|
|
233
256
|
category: 'data',
|
|
234
257
|
senior: false,
|
|
235
258
|
element: 'node:dataStore',
|
|
236
|
-
|
|
259
|
+
node: 'dataStore',
|
|
237
260
|
},
|
|
238
261
|
/* ── Artifacts: what an author writes ON the picture ────────────────── */
|
|
239
262
|
{
|
|
@@ -244,7 +267,7 @@ const SPECS = [
|
|
|
244
267
|
category: 'annotations',
|
|
245
268
|
senior: true,
|
|
246
269
|
element: 'node:textAnnotation',
|
|
247
|
-
|
|
270
|
+
node: 'textAnnotation',
|
|
248
271
|
},
|
|
249
272
|
{
|
|
250
273
|
// Filed with the annotation and not in a section of its own: both are
|
|
@@ -261,29 +284,160 @@ const SPECS = [
|
|
|
261
284
|
// senior row is a shortcut to.
|
|
262
285
|
senior: false,
|
|
263
286
|
element: 'node:group',
|
|
264
|
-
|
|
287
|
+
node: 'group',
|
|
265
288
|
},
|
|
266
289
|
];
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
290
|
+
/* ── The legend, subscribed rather than tabulated ──────────────────────── */
|
|
291
|
+
/**
|
|
292
|
+
* The legend of a pool is not a table: every row below is DERIVED from the
|
|
293
|
+
* command that draws the artefact, from the same preset the gesture creates it
|
|
294
|
+
* with, and it is listed only when the pool actually contains one (ADR 0026,
|
|
295
|
+
* `legendFromCommands`).
|
|
296
|
+
*
|
|
297
|
+
* ## The swatch box, and why BPMN asks for a bigger one than UML
|
|
298
|
+
*
|
|
299
|
+
* UML tells its figures apart by full-box silhouettes (a stick figure, a
|
|
300
|
+
* divided box, an ellipse) and is comfortable at 34 × 24. BPMN puts its
|
|
301
|
+
* distinctions in CORNER MARKERS — the person and the cog are `0.24 × unit` in
|
|
302
|
+
* the top-left (`node/node-renderer.ts`) — so it needs about 30 % more: at
|
|
303
|
+
* 44 × 30 a task's marker is ~6 px and a gateway's arms ~6 px, which is the
|
|
304
|
+
* floor at which they read at all.
|
|
305
|
+
*
|
|
306
|
+
* ## The one known visual limit
|
|
307
|
+
*
|
|
308
|
+
* The group's dashed lasso uses the renderer's fixed `[12, 12]` dash pattern
|
|
309
|
+
* (`consts.ts` says why there is no dotted stroke to ask for): across 44 units
|
|
310
|
+
* that is about two dashes, and down 29 it is none. The row is still
|
|
311
|
+
* distinguishable from the text annotation — which draws no closed rectangle —
|
|
312
|
+
* but it does not READ as dotted, and nothing in this file can change that.
|
|
313
|
+
*/
|
|
314
|
+
const SWATCH_W = 44;
|
|
315
|
+
const SWATCH_H = 30;
|
|
316
|
+
const BPMN_LEGEND_BOX = {
|
|
317
|
+
// No `titleWording`: every board that has a legend says the same generic
|
|
318
|
+
// "Legend", which is what the platform falls back to (`BOARD_LEGEND_TITLE`).
|
|
319
|
+
width: 300,
|
|
320
|
+
rowHeight: 36,
|
|
321
|
+
swatchWidth: SWATCH_W,
|
|
322
|
+
swatchHeight: SWATCH_H,
|
|
323
|
+
};
|
|
324
|
+
/**
|
|
325
|
+
* The three roles whose row must match EXACTLY, and no others.
|
|
326
|
+
*
|
|
327
|
+
* `bpmn:start-event`, `bpmn:end-event` and `bpmn:task` are the three roles with
|
|
328
|
+
* a row that also have children (`roles.ts`). Without `exact`, a pool holding
|
|
329
|
+
* only a message start event would light the plain "Start event" row too — a
|
|
330
|
+
* bare circle nobody drew. The families that have no row at all
|
|
331
|
+
* (`bpmn:event`, `bpmn:activity`, `bpmn:gateway`, `bpmn:data`,
|
|
332
|
+
* `bpmn:flow-object`) need no such care: they are never stamped.
|
|
333
|
+
*/
|
|
334
|
+
const EXACT_ROLES = new Set([
|
|
335
|
+
BPMN_ROLE.startEvent,
|
|
336
|
+
BPMN_ROLE.endEvent,
|
|
337
|
+
BPMN_ROLE.task,
|
|
338
|
+
]);
|
|
339
|
+
/**
|
|
340
|
+
* A glyph row: the artefact itself, painted at swatch size by the very renderer
|
|
341
|
+
* that paints it on the board — the creation preset minus three keys.
|
|
342
|
+
*
|
|
343
|
+
* - `role`, because the legend is drawn IN the pool it documents and the scan
|
|
344
|
+
* detects by role: a swatch carrying one would list itself the next time,
|
|
345
|
+
* and all 21 validation rules would count it (`rules.ts`);
|
|
346
|
+
* - `xywh`, because the box belongs to the layout, which fits {@link
|
|
347
|
+
* CommandLegendRow.aspect} inside the swatch column;
|
|
348
|
+
* - `text`, because `bpmnNodeProps` writes the artefact's default caption at
|
|
349
|
+
* 18 px with `TextFitMode.Overflow`: a "Task" that size would spill across
|
|
350
|
+
* the whole box. Without it `fontSize` / `textAlign` / `textFitMode` are
|
|
351
|
+
* inert, so there is no reason to strip those too.
|
|
352
|
+
*
|
|
353
|
+
* `radius` is the one prop SCALED to the swatch, and it has to be: it is an
|
|
354
|
+
* absolute, unbounded value (`drawRect` calls `arcTo` with it), so the group's
|
|
355
|
+
* 20 and the task's 10 would both round a 44 × 30 box into a pill.
|
|
356
|
+
* `strokeWidth` is deliberately NOT scaled — the thin ring against the thick
|
|
357
|
+
* one, and the call activity's heavy border against the sub-process's, IS the
|
|
358
|
+
* notation, and at 30 units the 2-against-4 ratio reads better than at 56.
|
|
359
|
+
*/
|
|
360
|
+
function nodeRow(kind) {
|
|
361
|
+
const { role: _role, xywh: _xywh, text: _text, ...props } = bpmnNodeProps(kind, { xywh: '[0,0,0,0]' });
|
|
362
|
+
const size = NODE_SIZE[kind];
|
|
363
|
+
return {
|
|
364
|
+
swatch: 'glyph',
|
|
365
|
+
// Read by nothing for a glyph row — the element carries its own fill and
|
|
366
|
+
// stroke — and written all the same, because `CommandLegendRow` asks for a
|
|
367
|
+
// colour and the paper is the honest answer. UML does the same.
|
|
368
|
+
color: NODE_FILL,
|
|
369
|
+
props: {
|
|
370
|
+
...props,
|
|
371
|
+
radius: Math.round((Number(props.radius) || 0) * (SWATCH_H / size.h)),
|
|
372
|
+
},
|
|
373
|
+
aspect: size.h > 0 ? size.w / size.h : 1,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* An edge row: the line the tool actually arms, endpoints and all, drawn by the
|
|
378
|
+
* connector renderer at swatch width rather than approximated by a bar.
|
|
379
|
+
*
|
|
380
|
+
* `dashed` is kept beside the props although the connector carries its own
|
|
381
|
+
* `strokeStyle`: it is the one fact about an edge row a pure test can read
|
|
382
|
+
* without a renderer, and it is DERIVED from the same table, so the two can
|
|
383
|
+
* never disagree.
|
|
384
|
+
*/
|
|
385
|
+
function edgeRow(key) {
|
|
386
|
+
const style = BPMN_EDGE_STYLE[key];
|
|
387
|
+
return {
|
|
388
|
+
swatch: 'edge',
|
|
389
|
+
color: style.stroke,
|
|
390
|
+
dashed: style.strokeStyle === StrokeStyle.Dash,
|
|
391
|
+
props: { ...style },
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* The row a spec subscribes, or none.
|
|
396
|
+
*
|
|
397
|
+
* The pool subscribes nothing on purpose: it is the SHEET the legend is drawn
|
|
398
|
+
* on, and listing it would be listing the paper — the same call C4's board and
|
|
399
|
+
* UML's frame make about themselves.
|
|
400
|
+
*/
|
|
401
|
+
function legendOf(spec) {
|
|
402
|
+
if (spec.edge) {
|
|
403
|
+
return { role: BPMN_ROLE[spec.edge], row: edgeRow(spec.edge) };
|
|
404
|
+
}
|
|
405
|
+
if (!spec.node)
|
|
406
|
+
return undefined;
|
|
407
|
+
const role = BPMN_ROLE_OF_KIND[spec.node];
|
|
408
|
+
return {
|
|
409
|
+
role,
|
|
410
|
+
row: nodeRow(spec.node),
|
|
411
|
+
...(EXACT_ROLES.has(role) ? { exact: true } : {}),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const toolboxCommands = SPECS.map((spec, order) => {
|
|
415
|
+
const legend = legendOf(spec);
|
|
416
|
+
return {
|
|
417
|
+
id: `bpmn.${spec.id}`,
|
|
418
|
+
owner: 'bpmn',
|
|
419
|
+
kind: spec.kind,
|
|
420
|
+
labelKey: `com.labre.commands.bpmn.${spec.id}`,
|
|
421
|
+
labelFallback: spec.label,
|
|
422
|
+
category: spec.category,
|
|
423
|
+
iconKey: spec.iconKey,
|
|
424
|
+
// The catalogue holds all of them; `senior` decides which fourteen the
|
|
425
|
+
// sub-menu opens on before this user has reached for anything.
|
|
426
|
+
surfaces: spec.senior
|
|
427
|
+
? ['senior-menu', 'catalogue', 'palette', 'agent']
|
|
428
|
+
: ['catalogue', 'palette', 'agent'],
|
|
429
|
+
order,
|
|
430
|
+
scope: 'edgeless',
|
|
431
|
+
defaultKeys: { mac: [], other: [] },
|
|
432
|
+
availability: 'always',
|
|
433
|
+
run: gestureOf(spec),
|
|
434
|
+
telemetry: { framework: 'bpmn', element: spec.element, board: spec.board },
|
|
435
|
+
...(legend ? { legend } : {}),
|
|
436
|
+
// The board carries the BOX the rows are laid out in, and only the board:
|
|
437
|
+
// exactly one command per framework may declare it.
|
|
438
|
+
...(spec.board ? { legendBox: BPMN_LEGEND_BOX } : {}),
|
|
439
|
+
};
|
|
440
|
+
});
|
|
287
441
|
/**
|
|
288
442
|
* The LANE commands (B4) — the first BPMN entries that are not a toolbox slot.
|
|
289
443
|
*
|
|
@@ -379,7 +533,12 @@ const exportCommand = {
|
|
|
379
533
|
labelKey: 'com.labre.commands.bpmn.exportXml',
|
|
380
534
|
labelFallback: 'Export BPMN XML',
|
|
381
535
|
descriptionKey: 'com.labre.commands.bpmn.exportXml.description',
|
|
382
|
-
|
|
536
|
+
// The second sentence is the PO's ruling of 2026-09-17 said BEFORE the click
|
|
537
|
+
// rather than after it: only artefacts carrying a BPMN role are written, and
|
|
538
|
+
// the board's generic SVG export (ADR 0025, R34) is what takes the drawing.
|
|
539
|
+
// The export also SAYS what it left out, once, in its own report — but a
|
|
540
|
+
// promise a command makes in the catalogue is cheaper than a surprise.
|
|
541
|
+
descriptionFallback: 'Download the whole board as a BPMN 2.0 XML file, ready to open in any BPMN tool. Only BPMN artefacts are written; export SVG to get everything drawn in the pool.',
|
|
383
542
|
// Filed with the import it is the other half of — see {@link INTERCHANGE}.
|
|
384
543
|
// It shipped filed under `swimlanes`, because the pool's "⋮" is where it is
|
|
385
544
|
// REACHED from and there was no better section for a command with no sibling;
|
|
@@ -565,4 +724,7 @@ export const bpmnCommandIcons = {
|
|
|
565
724
|
'bpmn.export-xml': bpmnExportXmlIcon,
|
|
566
725
|
'bpmn.import-xml': bpmnImportXmlIcon,
|
|
567
726
|
'bpmn.import-svg': bpmnImportSvgIcon,
|
|
727
|
+
// The senior button's 56×56 glyph, so `FrameworkDescriptor.iconKey` resolves
|
|
728
|
+
// through `getCommandIcon`.
|
|
729
|
+
'bpmn.toolbar': bpmnToolbarIcon,
|
|
568
730
|
};
|
package/dist/consts.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
|
|
2
3
|
/**
|
|
3
4
|
* Visual constants for the BPMN basics. Style "C" (hybrid): spec-accurate
|
|
4
5
|
* shapes and line weights, with accent colour only on the event rings — the
|
|
@@ -23,8 +24,9 @@ export declare const START_WIDTH = 2;
|
|
|
23
24
|
export declare const END_WIDTH = 4;
|
|
24
25
|
export declare const NODE_STROKE_WIDTH = 2;
|
|
25
26
|
/**
|
|
26
|
-
* The call activity's border, which the spec draws THICK — it is the
|
|
27
|
-
* tell it from the sub-process, since
|
|
27
|
+
* The call activity's border, which the spec draws THICK — and here it is the
|
|
28
|
+
* ONLY way to tell it from the sub-process, since Labre draws neither of them
|
|
29
|
+
* with the notation's collapsed `+` (`node/node-renderer.ts`). Same
|
|
28
30
|
* weight as the end-event ring, and for the same reason: this is the heaviest
|
|
29
31
|
* line the notation uses, and it is spent on "this one stands for a whole
|
|
30
32
|
* process defined somewhere else".
|
|
@@ -260,3 +262,33 @@ export declare const MESSAGE_WIDTH = 2;
|
|
|
260
262
|
*/
|
|
261
263
|
export declare const ASSOCIATION_STROKE: string;
|
|
262
264
|
export declare const ASSOCIATION_WIDTH = 2;
|
|
265
|
+
/** The three connecting objects, keyed the way {@link BPMN_EDGE_STYLE} is. */
|
|
266
|
+
export type BpmnEdgeKey = 'sequenceFlow' | 'messageFlow' | 'association';
|
|
267
|
+
/**
|
|
268
|
+
* What a BPMN connecting object LOOKS like — the five props, and never a sixth.
|
|
269
|
+
*
|
|
270
|
+
* `mode` is deliberately absent. The toolbox arms the connector tool
|
|
271
|
+
* orthogonally, but that is a property of the DRAWING gesture, not of the line:
|
|
272
|
+
* a legend swatch draws the same notation across 44 units in a straight
|
|
273
|
+
* segment, and an orthogonal mode there would put a right angle in a sample
|
|
274
|
+
* that has nothing to route around.
|
|
275
|
+
*/
|
|
276
|
+
export interface BpmnEdgeStyle {
|
|
277
|
+
stroke: string;
|
|
278
|
+
strokeStyle: StrokeStyle;
|
|
279
|
+
strokeWidth: number;
|
|
280
|
+
frontEndpointStyle: PointStyle;
|
|
281
|
+
rearEndpointStyle: PointStyle;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* The whole BPMN line notation, in one table — read by the tool that ARMS the
|
|
285
|
+
* connector (`actions.ts`) and by the legend row that PICTURES it
|
|
286
|
+
* (`commands.ts`).
|
|
287
|
+
*
|
|
288
|
+
* One table for the same reason `presets.ts` is one builder for the nodes: two
|
|
289
|
+
* spellings of the same line agree the day they are written and drift on the
|
|
290
|
+
* first restyle, and the drift shows up as a legend that documents a notation
|
|
291
|
+
* the board does not use. Same argument, and the same shape, as UML's
|
|
292
|
+
* `UML_EDGE_STYLE`.
|
|
293
|
+
*/
|
|
294
|
+
export declare const BPMN_EDGE_STYLE: Record<BpmnEdgeKey, BpmnEdgeStyle>;
|
package/dist/consts.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
|
|
1
2
|
import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/consts';
|
|
2
3
|
/**
|
|
3
4
|
* Visual constants for the BPMN basics. Style "C" (hybrid): spec-accurate
|
|
@@ -23,8 +24,9 @@ export const START_WIDTH = 2;
|
|
|
23
24
|
export const END_WIDTH = 4;
|
|
24
25
|
export const NODE_STROKE_WIDTH = 2;
|
|
25
26
|
/**
|
|
26
|
-
* The call activity's border, which the spec draws THICK — it is the
|
|
27
|
-
* tell it from the sub-process, since
|
|
27
|
+
* The call activity's border, which the spec draws THICK — and here it is the
|
|
28
|
+
* ONLY way to tell it from the sub-process, since Labre draws neither of them
|
|
29
|
+
* with the notation's collapsed `+` (`node/node-renderer.ts`). Same
|
|
28
30
|
* weight as the end-event ring, and for the same reason: this is the heaviest
|
|
29
31
|
* line the notation uses, and it is spent on "this one stands for a whole
|
|
30
32
|
* process defined somewhere else".
|
|
@@ -302,3 +304,37 @@ export const MESSAGE_WIDTH = 2;
|
|
|
302
304
|
*/
|
|
303
305
|
export const ASSOCIATION_STROKE = NOTATION_NEUTRALS.ink;
|
|
304
306
|
export const ASSOCIATION_WIDTH = 2;
|
|
307
|
+
/**
|
|
308
|
+
* The whole BPMN line notation, in one table — read by the tool that ARMS the
|
|
309
|
+
* connector (`actions.ts`) and by the legend row that PICTURES it
|
|
310
|
+
* (`commands.ts`).
|
|
311
|
+
*
|
|
312
|
+
* One table for the same reason `presets.ts` is one builder for the nodes: two
|
|
313
|
+
* spellings of the same line agree the day they are written and drift on the
|
|
314
|
+
* first restyle, and the drift shows up as a legend that documents a notation
|
|
315
|
+
* the board does not use. Same argument, and the same shape, as UML's
|
|
316
|
+
* `UML_EDGE_STYLE`.
|
|
317
|
+
*/
|
|
318
|
+
export const BPMN_EDGE_STYLE = {
|
|
319
|
+
sequenceFlow: {
|
|
320
|
+
stroke: SEQUENCE_STROKE,
|
|
321
|
+
strokeStyle: StrokeStyle.Solid,
|
|
322
|
+
strokeWidth: SEQUENCE_WIDTH,
|
|
323
|
+
frontEndpointStyle: PointStyle.None,
|
|
324
|
+
rearEndpointStyle: PointStyle.Triangle,
|
|
325
|
+
},
|
|
326
|
+
messageFlow: {
|
|
327
|
+
stroke: MESSAGE_STROKE,
|
|
328
|
+
strokeStyle: StrokeStyle.Dash,
|
|
329
|
+
strokeWidth: MESSAGE_WIDTH,
|
|
330
|
+
frontEndpointStyle: PointStyle.Circle,
|
|
331
|
+
rearEndpointStyle: PointStyle.Arrow,
|
|
332
|
+
},
|
|
333
|
+
association: {
|
|
334
|
+
stroke: ASSOCIATION_STROKE,
|
|
335
|
+
strokeStyle: StrokeStyle.Dash,
|
|
336
|
+
strokeWidth: ASSOCIATION_WIDTH,
|
|
337
|
+
frontEndpointStyle: PointStyle.None,
|
|
338
|
+
rearEndpointStyle: PointStyle.None,
|
|
339
|
+
},
|
|
340
|
+
};
|
package/dist/element-view.js
CHANGED
|
@@ -301,7 +301,7 @@ export class BpmnPoolView extends GfxElementModelView {
|
|
|
301
301
|
font: '14px Inter, sans-serif',
|
|
302
302
|
color: 'var(--affine-text-primary-color, #1f2328)',
|
|
303
303
|
background: 'var(--affine-background-overlay-panel-color, #ffffff)',
|
|
304
|
-
border: '1px solid var(--affine-primary-color
|
|
304
|
+
border: '1px solid var(--affine-primary-color)',
|
|
305
305
|
borderRadius: '6px',
|
|
306
306
|
boxShadow: 'var(--affine-shadow-2, 0 2px 8px rgba(0,0,0,0.18))',
|
|
307
307
|
outline: 'none',
|
package/dist/export.d.ts
CHANGED
|
@@ -217,6 +217,18 @@ export interface BpmnExportBoard {
|
|
|
217
217
|
pools: readonly BpmnPoolElementModel[];
|
|
218
218
|
nodes: readonly BpmnNodeElementModel[];
|
|
219
219
|
connectors: readonly ConnectorElementModel[];
|
|
220
|
+
/**
|
|
221
|
+
* How many things drawn INSIDE a pool the picking left behind because they
|
|
222
|
+
* carry no BPMN role — a free shape, a text, an artefact drawn before roles
|
|
223
|
+
* existed (2026-08-26).
|
|
224
|
+
*
|
|
225
|
+
* Counted by whoever picked the board (`bpmnBoardFrom`), because that is the
|
|
226
|
+
* only place that ever sees what was NOT picked. The behaviour is the PO's
|
|
227
|
+
* ruling of 2026-09-17 and does not change: a `.bpmn` carries the author's
|
|
228
|
+
* statements, and the board's generic SVG export (ADR 0025, R34) carries the
|
|
229
|
+
* drawing. What was missing was SAYING so, which is what this number buys.
|
|
230
|
+
*/
|
|
231
|
+
leftOut?: number;
|
|
220
232
|
}
|
|
221
233
|
export interface BpmnExportOptions {
|
|
222
234
|
/** Names the `collaboration` / lone `process` and the `BPMNDiagram`. */
|
|
@@ -237,7 +249,7 @@ export interface BpmnExportWarning {
|
|
|
237
249
|
/** Values for the fallback's placeholders — a count, a list of names. */
|
|
238
250
|
params?: Record<string, string | number>;
|
|
239
251
|
}
|
|
240
|
-
/** All
|
|
252
|
+
/** All ten, for `translations.ts`'s manifest contribution. */
|
|
241
253
|
export declare const BPMN_EXPORT_WARNING_KEYS: readonly (readonly [string, string])[];
|
|
242
254
|
/**
|
|
243
255
|
* The document, plus what writing it could not say.
|
package/dist/export.js
CHANGED
|
@@ -764,7 +764,7 @@ class IdMinter {
|
|
|
764
764
|
}
|
|
765
765
|
}
|
|
766
766
|
/**
|
|
767
|
-
* The
|
|
767
|
+
* The ten export-warning keys, each paired with its English fallback
|
|
768
768
|
* (`{{name}}` placeholders included) — declared ONCE, here, and read both by
|
|
769
769
|
* the `if` blocks below (which add the live `params`) and by
|
|
770
770
|
* `translations.ts`'s manifest (which needs the pair with no board to run
|
|
@@ -812,7 +812,11 @@ const UNWRITABLE_EDGES_WARNING = [
|
|
|
812
812
|
'com.labre.bpmn.export.warning.unwritable-edges',
|
|
813
813
|
'{{count}} arrow(s) were left out: BPMN requires both ends of a flow to be named, and they have an end that is loose or attached to something that is not a BPMN artefact.',
|
|
814
814
|
];
|
|
815
|
-
|
|
815
|
+
const LEFT_OUT_WARNING = [
|
|
816
|
+
'com.labre.bpmn.export.warning.left-out',
|
|
817
|
+
'{{count}} element(s) inside the pool are not BPMN elements and were left out of the .bpmn file. Export SVG to get everything drawn in the pool.',
|
|
818
|
+
];
|
|
819
|
+
/** All ten, for `translations.ts`'s manifest contribution. */
|
|
816
820
|
export const BPMN_EXPORT_WARNING_KEYS = [
|
|
817
821
|
UNDRAWN_ARTEFACTS_WARNING,
|
|
818
822
|
DROPPED_MESSAGE_FLOWS_WARNING,
|
|
@@ -823,6 +827,7 @@ export const BPMN_EXPORT_WARNING_KEYS = [
|
|
|
823
827
|
CONFLICTING_IDS_WARNING,
|
|
824
828
|
REFUSED_ATTRIBUTE_NAMES_WARNING,
|
|
825
829
|
UNWRITABLE_EDGES_WARNING,
|
|
830
|
+
LEFT_OUT_WARNING,
|
|
826
831
|
];
|
|
827
832
|
/* ── The plan ─────────────────────────────────────────────────────────── */
|
|
828
833
|
/**
|
|
@@ -1425,9 +1430,11 @@ export function exportBpmnXmlWithWarnings(board, options = {}) {
|
|
|
1425
1430
|
id: minter.mint('Shape', node.id),
|
|
1426
1431
|
bpmnElement: node.id,
|
|
1427
1432
|
};
|
|
1428
|
-
// The pack draws the COLLAPSED sub-process only — a task-sized box with
|
|
1429
|
-
//
|
|
1430
|
-
// tool is free to draw an expanded container the
|
|
1433
|
+
// The pack draws the COLLAPSED sub-process only — a task-sized box, with
|
|
1434
|
+
// no body folded open inside it — and `isExpanded="false"` is how DI says
|
|
1435
|
+
// exactly that. Without it a tool is free to draw an expanded container the
|
|
1436
|
+
// author never made. (Labre leaves the `+` marker itself off the box, which
|
|
1437
|
+
// is a drawing choice and says nothing about the DI flag.)
|
|
1431
1438
|
if (node.model.kind === 'subProcess' ||
|
|
1432
1439
|
node.model.kind === 'callActivity') {
|
|
1433
1440
|
attrs.isExpanded = 'false';
|
|
@@ -1621,6 +1628,13 @@ export function exportBpmnXmlWithWarnings(board, options = {}) {
|
|
|
1621
1628
|
const [key, fallback] = UNWRITABLE_EDGES_WARNING;
|
|
1622
1629
|
warnings.push({ key, fallback, params: { count: unwritableEdges } });
|
|
1623
1630
|
}
|
|
1631
|
+
// What the PICKING left behind (see {@link BpmnExportBoard.leftOut}). One
|
|
1632
|
+
// line for the whole pool, because the point is not which shape it was: it is
|
|
1633
|
+
// that the file is the process and the SVG is the picture.
|
|
1634
|
+
if (board.leftOut !== undefined && board.leftOut > 0) {
|
|
1635
|
+
const [key, fallback] = LEFT_OUT_WARNING;
|
|
1636
|
+
warnings.push({ key, fallback, params: { count: board.leftOut } });
|
|
1637
|
+
}
|
|
1624
1638
|
return {
|
|
1625
1639
|
text: `<?xml version="1.0" encoding="UTF-8"?>\n${serializeElement(definitions, '')}\n`,
|
|
1626
1640
|
warnings,
|
package/dist/import.d.ts
CHANGED
|
@@ -62,6 +62,16 @@ export declare const BPMN_IMPORT_ERRORS: {
|
|
|
62
62
|
readonly malformedXml: readonly ["com.labre.bpmn.import.error.malformed-xml", "This file is not well-formed XML, so no BPMN can be read out of it: {{detail}}"];
|
|
63
63
|
readonly notDefinitions: readonly ["com.labre.bpmn.import.error.not-definitions", "A BPMN file opens on <definitions>; this one opens on <{{tag}}>."];
|
|
64
64
|
readonly wrongNamespace: readonly ["com.labre.bpmn.import.error.wrong-namespace", "This <definitions> is in \"{{namespace}}\", not in BPMN 2.0's (\"{{bpmnNamespace}}\"). A DMN decision model and a BPMN process open on the same element name and are not the same file."];
|
|
65
|
+
/**
|
|
66
|
+
* Its OWN entry rather than `wrongNamespace` with the words "no namespace"
|
|
67
|
+
* poured into `{{namespace}}` (#390). That fragment was English prose
|
|
68
|
+
* substituted into a translated sentence — the one shape a `messageParams`
|
|
69
|
+
* hole cannot carry, because the reader is pure and has no `std` to resolve
|
|
70
|
+
* it with. It is also a different FACT, which is what this table is a list
|
|
71
|
+
* of: a `<definitions>` in the wrong namespace names one, a `<definitions>`
|
|
72
|
+
* in none names nothing at all.
|
|
73
|
+
*/
|
|
74
|
+
readonly missingNamespace: readonly ["com.labre.bpmn.import.error.missing-namespace", "This <definitions> declares no namespace, so it does not say it is BPMN 2.0 (\"{{bpmnNamespace}}\"). A DMN decision model and a BPMN process open on the same element name and are not the same file."];
|
|
65
75
|
readonly declinedRootKind: readonly ["com.labre.bpmn.import.error.declined-root-kind", "This file is a BPMN {{kind}}, which Labre does not draw. Only a process or a collaboration can be imported."];
|
|
66
76
|
};
|
|
67
77
|
/**
|
package/dist/import.js
CHANGED
|
@@ -120,6 +120,19 @@ export const BPMN_IMPORT_ERRORS = {
|
|
|
120
120
|
'com.labre.bpmn.import.error.wrong-namespace',
|
|
121
121
|
'This <definitions> is in "{{namespace}}", not in BPMN 2.0\'s ("{{bpmnNamespace}}"). A DMN decision model and a BPMN process open on the same element name and are not the same file.',
|
|
122
122
|
],
|
|
123
|
+
/**
|
|
124
|
+
* Its OWN entry rather than `wrongNamespace` with the words "no namespace"
|
|
125
|
+
* poured into `{{namespace}}` (#390). That fragment was English prose
|
|
126
|
+
* substituted into a translated sentence — the one shape a `messageParams`
|
|
127
|
+
* hole cannot carry, because the reader is pure and has no `std` to resolve
|
|
128
|
+
* it with. It is also a different FACT, which is what this table is a list
|
|
129
|
+
* of: a `<definitions>` in the wrong namespace names one, a `<definitions>`
|
|
130
|
+
* in none names nothing at all.
|
|
131
|
+
*/
|
|
132
|
+
missingNamespace: [
|
|
133
|
+
'com.labre.bpmn.import.error.missing-namespace',
|
|
134
|
+
'This <definitions> declares no namespace, so it does not say it is BPMN 2.0 ("{{bpmnNamespace}}"). A DMN decision model and a BPMN process open on the same element name and are not the same file.',
|
|
135
|
+
],
|
|
123
136
|
declinedRootKind: [
|
|
124
137
|
'com.labre.bpmn.import.error.declined-root-kind',
|
|
125
138
|
'This file is a BPMN {{kind}}, which Labre does not draw. Only a process or a collaboration can be imported.',
|
|
@@ -469,7 +482,19 @@ function parseDefinitions(source) {
|
|
|
469
482
|
// Without this a `.dmn` imports as an empty board, which is exactly the
|
|
470
483
|
// "three zeroes claiming an empty process" this reader refuses to return.
|
|
471
484
|
if (root.namespaceURI !== BPMN_NS.model) {
|
|
472
|
-
|
|
485
|
+
// Two facts, two refusals: a namespace this reader can quote back, and no
|
|
486
|
+
// namespace at all. The second used to borrow the first's sentence with
|
|
487
|
+
// the English words "no namespace" poured into its `{{namespace}}` hole,
|
|
488
|
+
// which put a fragment of English inside a translated sentence (#390).
|
|
489
|
+
const namespace = root.namespaceURI;
|
|
490
|
+
if (namespace === null) {
|
|
491
|
+
throw new InterchangeImportError(`This <definitions> declares no namespace, so it does not say it is ` +
|
|
492
|
+
`BPMN 2.0 ("${BPMN_NS.model}"). A DMN decision model and a BPMN ` +
|
|
493
|
+
`process open on the same element name and are not the same file.`, {
|
|
494
|
+
messageKey: BPMN_IMPORT_ERRORS.missingNamespace[0],
|
|
495
|
+
messageParams: { bpmnNamespace: BPMN_NS.model },
|
|
496
|
+
});
|
|
497
|
+
}
|
|
473
498
|
throw new InterchangeImportError(`This <definitions> is in "${namespace}", not ` +
|
|
474
499
|
`in BPMN 2.0's ("${BPMN_NS.model}"). A DMN decision model and a BPMN ` +
|
|
475
500
|
`process open on the same element name and are not the same file.`, {
|