@bpmn-nova/studio 0.3.0-preview → 0.3.2-preview
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 -20
- package/dist/canvas.js +7 -4
- package/dist/context-menu.js +2 -2
- package/dist/controller.js +84 -6
- package/dist/index.d.ts +138 -38
- package/dist/index.js +12 -11
- package/dist/interactions.js +1 -1
- package/dist/modules/bpmn-model/index.d.ts +11 -0
- package/dist/modules/bpmn-model/index.js +703 -0
- package/dist/modules/core/containment.js +590 -0
- package/dist/modules/core/gateway.js +72 -0
- package/dist/modules/core/history.js +32 -0
- package/dist/modules/core/index.d.ts +268 -0
- package/dist/modules/core/index.js +7 -0
- package/dist/modules/core/layout.js +644 -0
- package/dist/modules/core/model.js +287 -0
- package/dist/modules/core/runtime-transition-route.js +360 -0
- package/dist/modules/core/scope.js +99 -0
- package/dist/modules/designer/index.d.ts +79 -0
- package/dist/modules/designer/index.js +607 -0
- package/dist/modules/engine-activiti/index.d.ts +19 -0
- package/dist/modules/engine-activiti/index.js +160 -0
- package/dist/modules/engine-flowable/index.d.ts +19 -0
- package/dist/modules/engine-flowable/index.js +160 -0
- package/dist/modules/export-svg/index.d.ts +112 -0
- package/dist/modules/export-svg/index.js +2 -0
- package/dist/modules/export-svg/preview.js +327 -0
- package/dist/modules/export-svg/render.js +718 -0
- package/dist/modules/icons/index.d.ts +24 -0
- package/dist/modules/icons/index.js +264 -0
- package/dist/modules/palette/index.d.ts +74 -0
- package/dist/modules/palette/index.js +99 -0
- package/dist/modules/palette/panel.js +99 -0
- package/dist/modules/properties/index.d.ts +20 -0
- package/dist/modules/properties/index.js +19 -0
- package/dist/modules/properties-activiti/index.d.ts +3 -0
- package/dist/modules/properties-activiti/index.js +97 -0
- package/dist/modules/properties-bpmn/index.d.ts +3 -0
- package/dist/modules/properties-bpmn/index.js +518 -0
- package/dist/modules/properties-core/index.d.ts +124 -0
- package/dist/modules/properties-core/index.js +312 -0
- package/dist/modules/properties-flowable/index.d.ts +3 -0
- package/dist/modules/properties-flowable/index.js +114 -0
- package/dist/modules/properties-renderer/index.d.ts +25 -0
- package/dist/modules/properties-renderer/index.js +491 -0
- package/dist/modules/renderer-svg/index.d.ts +118 -0
- package/dist/modules/renderer-svg/index.js +1460 -0
- package/dist/modules/runtime/index.d.ts +169 -0
- package/dist/modules/runtime/index.js +535 -0
- package/dist/modules/theme/index.d.ts +95 -0
- package/dist/modules/theme/index.js +368 -0
- package/dist/modules/viewer/index.d.ts +265 -0
- package/dist/modules/viewer/index.js +1011 -0
- package/dist/modules/viewer/runtime-content.js +123 -0
- package/dist/modules/viewer/runtime-details-motion.js +228 -0
- package/dist/modules/viewer/runtime-trace.js +574 -0
- package/dist/modules/viewer/timeline.js +276 -0
- package/dist/selection-layout.js +1 -1
- package/dist/shell.js +210 -26
- package/dist/styles.css +116 -7
- package/llms-full.txt +3082 -0
- package/llms.txt +225 -0
- package/package.json +39 -16
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const escapeXml = (value = '') => String(value).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
2
|
+
|
|
3
|
+
function implementationAttrs(prefix, item = {}) {
|
|
4
|
+
const type = item.implementationType || 'class';
|
|
5
|
+
const value = item.implementation || '';
|
|
6
|
+
return value ? ` ${type}="${escapeXml(value)}"` : '';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function parseImplementation(element, prefix, namespace) {
|
|
10
|
+
const get = (name) => element.getAttributeNS(namespace, name) || element.getAttribute(`${prefix}:${name}`) || '';
|
|
11
|
+
const found = [['class', get('class')], ['delegateExpression', get('delegateExpression')], ['expression', get('expression')]].find(([, value]) => value);
|
|
12
|
+
return found ? { implementationType: found[0], implementation: found[1] } : {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function parseExtensionProperties(element, prefix, namespace) {
|
|
16
|
+
const properties = { executionListeners: [], taskListeners: [], fields: [] };
|
|
17
|
+
const ext = Array.from(element.children || []).find((child) => child.localName === 'extensionElements');
|
|
18
|
+
if (ext) {
|
|
19
|
+
for (const child of Array.from(ext.children || [])) {
|
|
20
|
+
if (child.localName === 'executionListener') {
|
|
21
|
+
properties.executionListeners.push({ event: child.getAttribute('event') || 'start', ...parseImplementation(child, prefix, namespace) });
|
|
22
|
+
} else if (child.localName === 'taskListener') {
|
|
23
|
+
properties.taskListeners.push({ event: child.getAttribute('event') || 'create', ...parseImplementation(child, prefix, namespace) });
|
|
24
|
+
} else if (child.localName === 'field') {
|
|
25
|
+
const string = Array.from(child.children || []).find((item) => item.localName === 'string');
|
|
26
|
+
const expression = Array.from(child.children || []).find((item) => item.localName === 'expression');
|
|
27
|
+
properties.fields.push({ name: child.getAttribute('name') || '', type: expression ? 'expression' : 'string', value: (expression || string)?.textContent || '' });
|
|
28
|
+
} else if (child.localName === 'failedJobRetryTimeCycle') {
|
|
29
|
+
properties.failedJobRetryTimeCycle = child.textContent?.trim() || '';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const inParameters = [];
|
|
34
|
+
const outParameters = [];
|
|
35
|
+
for (const child of Array.from(element.children || [])) {
|
|
36
|
+
if (child.localName !== 'in' && child.localName !== 'out') continue;
|
|
37
|
+
const row = { source: child.getAttribute('source') || '', sourceExpression: child.getAttribute('sourceExpression') || '', target: child.getAttribute('target') || '' };
|
|
38
|
+
(child.localName === 'in' ? inParameters : outParameters).push(row);
|
|
39
|
+
}
|
|
40
|
+
if (inParameters.length) properties.inParameters = inParameters;
|
|
41
|
+
if (outParameters.length) properties.outParameters = outParameters;
|
|
42
|
+
return properties;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function listenerXml(prefix, kind, listener) {
|
|
46
|
+
return `<${prefix}:${kind} event="${escapeXml(listener.event || (kind === 'taskListener' ? 'create' : 'start'))}"${implementationAttrs(prefix, listener)} />`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const activitiProfile = {
|
|
50
|
+
id: 'activiti',
|
|
51
|
+
label: 'Activiti',
|
|
52
|
+
prefix: 'activiti',
|
|
53
|
+
namespace: 'http://activiti.org/bpmn',
|
|
54
|
+
|
|
55
|
+
parseProcess(element) {
|
|
56
|
+
const get = (name) => element.getAttributeNS(this.namespace, name) || element.getAttribute(`${this.prefix}:${name}`) || '';
|
|
57
|
+
return {
|
|
58
|
+
candidateStarterUsers: get('candidateStarterUsers'),
|
|
59
|
+
candidateStarterGroups: get('candidateStarterGroups'),
|
|
60
|
+
...parseExtensionProperties(element, this.prefix, this.namespace),
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
processAttributes(model) {
|
|
65
|
+
const p = model.properties || {};
|
|
66
|
+
return {
|
|
67
|
+
...(p.candidateStarterUsers ? { [`${this.prefix}:candidateStarterUsers`]: p.candidateStarterUsers } : {}),
|
|
68
|
+
...(p.candidateStarterGroups ? { [`${this.prefix}:candidateStarterGroups`]: p.candidateStarterGroups } : {}),
|
|
69
|
+
...(p.extensionAttributes || {}),
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
parseNode(element) {
|
|
74
|
+
const get = (name) => element.getAttributeNS(this.namespace, name) || element.getAttribute(`${this.prefix}:${name}`) || '';
|
|
75
|
+
const local = element.localName;
|
|
76
|
+
const common = {
|
|
77
|
+
async: get('async') === 'true',
|
|
78
|
+
exclusive: get('exclusive') !== 'false',
|
|
79
|
+
asyncLeave: get('asyncLeave') === 'true',
|
|
80
|
+
skipExpression: get('skipExpression'),
|
|
81
|
+
...parseExtensionProperties(element, this.prefix, this.namespace),
|
|
82
|
+
};
|
|
83
|
+
if (local === 'userTask') Object.assign(common, {
|
|
84
|
+
assignee: get('assignee'), owner: get('owner'), candidateUsers: get('candidateUsers'), candidateGroups: get('candidateGroups'), formKey: get('formKey'), dueDate: get('dueDate'), priority: get('priority'), category: get('category'),
|
|
85
|
+
});
|
|
86
|
+
if (['serviceTask', 'sendTask', 'businessRuleTask'].includes(local)) Object.assign(common, parseImplementation(element, this.prefix, this.namespace), { resultVariable: get('resultVariable') || get('resultVariableName') });
|
|
87
|
+
if (local === 'scriptTask') common.resultVariable = get('resultVariable') || '';
|
|
88
|
+
if (local === 'callActivity') Object.assign(common, { businessKey: get('businessKey'), inheritBusinessKey: get('inheritBusinessKey') === 'true', inheritVariables: get('inheritVariables') === 'true', sameDeployment: get('sameDeployment') === 'true', processInstanceName: get('processInstanceName') });
|
|
89
|
+
return common;
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
nodeAttributes(node) {
|
|
93
|
+
const p = node.properties || {};
|
|
94
|
+
const attrs = { ...(p.extensionAttributes || {}) };
|
|
95
|
+
if (p.async) attrs[`${this.prefix}:async`] = 'true';
|
|
96
|
+
if (p.exclusive === false) attrs[`${this.prefix}:exclusive`] = 'false';
|
|
97
|
+
if (p.asyncLeave) attrs[`${this.prefix}:asyncLeave`] = 'true';
|
|
98
|
+
if (p.skipExpression) attrs[`${this.prefix}:skipExpression`] = p.skipExpression;
|
|
99
|
+
if (node.type === 'userTask') Object.assign(attrs, {
|
|
100
|
+
...(p.assignee ? { [`${this.prefix}:assignee`]: p.assignee } : {}),
|
|
101
|
+
...(p.owner ? { [`${this.prefix}:owner`]: p.owner } : {}),
|
|
102
|
+
...(p.candidateUsers ? { [`${this.prefix}:candidateUsers`]: p.candidateUsers } : {}),
|
|
103
|
+
...(p.candidateGroups ? { [`${this.prefix}:candidateGroups`]: p.candidateGroups } : {}),
|
|
104
|
+
...(p.formKey ? { [`${this.prefix}:formKey`]: p.formKey } : {}),
|
|
105
|
+
...(p.dueDate ? { [`${this.prefix}:dueDate`]: p.dueDate } : {}),
|
|
106
|
+
...(p.priority !== '' && p.priority != null ? { [`${this.prefix}:priority`]: p.priority } : {}),
|
|
107
|
+
...(p.category ? { [`${this.prefix}:category`]: p.category } : {}),
|
|
108
|
+
});
|
|
109
|
+
if (['serviceTask', 'sendTask', 'businessRuleTask'].includes(node.type) && p.implementation) attrs[`${this.prefix}:${p.implementationType || 'class'}`] = p.implementation;
|
|
110
|
+
if (['serviceTask', 'sendTask', 'businessRuleTask', 'scriptTask'].includes(node.type) && p.resultVariable) attrs[`${this.prefix}:resultVariable`] = p.resultVariable;
|
|
111
|
+
if (node.type === 'callActivity') Object.assign(attrs, {
|
|
112
|
+
...(p.businessKey ? { [`${this.prefix}:businessKey`]: p.businessKey } : {}),
|
|
113
|
+
...(p.inheritBusinessKey ? { [`${this.prefix}:inheritBusinessKey`]: 'true' } : {}),
|
|
114
|
+
...(p.inheritVariables ? { [`${this.prefix}:inheritVariables`]: 'true' } : {}),
|
|
115
|
+
...(p.sameDeployment ? { [`${this.prefix}:sameDeployment`]: 'true' } : {}),
|
|
116
|
+
...(p.processInstanceName ? { [`${this.prefix}:processInstanceName`]: p.processInstanceName } : {}),
|
|
117
|
+
});
|
|
118
|
+
return attrs;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
processExtensionElements(model) {
|
|
122
|
+
return (model.properties?.executionListeners || []).filter((item) => item.implementation).map((item) => listenerXml(this.prefix, 'executionListener', item));
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
nodeExtensionElements(node) {
|
|
126
|
+
const p = node.properties || {};
|
|
127
|
+
const result = [];
|
|
128
|
+
for (const listener of p.executionListeners || []) if (listener.implementation) result.push(listenerXml(this.prefix, 'executionListener', listener));
|
|
129
|
+
for (const listener of p.taskListeners || []) if (listener.implementation) result.push(listenerXml(this.prefix, 'taskListener', listener));
|
|
130
|
+
for (const field of p.fields || []) {
|
|
131
|
+
if (!field.name) continue;
|
|
132
|
+
const tag = field.type === 'expression' ? 'expression' : 'string';
|
|
133
|
+
result.push(`<${this.prefix}:field name="${escapeXml(field.name)}"><${this.prefix}:${tag}>${escapeXml(field.value || '')}</${this.prefix}:${tag}></${this.prefix}:field>`);
|
|
134
|
+
}
|
|
135
|
+
if (p.failedJobRetryTimeCycle) result.push(`<${this.prefix}:failedJobRetryTimeCycle>${escapeXml(p.failedJobRetryTimeCycle)}</${this.prefix}:failedJobRetryTimeCycle>`);
|
|
136
|
+
return result;
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
nodeChildElements(node) {
|
|
140
|
+
if (node.type !== 'callActivity') return [];
|
|
141
|
+
const result = [];
|
|
142
|
+
for (const row of node.properties?.inParameters || []) {
|
|
143
|
+
const attrs = [row.source ? `source="${escapeXml(row.source)}"` : '', row.sourceExpression ? `sourceExpression="${escapeXml(row.sourceExpression)}"` : '', row.target ? `target="${escapeXml(row.target)}"` : ''].filter(Boolean).join(' ');
|
|
144
|
+
if (attrs) result.push(`<${this.prefix}:in ${attrs} />`);
|
|
145
|
+
}
|
|
146
|
+
for (const row of node.properties?.outParameters || []) {
|
|
147
|
+
const attrs = [row.source ? `source="${escapeXml(row.source)}"` : '', row.sourceExpression ? `sourceExpression="${escapeXml(row.sourceExpression)}"` : '', row.target ? `target="${escapeXml(row.target)}"` : ''].filter(Boolean).join(' ');
|
|
148
|
+
if (attrs) result.push(`<${this.prefix}:out ${attrs} />`);
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
parseEdge(element) {
|
|
154
|
+
return { ...parseExtensionProperties(element, this.prefix, this.namespace) };
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
edgeExtensionElements(edge) {
|
|
158
|
+
return (edge.properties?.executionListeners || []).filter((item) => item.implementation).map((item) => listenerXml(this.prefix, 'executionListener', item));
|
|
159
|
+
},
|
|
160
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BpmnEdge, BpmnNode, ProcessModel } from '../core/index.js'
|
|
2
|
+
|
|
3
|
+
export interface FlowableEngineProfile {
|
|
4
|
+
id: 'flowable'
|
|
5
|
+
label: 'Flowable'
|
|
6
|
+
prefix: 'flowable'
|
|
7
|
+
namespace: 'http://flowable.org/bpmn'
|
|
8
|
+
parseProcess(element: Element): Record<string, unknown>
|
|
9
|
+
processAttributes(model: ProcessModel): Record<string, unknown>
|
|
10
|
+
parseNode(element: Element): Record<string, unknown>
|
|
11
|
+
nodeAttributes(node: BpmnNode): Record<string, unknown>
|
|
12
|
+
processExtensionElements(model: ProcessModel): string[]
|
|
13
|
+
nodeExtensionElements(node: BpmnNode): string[]
|
|
14
|
+
nodeChildElements(node: BpmnNode): string[]
|
|
15
|
+
parseEdge(element: Element): Record<string, unknown>
|
|
16
|
+
edgeExtensionElements(edge: BpmnEdge): string[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const flowableProfile: FlowableEngineProfile
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const escapeXml = (value = '') => String(value).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
2
|
+
|
|
3
|
+
function implementationAttrs(prefix, item = {}) {
|
|
4
|
+
const type = item.implementationType || 'class';
|
|
5
|
+
const value = item.implementation || '';
|
|
6
|
+
return value ? ` ${type}="${escapeXml(value)}"` : '';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function parseImplementation(element, prefix, namespace) {
|
|
10
|
+
const get = (name) => element.getAttributeNS(namespace, name) || element.getAttribute(`${prefix}:${name}`) || '';
|
|
11
|
+
const found = [['class', get('class')], ['delegateExpression', get('delegateExpression')], ['expression', get('expression')]].find(([, value]) => value);
|
|
12
|
+
return found ? { implementationType: found[0], implementation: found[1] } : {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function parseExtensionProperties(element, prefix, namespace) {
|
|
16
|
+
const properties = { executionListeners: [], taskListeners: [], fields: [] };
|
|
17
|
+
const ext = Array.from(element.children || []).find((child) => child.localName === 'extensionElements');
|
|
18
|
+
if (ext) {
|
|
19
|
+
for (const child of Array.from(ext.children || [])) {
|
|
20
|
+
if (child.localName === 'executionListener') {
|
|
21
|
+
properties.executionListeners.push({ event: child.getAttribute('event') || 'start', ...parseImplementation(child, prefix, namespace) });
|
|
22
|
+
} else if (child.localName === 'taskListener') {
|
|
23
|
+
properties.taskListeners.push({ event: child.getAttribute('event') || 'create', ...parseImplementation(child, prefix, namespace) });
|
|
24
|
+
} else if (child.localName === 'field') {
|
|
25
|
+
const string = Array.from(child.children || []).find((item) => item.localName === 'string');
|
|
26
|
+
const expression = Array.from(child.children || []).find((item) => item.localName === 'expression');
|
|
27
|
+
properties.fields.push({ name: child.getAttribute('name') || '', type: expression ? 'expression' : 'string', value: (expression || string)?.textContent || '' });
|
|
28
|
+
} else if (child.localName === 'failedJobRetryTimeCycle') {
|
|
29
|
+
properties.failedJobRetryTimeCycle = child.textContent?.trim() || '';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const inParameters = [];
|
|
34
|
+
const outParameters = [];
|
|
35
|
+
for (const child of Array.from(element.children || [])) {
|
|
36
|
+
if (child.localName !== 'in' && child.localName !== 'out') continue;
|
|
37
|
+
const row = { source: child.getAttribute('source') || '', sourceExpression: child.getAttribute('sourceExpression') || '', target: child.getAttribute('target') || '' };
|
|
38
|
+
(child.localName === 'in' ? inParameters : outParameters).push(row);
|
|
39
|
+
}
|
|
40
|
+
if (inParameters.length) properties.inParameters = inParameters;
|
|
41
|
+
if (outParameters.length) properties.outParameters = outParameters;
|
|
42
|
+
return properties;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function listenerXml(prefix, kind, listener) {
|
|
46
|
+
return `<${prefix}:${kind} event="${escapeXml(listener.event || (kind === 'taskListener' ? 'create' : 'start'))}"${implementationAttrs(prefix, listener)} />`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const flowableProfile = {
|
|
50
|
+
id: 'flowable',
|
|
51
|
+
label: 'Flowable',
|
|
52
|
+
prefix: 'flowable',
|
|
53
|
+
namespace: 'http://flowable.org/bpmn',
|
|
54
|
+
|
|
55
|
+
parseProcess(element) {
|
|
56
|
+
const get = (name) => element.getAttributeNS(this.namespace, name) || element.getAttribute(`${this.prefix}:${name}`) || '';
|
|
57
|
+
return {
|
|
58
|
+
candidateStarterUsers: get('candidateStarterUsers'),
|
|
59
|
+
candidateStarterGroups: get('candidateStarterGroups'),
|
|
60
|
+
...parseExtensionProperties(element, this.prefix, this.namespace),
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
processAttributes(model) {
|
|
65
|
+
const p = model.properties || {};
|
|
66
|
+
return {
|
|
67
|
+
...(p.candidateStarterUsers ? { [`${this.prefix}:candidateStarterUsers`]: p.candidateStarterUsers } : {}),
|
|
68
|
+
...(p.candidateStarterGroups ? { [`${this.prefix}:candidateStarterGroups`]: p.candidateStarterGroups } : {}),
|
|
69
|
+
...(p.extensionAttributes || {}),
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
parseNode(element) {
|
|
74
|
+
const get = (name) => element.getAttributeNS(this.namespace, name) || element.getAttribute(`${this.prefix}:${name}`) || '';
|
|
75
|
+
const local = element.localName;
|
|
76
|
+
const common = {
|
|
77
|
+
async: get('async') === 'true',
|
|
78
|
+
exclusive: get('exclusive') !== 'false',
|
|
79
|
+
asyncLeave: get('asyncLeave') === 'true',
|
|
80
|
+
skipExpression: get('skipExpression'),
|
|
81
|
+
...parseExtensionProperties(element, this.prefix, this.namespace),
|
|
82
|
+
};
|
|
83
|
+
if (local === 'userTask') Object.assign(common, {
|
|
84
|
+
assignee: get('assignee'), owner: get('owner'), candidateUsers: get('candidateUsers'), candidateGroups: get('candidateGroups'), formKey: get('formKey'), dueDate: get('dueDate'), priority: get('priority'), category: get('category'),
|
|
85
|
+
});
|
|
86
|
+
if (['serviceTask', 'sendTask', 'businessRuleTask'].includes(local)) Object.assign(common, parseImplementation(element, this.prefix, this.namespace), { resultVariable: get('resultVariable') || get('resultVariableName') });
|
|
87
|
+
if (local === 'scriptTask') common.resultVariable = get('resultVariable') || '';
|
|
88
|
+
if (local === 'callActivity') Object.assign(common, { businessKey: get('businessKey'), inheritBusinessKey: get('inheritBusinessKey') === 'true', inheritVariables: get('inheritVariables') === 'true', sameDeployment: get('sameDeployment') === 'true', processInstanceName: get('processInstanceName') });
|
|
89
|
+
return common;
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
nodeAttributes(node) {
|
|
93
|
+
const p = node.properties || {};
|
|
94
|
+
const attrs = { ...(p.extensionAttributes || {}) };
|
|
95
|
+
if (p.async) attrs[`${this.prefix}:async`] = 'true';
|
|
96
|
+
if (p.exclusive === false) attrs[`${this.prefix}:exclusive`] = 'false';
|
|
97
|
+
if (p.asyncLeave) attrs[`${this.prefix}:asyncLeave`] = 'true';
|
|
98
|
+
if (p.skipExpression) attrs[`${this.prefix}:skipExpression`] = p.skipExpression;
|
|
99
|
+
if (node.type === 'userTask') Object.assign(attrs, {
|
|
100
|
+
...(p.assignee ? { [`${this.prefix}:assignee`]: p.assignee } : {}),
|
|
101
|
+
...(p.owner ? { [`${this.prefix}:owner`]: p.owner } : {}),
|
|
102
|
+
...(p.candidateUsers ? { [`${this.prefix}:candidateUsers`]: p.candidateUsers } : {}),
|
|
103
|
+
...(p.candidateGroups ? { [`${this.prefix}:candidateGroups`]: p.candidateGroups } : {}),
|
|
104
|
+
...(p.formKey ? { [`${this.prefix}:formKey`]: p.formKey } : {}),
|
|
105
|
+
...(p.dueDate ? { [`${this.prefix}:dueDate`]: p.dueDate } : {}),
|
|
106
|
+
...(p.priority !== '' && p.priority != null ? { [`${this.prefix}:priority`]: p.priority } : {}),
|
|
107
|
+
...(p.category ? { [`${this.prefix}:category`]: p.category } : {}),
|
|
108
|
+
});
|
|
109
|
+
if (['serviceTask', 'sendTask', 'businessRuleTask'].includes(node.type) && p.implementation) attrs[`${this.prefix}:${p.implementationType || 'class'}`] = p.implementation;
|
|
110
|
+
if (['serviceTask', 'sendTask', 'businessRuleTask', 'scriptTask'].includes(node.type) && p.resultVariable) attrs[`${this.prefix}:resultVariable`] = p.resultVariable;
|
|
111
|
+
if (node.type === 'callActivity') Object.assign(attrs, {
|
|
112
|
+
...(p.businessKey ? { [`${this.prefix}:businessKey`]: p.businessKey } : {}),
|
|
113
|
+
...(p.inheritBusinessKey ? { [`${this.prefix}:inheritBusinessKey`]: 'true' } : {}),
|
|
114
|
+
...(p.inheritVariables ? { [`${this.prefix}:inheritVariables`]: 'true' } : {}),
|
|
115
|
+
...(p.sameDeployment ? { [`${this.prefix}:sameDeployment`]: 'true' } : {}),
|
|
116
|
+
...(p.processInstanceName ? { [`${this.prefix}:processInstanceName`]: p.processInstanceName } : {}),
|
|
117
|
+
});
|
|
118
|
+
return attrs;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
processExtensionElements(model) {
|
|
122
|
+
return (model.properties?.executionListeners || []).filter((item) => item.implementation).map((item) => listenerXml(this.prefix, 'executionListener', item));
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
nodeExtensionElements(node) {
|
|
126
|
+
const p = node.properties || {};
|
|
127
|
+
const result = [];
|
|
128
|
+
for (const listener of p.executionListeners || []) if (listener.implementation) result.push(listenerXml(this.prefix, 'executionListener', listener));
|
|
129
|
+
for (const listener of p.taskListeners || []) if (listener.implementation) result.push(listenerXml(this.prefix, 'taskListener', listener));
|
|
130
|
+
for (const field of p.fields || []) {
|
|
131
|
+
if (!field.name) continue;
|
|
132
|
+
const tag = field.type === 'expression' ? 'expression' : 'string';
|
|
133
|
+
result.push(`<${this.prefix}:field name="${escapeXml(field.name)}"><${this.prefix}:${tag}>${escapeXml(field.value || '')}</${this.prefix}:${tag}></${this.prefix}:field>`);
|
|
134
|
+
}
|
|
135
|
+
if (p.failedJobRetryTimeCycle) result.push(`<${this.prefix}:failedJobRetryTimeCycle>${escapeXml(p.failedJobRetryTimeCycle)}</${this.prefix}:failedJobRetryTimeCycle>`);
|
|
136
|
+
return result;
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
nodeChildElements(node) {
|
|
140
|
+
if (node.type !== 'callActivity') return [];
|
|
141
|
+
const result = [];
|
|
142
|
+
for (const row of node.properties?.inParameters || []) {
|
|
143
|
+
const attrs = [row.source ? `source="${escapeXml(row.source)}"` : '', row.sourceExpression ? `sourceExpression="${escapeXml(row.sourceExpression)}"` : '', row.target ? `target="${escapeXml(row.target)}"` : ''].filter(Boolean).join(' ');
|
|
144
|
+
if (attrs) result.push(`<${this.prefix}:in ${attrs} />`);
|
|
145
|
+
}
|
|
146
|
+
for (const row of node.properties?.outParameters || []) {
|
|
147
|
+
const attrs = [row.source ? `source="${escapeXml(row.source)}"` : '', row.sourceExpression ? `sourceExpression="${escapeXml(row.sourceExpression)}"` : '', row.target ? `target="${escapeXml(row.target)}"` : ''].filter(Boolean).join(' ');
|
|
148
|
+
if (attrs) result.push(`<${this.prefix}:out ${attrs} />`);
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
parseEdge(element) {
|
|
154
|
+
return { ...parseExtensionProperties(element, this.prefix, this.namespace) };
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
edgeExtensionElements(edge) {
|
|
158
|
+
return (edge.properties?.executionListeners || []).filter((item) => item.implementation).map((item) => listenerXml(this.prefix, 'executionListener', item));
|
|
159
|
+
},
|
|
160
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { BpmnNode, ProcessModel } from '../core/index.js'
|
|
2
|
+
import type { IconRegistry, NodeVisualResolution } from '../icons/index.js'
|
|
3
|
+
import type { NodeRuntimePresentation, ProcessInstanceSnapshot, RuntimeApprovalActionPresentation, RuntimePresentation, RuntimeAssetRef } from '../runtime/index.js'
|
|
4
|
+
import type { NovaResolvedTheme, NovaThemeSnapshot, RuntimeAppearanceOptions, RuntimeAppearanceResolver, ThemeController } from '../theme/index.js'
|
|
5
|
+
|
|
6
|
+
export type SvgExportTheme = 'current' | NovaResolvedTheme
|
|
7
|
+
export interface SvgExportOptions {
|
|
8
|
+
theme?: SvgExportTheme
|
|
9
|
+
transparentBackground?: boolean
|
|
10
|
+
padding?: number
|
|
11
|
+
filename?: string
|
|
12
|
+
title?: string
|
|
13
|
+
signal?: AbortSignal
|
|
14
|
+
}
|
|
15
|
+
export interface SvgExportWarning {
|
|
16
|
+
code: string
|
|
17
|
+
message: string
|
|
18
|
+
elementId?: string
|
|
19
|
+
assetId?: string
|
|
20
|
+
}
|
|
21
|
+
export interface SvgExportArtifact {
|
|
22
|
+
svg: string
|
|
23
|
+
blob: Blob
|
|
24
|
+
filename: string
|
|
25
|
+
mimeType: 'image/svg+xml'
|
|
26
|
+
width: number
|
|
27
|
+
height: number
|
|
28
|
+
viewBox: { x: number; y: number; width: number; height: number }
|
|
29
|
+
warnings: readonly SvgExportWarning[]
|
|
30
|
+
}
|
|
31
|
+
export interface SvgNodeRendererContext {
|
|
32
|
+
container: SVGGElement
|
|
33
|
+
node: BpmnNode
|
|
34
|
+
definition: Record<string, unknown>
|
|
35
|
+
runtimePresentation: NodeRuntimePresentation | null
|
|
36
|
+
visual: NodeVisualResolution
|
|
37
|
+
model: ProcessModel
|
|
38
|
+
themeSnapshot: NovaThemeSnapshot
|
|
39
|
+
iconRegistry: IconRegistry
|
|
40
|
+
}
|
|
41
|
+
export type SvgNodeRenderer = (context: SvgNodeRendererContext) => void | boolean
|
|
42
|
+
export type RuntimeTimelineSvgRenderer = (context: {
|
|
43
|
+
container: SVGGElement
|
|
44
|
+
document: Document
|
|
45
|
+
projection: Record<string, unknown>
|
|
46
|
+
model: ProcessModel
|
|
47
|
+
runtime: ProcessInstanceSnapshot | null
|
|
48
|
+
themeSnapshot: NovaThemeSnapshot
|
|
49
|
+
appearance: RuntimeAppearanceResolver
|
|
50
|
+
resolveAsset?: SvgRuntimeAssetResolver
|
|
51
|
+
signal?: AbortSignal
|
|
52
|
+
}) => void | { height?: number } | Promise<void | { height?: number }>
|
|
53
|
+
export type SvgRuntimeAssetResolver = (asset: RuntimeAssetRef, purpose: 'export', action: RuntimeApprovalActionPresentation) => string | null | Promise<string | null>
|
|
54
|
+
export interface DiagramSvgExportContext {
|
|
55
|
+
document?: Document
|
|
56
|
+
root?: HTMLElement
|
|
57
|
+
model: ProcessModel
|
|
58
|
+
visualModel?: ProcessModel
|
|
59
|
+
runtime?: ProcessInstanceSnapshot | null
|
|
60
|
+
runtimePresentation?: RuntimePresentation
|
|
61
|
+
runtimeAppearance?: RuntimeAppearanceOptions | RuntimeAppearanceResolver | null
|
|
62
|
+
themeController?: ThemeController
|
|
63
|
+
themeSnapshot?: NovaThemeSnapshot
|
|
64
|
+
iconRegistry?: IconRegistry
|
|
65
|
+
nodeRenderers?: Record<string, SvgNodeRenderer>
|
|
66
|
+
htmlNodeRenderers?: Record<string, Function>
|
|
67
|
+
htmlNodeRenderer?: Function
|
|
68
|
+
mode?: 'design' | 'viewer' | 'instance'
|
|
69
|
+
label?: string
|
|
70
|
+
}
|
|
71
|
+
export interface RuntimeTimelineSvgExportContext {
|
|
72
|
+
document?: Document
|
|
73
|
+
root?: HTMLElement
|
|
74
|
+
model: ProcessModel
|
|
75
|
+
runtime: ProcessInstanceSnapshot | null
|
|
76
|
+
projection: { items: any[]; groups: any[]; links: any[] }
|
|
77
|
+
title?: string | null
|
|
78
|
+
description?: string | null
|
|
79
|
+
runtimeAppearance?: RuntimeAppearanceOptions | RuntimeAppearanceResolver | null
|
|
80
|
+
themeController?: ThemeController
|
|
81
|
+
themeSnapshot?: NovaThemeSnapshot
|
|
82
|
+
iconRegistry?: IconRegistry
|
|
83
|
+
resolveAsset?: SvgRuntimeAssetResolver
|
|
84
|
+
assetCache?: Map<string, string>
|
|
85
|
+
timelineRenderer?: RuntimeTimelineSvgRenderer
|
|
86
|
+
label?: string
|
|
87
|
+
}
|
|
88
|
+
export function sanitizeSvgFilename(value: string, fallback?: string): string
|
|
89
|
+
export function exportDiagramSvg(context: DiagramSvgExportContext, options?: SvgExportOptions): Promise<SvgExportArtifact>
|
|
90
|
+
export function exportRuntimeTimelineSvg(context: RuntimeTimelineSvgExportContext, options?: SvgExportOptions & { width?: number; description?: string }): Promise<SvgExportArtifact>
|
|
91
|
+
export function downloadSvg(artifact: SvgExportArtifact, options?: { document?: Document }): string
|
|
92
|
+
|
|
93
|
+
export interface SvgExportPreviewOptions {
|
|
94
|
+
container: HTMLElement
|
|
95
|
+
createArtifact(options: SvgExportOptions): Promise<SvgExportArtifact>
|
|
96
|
+
title?: string
|
|
97
|
+
initialTheme?: SvgExportTheme
|
|
98
|
+
onClose?: () => void
|
|
99
|
+
onDownload?: (artifact: SvgExportArtifact) => void
|
|
100
|
+
}
|
|
101
|
+
export class SvgExportPreviewController {
|
|
102
|
+
constructor(options: SvgExportPreviewOptions)
|
|
103
|
+
readonly artifact: SvgExportArtifact | null
|
|
104
|
+
readonly closed: boolean
|
|
105
|
+
setTheme(theme: SvgExportTheme): void
|
|
106
|
+
setTransparentBackground(value: boolean): void
|
|
107
|
+
fit(): void
|
|
108
|
+
actualSize(): void
|
|
109
|
+
focus(): void
|
|
110
|
+
close(options?: { immediate?: boolean }): void
|
|
111
|
+
}
|
|
112
|
+
export function openSvgExportPreview(options: SvgExportPreviewOptions): SvgExportPreviewController
|