@valtimo/process-management 13.42.0 → 13.43.0

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.
Files changed (37) hide show
  1. package/fesm2022/valtimo-process-management.mjs +1411 -101
  2. package/fesm2022/valtimo-process-management.mjs.map +1 -1
  3. package/lib/components/process-management-builder/panel/expression-autocomplete.d.ts +37 -0
  4. package/lib/components/process-management-builder/panel/expression-autocomplete.d.ts.map +1 -0
  5. package/lib/components/process-management-builder/panel/index.d.ts +1 -0
  6. package/lib/components/process-management-builder/panel/index.d.ts.map +1 -1
  7. package/lib/components/process-management-builder/panel/valtimo-properties-provider.d.ts +2 -0
  8. package/lib/components/process-management-builder/panel/valtimo-properties-provider.d.ts.map +1 -1
  9. package/lib/components/process-management-builder/process-management-builder.component.d.ts +34 -3
  10. package/lib/components/process-management-builder/process-management-builder.component.d.ts.map +1 -1
  11. package/lib/components/process-management-list/process-management-list.component.d.ts +1 -0
  12. package/lib/components/process-management-list/process-management-list.component.d.ts.map +1 -1
  13. package/lib/components/process-management-upload/process-management-upload.component.d.ts +38 -1
  14. package/lib/components/process-management-upload/process-management-upload.component.d.ts.map +1 -1
  15. package/lib/constants/process-management.test-ids.d.ts +2 -0
  16. package/lib/constants/process-management.test-ids.d.ts.map +1 -1
  17. package/lib/models/index.d.ts +2 -0
  18. package/lib/models/index.d.ts.map +1 -1
  19. package/lib/models/process-bean.model.d.ts +19 -0
  20. package/lib/models/process-bean.model.d.ts.map +1 -0
  21. package/lib/models/process-definition-import.model.d.ts +37 -0
  22. package/lib/models/process-definition-import.model.d.ts.map +1 -0
  23. package/lib/models/process-management.model.d.ts +14 -1
  24. package/lib/models/process-management.model.d.ts.map +1 -1
  25. package/lib/models/process.model.d.ts +2 -0
  26. package/lib/models/process.model.d.ts.map +1 -1
  27. package/lib/models/window.model.d.ts +2 -0
  28. package/lib/models/window.model.d.ts.map +1 -1
  29. package/lib/services/index.d.ts +1 -0
  30. package/lib/services/index.d.ts.map +1 -1
  31. package/lib/services/process-bean.service.d.ts +15 -0
  32. package/lib/services/process-bean.service.d.ts.map +1 -0
  33. package/lib/services/process-management-editor.service.d.ts +12 -0
  34. package/lib/services/process-management-editor.service.d.ts.map +1 -1
  35. package/lib/services/process-management.service.d.ts +5 -2
  36. package/lib/services/process-management.service.d.ts.map +1 -1
  37. package/package.json +1 -1
@@ -7,16 +7,15 @@ import { ReactiveFormsModule, Validators, FormsModule } from '@angular/forms';
7
7
  import * as i9 from '@ngx-translate/core';
8
8
  import { TranslateModule, TranslateService } from '@ngx-translate/core';
9
9
  import * as i1$1 from '@valtimo/components';
10
- import { FitPageDirective, RenderInPageHeaderDirective, OverflowMenuComponent, OverflowMenuOptionComponent, OverflowMenuTriggerComponent, ConfirmationModalModule, ViewType, CarbonListModule, CARBON_CONSTANTS, RenderInBodyComponent, ValtimoCdsModalDirective, WidgetModule } from '@valtimo/components';
10
+ import { FitPageDirective, RenderInPageHeaderDirective, ConfirmationModalModule, OverflowMenuModule, ViewType, CarbonListModule, CARBON_CONSTANTS, RenderInBodyComponent, ValtimoCdsModalDirective, WidgetModule } from '@valtimo/components';
11
11
  import * as i5 from '@valtimo/process-link';
12
12
  import { ProcessLinkModule, ProcessLinkStateService, ProcessLinkStepService, ProcessLinkButtonService } from '@valtimo/process-link';
13
13
  import * as i2$2 from 'carbon-components-angular';
14
14
  import { LoadingModule, DropdownModule, SelectModule, ButtonModule, IconModule, TagModule, ToggleModule, TooltipModule, FileUploaderModule, ModalModule, LayerModule, NotificationModule, RadioModule } from 'carbon-components-angular';
15
15
  import * as i1 from '@angular/common/http';
16
- import { HttpErrorResponse } from '@angular/common/http';
17
- import { Deploy16, ListChecked16, Return16, Upload16 } from '@carbon/icons';
18
- import * as i2$1 from '@valtimo/shared';
19
- import { BaseApiService, getCaseManagementRouteParams, getBuildingBlockManagementRouteParams, ROLE_ADMIN } from '@valtimo/shared';
16
+ import { HttpHeaders, HttpErrorResponse } from '@angular/common/http';
17
+ import * as i2 from '@valtimo/shared';
18
+ import { BaseApiService, InterceptorSkipHeader, InterceptorSkip, getCaseManagementRouteParams, getBuildingBlockManagementRouteParams, ROLE_ADMIN } from '@valtimo/shared';
20
19
  import { useService, BpmnPropertiesPanelModule, BpmnPropertiesProviderModule, CamundaPlatformPropertiesProviderModule } from 'bpmn-js-properties-panel';
21
20
  import Modeler from 'bpmn-js/lib/Modeler';
22
21
  import camundaPlatformBehaviors from 'camunda-bpmn-js-behaviors/lib/camunda-platform';
@@ -24,15 +23,17 @@ import CamundaBpmnModdle from 'camunda-bpmn-moddle/resources/camunda.json';
24
23
  import { isEqual } from 'lodash';
25
24
  import { filter, BehaviorSubject, Subject, Subscription, combineLatest, switchMap, of, tap, map as map$1, startWith, from, take, merge } from 'rxjs';
26
25
  import { distinctUntilChanged, map, filter as filter$1 } from 'rxjs/operators';
27
- import * as i2 from '@valtimo/form';
26
+ import * as i2$1 from '@valtimo/form';
28
27
  import { toObservable } from '@angular/core/rxjs-interop';
29
28
  import { is } from 'bpmn-js/lib/util/ModelUtil';
30
29
  import { html } from 'htm/preact';
30
+ import { View16, ViewOff16, Upload16 } from '@carbon/icons';
31
31
  import * as i3 from 'ngx-logger';
32
32
  import * as i7 from '@valtimo/process';
33
33
  import * as i8 from '@angular/router';
34
34
  import { RouterModule } from '@angular/router';
35
35
  import * as i10 from '@valtimo/plugin';
36
+ import { PluginConfigurationMappingComponent } from '@valtimo/plugin';
36
37
  import { AuthGuardService } from '@valtimo/security';
37
38
 
38
39
  /*
@@ -90,6 +91,8 @@ const PROCESS_MANAGEMENT_BUILDER_TEST_IDS = {
90
91
  startsCaseToggle: 'processManagementBuilderStartsCaseToggle',
91
92
  startableByUserToggle: 'processManagementBuilderStartableByUserToggle',
92
93
  deployButton: 'processManagementBuilderDeployButton',
94
+ exportOption: 'processManagementBuilderExportOption',
95
+ markersVisibilityToggle: 'processManagementBuilderMarkersVisibilityToggle',
93
96
  };
94
97
 
95
98
  /*
@@ -108,8 +111,30 @@ const PROCESS_MANAGEMENT_BUILDER_TEST_IDS = {
108
111
  * limitations under the License.
109
112
  */
110
113
 
114
+ class ProcessBeanService extends BaseApiService {
115
+ constructor(httpClient, configService) {
116
+ super(httpClient, configService);
117
+ this.httpClient = httpClient;
118
+ this.configService = configService;
119
+ }
120
+ getProcessBeans() {
121
+ return this.httpClient.get(this.getApiUrl('/management/v1/process-bean'));
122
+ }
123
+ getProcessBean(beanName) {
124
+ return this.httpClient.get(this.getApiUrl(`/management/v1/process-bean/${beanName}`));
125
+ }
126
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessBeanService, deps: [{ token: i1.HttpClient }, { token: i2.ConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
127
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessBeanService, providedIn: 'root' }); }
128
+ }
129
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessBeanService, decorators: [{
130
+ type: Injectable,
131
+ args: [{
132
+ providedIn: 'root',
133
+ }]
134
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.ConfigService }] });
135
+
111
136
  /*
112
- * Copyright 2015-2025 Ritense BV, the Netherlands.
137
+ * Copyright 2015-2026 Ritense BV, the Netherlands.
113
138
  *
114
139
  * Licensed under EUPL, Version 1.2 (the "License");
115
140
  * you may not use this file except in compliance with the License.
@@ -154,6 +179,33 @@ class ProcessManagementEditorService {
154
179
  setValidationErrors(errors) {
155
180
  this._validationErrors$.next(errors);
156
181
  }
182
+ get dismissedAutofills() {
183
+ return this._dismissedAutofills$.getValue();
184
+ }
185
+ get autofillDismissed$() {
186
+ return this._autofillDismissed$.asObservable();
187
+ }
188
+ dismissAutofill(activityId) {
189
+ const current = this._dismissedAutofills$.getValue();
190
+ current.add(activityId);
191
+ this._dismissedAutofills$.next(new Set(current));
192
+ this._autofillDismissed$.next(activityId);
193
+ }
194
+ clearDismissedAutofills() {
195
+ this._dismissedAutofills$.next(new Set());
196
+ }
197
+ isAutofillDismissed(activityId) {
198
+ return this._dismissedAutofills$.getValue().has(activityId);
199
+ }
200
+ get autofilledElements() {
201
+ return this._autofilledElements$.getValue();
202
+ }
203
+ setAutofilledElements(elements) {
204
+ this._autofilledElements$.next(elements);
205
+ }
206
+ getAutofillForActivity(activityId) {
207
+ return this._autofilledElements$.getValue().find(e => e.activityId === activityId);
208
+ }
157
209
  constructor(processLinkService, formService) {
158
210
  this.processLinkService = processLinkService;
159
211
  this.formService = formService;
@@ -165,6 +217,9 @@ class ProcessManagementEditorService {
165
217
  this._formDefinitionOptions$ = new BehaviorSubject([]);
166
218
  this._validationErrors$ = new BehaviorSubject([]);
167
219
  this.validationErrors$ = this._validationErrors$.asObservable();
220
+ this._dismissedAutofills$ = new BehaviorSubject(new Set());
221
+ this._autofillDismissed$ = new Subject();
222
+ this._autofilledElements$ = new BehaviorSubject([]);
168
223
  this._updatingBpmnView = false;
169
224
  this._activityIdBusinessIdMap = {};
170
225
  this._subscriptions = new Subscription();
@@ -275,12 +330,12 @@ class ProcessManagementEditorService {
275
330
  }
276
331
  }));
277
332
  }
278
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementEditorService, deps: [{ token: i5.ProcessLinkService }, { token: i2.FormService }], target: i0.ɵɵFactoryTarget.Injectable }); }
333
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementEditorService, deps: [{ token: i5.ProcessLinkService }, { token: i2$1.FormService }], target: i0.ɵɵFactoryTarget.Injectable }); }
279
334
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementEditorService }); }
280
335
  }
281
336
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementEditorService, decorators: [{
282
337
  type: Injectable
283
- }], ctorParameters: () => [{ type: i5.ProcessLinkService }, { type: i2.FormService }] });
338
+ }], ctorParameters: () => [{ type: i5.ProcessLinkService }, { type: i2$1.FormService }] });
284
339
 
285
340
  /*
286
341
  * Copyright 2015-2025 Ritense BV, the Netherlands.
@@ -326,7 +381,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
326
381
  }] });
327
382
 
328
383
  /*
329
- * Copyright 2015-2025 Ritense BV, the Netherlands.
384
+ * Copyright 2015-2026 Ritense BV, the Netherlands.
330
385
  *
331
386
  * Licensed under EUPL, Version 1.2 (the "License");
332
387
  * you may not use this file except in compliance with the License.
@@ -358,7 +413,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
358
413
  */
359
414
 
360
415
  /*
361
- * Copyright 2015-2025 Ritense BV, the Netherlands.
416
+ * Copyright 2015-2026 Ritense BV, the Netherlands.
417
+ *
418
+ * Licensed under EUPL, Version 1.2 (the "License");
419
+ * you may not use this file except in compliance with the License.
420
+ * You may obtain a copy of the License at
421
+ *
422
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
423
+ *
424
+ * Unless required by applicable law or agreed to in writing, software
425
+ * distributed under the License is distributed on an "AS IS" basis,
426
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
427
+ * See the License for the specific language governing permissions and
428
+ * limitations under the License.
429
+ */
430
+
431
+ /*
432
+ * Copyright 2015-2026 Ritense BV, the Netherlands.
433
+ *
434
+ * Licensed under EUPL, Version 1.2 (the "License");
435
+ * you may not use this file except in compliance with the License.
436
+ * You may obtain a copy of the License at
437
+ *
438
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
439
+ *
440
+ * Unless required by applicable law or agreed to in writing, software
441
+ * distributed under the License is distributed on an "AS IS" basis,
442
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
443
+ * See the License for the specific language governing permissions and
444
+ * limitations under the License.
445
+ */
446
+
447
+ /*
448
+ * Copyright 2015-2026 Ritense BV, the Netherlands.
362
449
  *
363
450
  * Licensed under EUPL, Version 1.2 (the "License");
364
451
  * you may not use this file except in compliance with the License.
@@ -378,7 +465,7 @@ const PROCESS_MANAGEMENT_ENDPOINTS = {
378
465
  };
379
466
 
380
467
  /*
381
- * Copyright 2015-2025 Ritense BV, the Netherlands.
468
+ * Copyright 2015-2026 Ritense BV, the Netherlands.
382
469
  *
383
470
  * Licensed under EUPL, Version 1.2 (the "License");
384
471
  * you may not use this file except in compliance with the License.
@@ -409,6 +496,21 @@ const PROCESS_MANAGEMENT_ENDPOINTS = {
409
496
  * limitations under the License.
410
497
  */
411
498
 
499
+ /*
500
+ * Copyright 2015-2025 Ritense BV, the Netherlands.
501
+ *
502
+ * Licensed under EUPL, Version 1.2 (the "License");
503
+ * you may not use this file except in compliance with the License.
504
+ * You may obtain a copy of the License at
505
+ *
506
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
507
+ *
508
+ * Unless required by applicable law or agreed to in writing, software
509
+ * distributed under the License is distributed on an "AS IS" basis,
510
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
511
+ * See the License for the specific language governing permissions and
512
+ * limitations under the License.
513
+ */
412
514
  class ProcessManagementService extends BaseApiService {
413
515
  get caseDefinitionKey() {
414
516
  return this._definitionKey$.getValue() ?? '';
@@ -475,6 +577,18 @@ class ProcessManagementService extends BaseApiService {
475
577
  updateProcessDefinitionCaseDefinitionProperties(caseDefinitionKey, caseDefinitionVersionTag, processDefinitionId, body) {
476
578
  return this.httpClient.put(this.getApiUrl(`/management/v1/case-definition/${caseDefinitionKey}/version/${caseDefinitionVersionTag}/process/${processDefinitionId}/properties`), body);
477
579
  }
580
+ exportProcessDefinition(processDefinitionId) {
581
+ return this.httpClient.get(this.getApiUrl(`/management/v1/process-definition/${processDefinitionId}/export`), { observe: 'response', responseType: 'blob', headers: InterceptorSkipHeader });
582
+ }
583
+ previewProcessDefinitionImport(file) {
584
+ return this.httpClient.post(this.getApiUrl('/management/v1/process-definition/import/preview'), file, { headers: new HttpHeaders().set(InterceptorSkip, '400') });
585
+ }
586
+ importProcessDefinition(file, pluginConfigurationMappings) {
587
+ if (pluginConfigurationMappings) {
588
+ file.set('pluginConfigurationMappings', new Blob([JSON.stringify(pluginConfigurationMappings)], { type: 'application/json' }));
589
+ }
590
+ return this.httpClient.post(this.getApiUrl('/management/v1/process-definition/import'), file, { headers: new HttpHeaders().set(InterceptorSkip, '400') });
591
+ }
478
592
  validateProcessDefinition(request) {
479
593
  return this.httpClient.post(this.getApiUrl('/management/v1/process-definition/validate'), request);
480
594
  }
@@ -499,7 +613,7 @@ class ProcessManagementService extends BaseApiService {
499
613
  }
500
614
  return object;
501
615
  }
502
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementService, deps: [{ token: i1.HttpClient }, { token: i2$1.ConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
616
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementService, deps: [{ token: i1.HttpClient }, { token: i2.ConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
503
617
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementService, providedIn: 'root' }); }
504
618
  }
505
619
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementService, decorators: [{
@@ -507,7 +621,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
507
621
  args: [{
508
622
  providedIn: 'root',
509
623
  }]
510
- }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2$1.ConfigService }] });
624
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.ConfigService }] });
511
625
 
512
626
  /*
513
627
  * Copyright 2015-2025 Ritense BV, the Netherlands.
@@ -759,6 +873,9 @@ class ValtimoPropertiesProvider {
759
873
  get pluginTranslationService() {
760
874
  return window.pluginTranslationService;
761
875
  }
876
+ get processLinkService() {
877
+ return window.processLinkService;
878
+ }
762
879
  constructor(propertiesPanel) {
763
880
  propertiesPanel.registerProvider(500, this);
764
881
  }
@@ -774,6 +891,8 @@ class ValtimoPropertiesProvider {
774
891
  getGroups(element) {
775
892
  const processLink = this.processManagementEditorService.processLinksForSelectedDefinition.find(processLink => processLink.activityId === element.id) || null;
776
893
  const elementErrors = this.processManagementEditorService.validationErrors.filter(error => error.elementId === element.id);
894
+ const autofillInfo = this.processManagementEditorService.getAutofillForActivity(element.id);
895
+ const isAutofillDismissed = this.processManagementEditorService.isAutofillDismissed(element.id);
777
896
  return (groups) => {
778
897
  const generalGroup = groups.find((g) => g.id === 'general');
779
898
  if (generalGroup) {
@@ -795,6 +914,23 @@ class ValtimoPropertiesProvider {
795
914
  };
796
915
  groups.unshift(errorGroup);
797
916
  }
917
+ if (autofillInfo && !isAutofillDismissed) {
918
+ const targetGroupId = this.getGroupIdForModificationType(autofillInfo.modificationType);
919
+ const targetGroup = groups.find((g) => g.id === targetGroupId);
920
+ if (targetGroup) {
921
+ const notificationEntry = {
922
+ id: 'autofilledNotificationEntry',
923
+ activityId: element.id,
924
+ element,
925
+ translateService: this.translateService,
926
+ processManagementEditorService: this.processManagementEditorService,
927
+ processLinkService: this.processLinkService,
928
+ component: AutofilledNotificationElement,
929
+ };
930
+ targetGroup.entries.unshift(notificationEntry);
931
+ targetGroup.shouldOpen = true;
932
+ }
933
+ }
798
934
  if (is(element, 'bpmn:UserTask') ||
799
935
  is(element, 'bpmn:StartEvent') ||
800
936
  is(element, 'bpmn:ServiceTask') ||
@@ -814,6 +950,16 @@ class ValtimoPropertiesProvider {
814
950
  return groups;
815
951
  };
816
952
  }
953
+ getGroupIdForModificationType(modificationType) {
954
+ const groupMapping = {
955
+ SERVICE_TASK_EXPRESSION: 'CamundaPlatform__Implementation',
956
+ SEND_TASK_EXPRESSION: 'CamundaPlatform__Implementation',
957
+ MESSAGE_EVENT_EXPRESSION: 'message',
958
+ TIMER_DURATION: 'timer',
959
+ CALL_ACTIVITY_BUSINESS_KEY: 'CamundaPlatform__BusinessKey',
960
+ };
961
+ return groupMapping[modificationType] || 'general';
962
+ }
817
963
  createCustomRootElement(element, processLink) {
818
964
  return {
819
965
  translateService: this.translateService,
@@ -823,7 +969,7 @@ class ValtimoPropertiesProvider {
823
969
  processLink,
824
970
  element,
825
971
  component: CustomRootElement,
826
- isEdited: () => false,
972
+ isEdited: (node) => node && !!node.value,
827
973
  };
828
974
  }
829
975
  }
@@ -874,8 +1020,10 @@ const CustomRootElement = (props) => {
874
1020
  };
875
1021
  const processLinkFormDefinitionId = processLink?.formDefinitionId;
876
1022
  const processLinkFormDefinitionName = processManagementEditorService.formDefinitionOptions.find(option => option.id === processLinkFormDefinitionId)?.name;
1023
+ const hiddenInput = html `<input type="hidden" class="bio-properties-panel-input" value=${processLink ? 'configured' : ''} />`;
1024
+ const wrapEntry = (content) => html `<div data-entry-id=${props.id}>${hiddenInput}${content}</div>`;
877
1025
  if (processLinkFormDefinitionName) {
878
- return html `<div class="process-link-properties-panel">
1026
+ return wrapEntry(html `<div class="process-link-properties-panel">
879
1027
  <div class="process-link-properties-panel__header">
880
1028
  <span class="process-link-properties-panel__title">${processLinkFormDefinitionName}</span>
881
1029
 
@@ -902,11 +1050,11 @@ const CustomRootElement = (props) => {
902
1050
  ${editProcessLinkText}
903
1051
  </button>
904
1052
  </div>
905
- </div>`;
1053
+ </div>`);
906
1054
  }
907
1055
  const processLinkFormFlowDefinitionKey = processLink?.formFlowDefinitionKey;
908
1056
  if (processLinkFormFlowDefinitionKey) {
909
- return html `<div class="process-link-properties-panel">
1057
+ return wrapEntry(html `<div class="process-link-properties-panel">
910
1058
  <div class="process-link-properties-panel__header">
911
1059
  <span class="process-link-properties-panel__title"
912
1060
  >${processLinkFormFlowDefinitionKey}</span
@@ -935,12 +1083,12 @@ const CustomRootElement = (props) => {
935
1083
  ${editProcessLinkText}
936
1084
  </button>
937
1085
  </div>
938
- </div>`;
1086
+ </div>`);
939
1087
  }
940
1088
  const buildingBlockDefinitionKey = processLink?.buildingBlockDefinitionKey;
941
1089
  const buildingBlockDefinitionVersion = processLink?.buildingBlockDefinitionVersionTag;
942
1090
  if (buildingBlockDefinitionKey) {
943
- return html `<div class="process-link-properties-panel">
1091
+ return wrapEntry(html `<div class="process-link-properties-panel">
944
1092
  <div class="process-link-properties-panel__header">
945
1093
  <span class="process-link-properties-panel__title"
946
1094
  >${buildingBlockDefinitionKey} (${buildingBlockDefinitionVersion})</span
@@ -969,13 +1117,13 @@ const CustomRootElement = (props) => {
969
1117
  ${editProcessLinkText}
970
1118
  </button>
971
1119
  </div>
972
- </div>`;
1120
+ </div>`);
973
1121
  }
974
1122
  const pluginActionKey = processLink?.pluginActionDefinitionKey;
975
1123
  const pluginActionTranslation = pluginTranslationService.instantByPluginActionKey(pluginActionKey);
976
1124
  const pluginTitleTranslation = pluginTranslationService.instantPluginTitleByPluginActionKey(pluginActionKey);
977
1125
  if (pluginActionKey) {
978
- return html `<div class="process-link-properties-panel">
1126
+ return wrapEntry(html `<div class="process-link-properties-panel">
979
1127
  <div class="process-link-properties-panel__header">
980
1128
  <span class="process-link-properties-panel__title-container">
981
1129
  <span class="process-link-properties-panel__title">${pluginTitleTranslation}</span>
@@ -1006,11 +1154,11 @@ const CustomRootElement = (props) => {
1006
1154
  ${editProcessLinkText}
1007
1155
  </button>
1008
1156
  </div>
1009
- </div>`;
1157
+ </div>`);
1010
1158
  }
1011
1159
  const uiComponentKey = processLink?.componentKey;
1012
1160
  if (uiComponentKey) {
1013
- return html `<div class="process-link-properties-panel">
1161
+ return wrapEntry(html `<div class="process-link-properties-panel">
1014
1162
  <div class="process-link-properties-panel__header">
1015
1163
  <span class="process-link-properties-panel__title">${uiComponentKey}</span>
1016
1164
 
@@ -1037,7 +1185,7 @@ const CustomRootElement = (props) => {
1037
1185
  ${editProcessLinkText}
1038
1186
  </button>
1039
1187
  </div>
1040
- </div>`;
1188
+ </div>`);
1041
1189
  }
1042
1190
  const genericLinkedPanel = html `<div class="process-link-properties-panel">
1043
1191
  <div class="process-link-properties-panel__buttons">
@@ -1066,13 +1214,13 @@ const CustomRootElement = (props) => {
1066
1214
  </button>
1067
1215
  </div>
1068
1216
  </div>`;
1069
- return processLink ? genericLinkedPanel : genericCreatePanel;
1217
+ return wrapEntry(processLink ? genericLinkedPanel : genericCreatePanel);
1070
1218
  };
1071
1219
  const ValidationErrorsElement = (props) => {
1072
1220
  const getErrorMessage = (error) => {
1073
1221
  if (error.errorCode) {
1074
- const translationKey = `processManagement.expressionErrors.${error.errorCode}`;
1075
- const translated = props.translateService.instant(translationKey, { expression: error.expression ? `'${error.expression}'` : '' });
1222
+ const translationKey = `processManagement.validationErrorCodes.${error.errorCode}`;
1223
+ const translated = props.translateService.instant(translationKey, { expression: error.expression ?? '' });
1076
1224
  if (translated !== translationKey) {
1077
1225
  return translated;
1078
1226
  }
@@ -1086,11 +1234,624 @@ const ValidationErrorsElement = (props) => {
1086
1234
  </div>`)}
1087
1235
  </div>`;
1088
1236
  };
1237
+ const AutofilledNotificationElement = (props) => {
1238
+ const handleDismiss = (event) => {
1239
+ const processDefinitionId = props.processManagementEditorService.selectionProcessDefinition?.id;
1240
+ if (processDefinitionId) {
1241
+ props.processLinkService.deleteAutofill(processDefinitionId, props.activityId).subscribe();
1242
+ }
1243
+ props.processManagementEditorService.dismissAutofill(props.activityId);
1244
+ const target = event.currentTarget;
1245
+ const panel = target.closest('.autofilled-notification-panel');
1246
+ if (panel) {
1247
+ panel.style.display = 'none';
1248
+ }
1249
+ };
1250
+ return html `<div class="autofilled-notification-panel">
1251
+ <span class="autofilled-notification-panel__icon">!</span>
1252
+ <span class="autofilled-notification-panel__message">
1253
+ ${props.translateService.instant('processManagement.autofilled.sidebarMessage')}
1254
+ </span>
1255
+ <button class="autofilled-notification-panel__dismiss" onClick=${handleDismiss}>×</button>
1256
+ </div>`;
1257
+ };
1089
1258
  const ValtimoPropertiesProviderModule = {
1090
1259
  __init__: ['customPropertiesProvider'],
1091
1260
  customPropertiesProvider: ['type', ValtimoPropertiesProvider],
1092
1261
  };
1093
1262
 
1263
+ /*
1264
+ * Copyright 2015-2026 Ritense BV, the Netherlands.
1265
+ *
1266
+ * Licensed under EUPL, Version 1.2 (the "License");
1267
+ * you may not use this file except in compliance with the License.
1268
+ * You may obtain a copy of the License at
1269
+ *
1270
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
1271
+ *
1272
+ * Unless required by applicable law or agreed to in writing, software
1273
+ * distributed under the License is distributed on an "AS IS" basis,
1274
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1275
+ * See the License for the specific language governing permissions and
1276
+ * limitations under the License.
1277
+ */
1278
+ class ExpressionAutocomplete {
1279
+ static { this.$inject = ['eventBus']; }
1280
+ constructor(eventBus) {
1281
+ this.processBeans = [];
1282
+ this.panelContainer = null;
1283
+ this.stylesInjected = false;
1284
+ this.observer = null;
1285
+ this.documentClickHandlers = [];
1286
+ this.injectStyles();
1287
+ eventBus.on('diagram.destroy', () => {
1288
+ this.dispose();
1289
+ });
1290
+ }
1291
+ dispose() {
1292
+ this.cleanupClickHandlers();
1293
+ if (this.observer) {
1294
+ this.observer.disconnect();
1295
+ this.observer = null;
1296
+ }
1297
+ this.panelContainer = null;
1298
+ }
1299
+ cleanupClickHandlers() {
1300
+ for (const handler of this.documentClickHandlers) {
1301
+ document.removeEventListener('click', handler);
1302
+ }
1303
+ this.documentClickHandlers = [];
1304
+ }
1305
+ setProcessBeans(beans) {
1306
+ this.processBeans = beans;
1307
+ }
1308
+ setPanelContainer(container) {
1309
+ this.panelContainer = container;
1310
+ this.startObserving();
1311
+ setTimeout(() => this.scanAndAttach(), 100);
1312
+ }
1313
+ startObserving() {
1314
+ if (!this.panelContainer || this.observer)
1315
+ return;
1316
+ this.observer = new MutationObserver(() => {
1317
+ this.scanAndAttach();
1318
+ });
1319
+ this.observer.observe(this.panelContainer, {
1320
+ childList: true,
1321
+ subtree: true,
1322
+ });
1323
+ }
1324
+ scanAndAttach() {
1325
+ if (!this.panelContainer)
1326
+ return;
1327
+ const allInputs = this.panelContainer.querySelectorAll('input, textarea');
1328
+ allInputs.forEach(input => {
1329
+ if (input.dataset.autocompleteAttached)
1330
+ return;
1331
+ if (this.isExpressionField(input)) {
1332
+ this.attachAutocomplete(input);
1333
+ input.dataset.autocompleteAttached = 'true';
1334
+ }
1335
+ });
1336
+ }
1337
+ isExpressionField(input) {
1338
+ const type = input.type?.toLowerCase();
1339
+ if (input.tagName !== 'TEXTAREA' && !(input.tagName === 'INPUT' && (!type || type === 'text'))) {
1340
+ return false;
1341
+ }
1342
+ if (input.closest('.expression-editor-simple')) {
1343
+ return false;
1344
+ }
1345
+ const name = (input.name || input.id || '').toLowerCase();
1346
+ if (name.includes('resultvariable') || name.includes('result-variable')) {
1347
+ return false;
1348
+ }
1349
+ if (name.includes('expression') || name.includes('delegateexpression')) {
1350
+ return true;
1351
+ }
1352
+ const entry = input.closest('.bio-properties-panel-entry');
1353
+ if (entry) {
1354
+ const entryId = (entry.getAttribute('data-entry-id') || '').toLowerCase();
1355
+ if (entryId.includes('resultvariable') || entryId.includes('result-variable')) {
1356
+ return false;
1357
+ }
1358
+ if (entryId.includes('expression')) {
1359
+ return true;
1360
+ }
1361
+ }
1362
+ const label = input.closest('.bio-properties-panel-entry')?.querySelector('label');
1363
+ if (label) {
1364
+ const labelText = label.textContent?.toLowerCase() || '';
1365
+ if (labelText.includes('result variable') || labelText.includes('resultvariable')) {
1366
+ return false;
1367
+ }
1368
+ if (labelText.includes('expression') || labelText.includes('delegate')) {
1369
+ return true;
1370
+ }
1371
+ }
1372
+ return false;
1373
+ }
1374
+ attachAutocomplete(input) {
1375
+ this.wrapWithEditor(input);
1376
+ }
1377
+ // --- Expression Editor (Dropdown/Manual toggle) ---
1378
+ wrapWithEditor(input) {
1379
+ const wrapper = document.createElement('div');
1380
+ wrapper.className = 'expression-editor-wrapper';
1381
+ const parsed = this.parseExpression(input.value);
1382
+ const canUseDropdown = !input.value || (parsed.beanName !== null && parsed.methodName !== null);
1383
+ const initialMode = canUseDropdown ? 'simple' : 'technical';
1384
+ wrapper.dataset.mode = initialMode;
1385
+ input.parentNode?.insertBefore(wrapper, input);
1386
+ const toggle = document.createElement('div');
1387
+ toggle.className = 'expression-editor-toggle';
1388
+ toggle.innerHTML = `
1389
+ <button type="button" class="expression-editor-toggle__btn${initialMode === 'simple' ? ' active' : ''}" data-mode="simple">Dropdown</button>
1390
+ <button type="button" class="expression-editor-toggle__btn${initialMode === 'technical' ? ' active' : ''}" data-mode="technical">Manual</button>
1391
+ `;
1392
+ const technicalContainer = document.createElement('div');
1393
+ technicalContainer.className = 'expression-editor-technical';
1394
+ technicalContainer.appendChild(input);
1395
+ technicalContainer.style.display = initialMode === 'technical' ? 'block' : 'none';
1396
+ const simpleContainer = document.createElement('div');
1397
+ simpleContainer.className = 'expression-editor-simple';
1398
+ simpleContainer.style.display = initialMode === 'simple' ? 'block' : 'none';
1399
+ wrapper.appendChild(toggle);
1400
+ wrapper.appendChild(technicalContainer);
1401
+ wrapper.appendChild(simpleContainer);
1402
+ toggle.querySelectorAll('button').forEach(btn => {
1403
+ btn.addEventListener('click', e => {
1404
+ e.preventDefault();
1405
+ this.setEditorMode(wrapper, input, btn.dataset.mode || 'technical');
1406
+ });
1407
+ });
1408
+ if (initialMode === 'simple') {
1409
+ this.renderSimpleMode(simpleContainer, input);
1410
+ }
1411
+ }
1412
+ setEditorMode(wrapper, input, mode) {
1413
+ wrapper.dataset.mode = mode;
1414
+ wrapper.querySelectorAll('.expression-editor-toggle__btn').forEach(btn => {
1415
+ btn.classList.toggle('active', btn.dataset.mode === mode);
1416
+ });
1417
+ const technicalContainer = wrapper.querySelector('.expression-editor-technical');
1418
+ const simpleContainer = wrapper.querySelector('.expression-editor-simple');
1419
+ const invalidArgsStr = wrapper.dataset.invalidArgs;
1420
+ const invalidArgs = invalidArgsStr ? JSON.parse(invalidArgsStr) : [];
1421
+ if (mode === 'simple') {
1422
+ technicalContainer.style.display = 'none';
1423
+ simpleContainer.style.display = 'block';
1424
+ input.classList.remove('validation-error-param');
1425
+ this.renderSimpleMode(simpleContainer, input);
1426
+ if (invalidArgs.length > 0) {
1427
+ setTimeout(() => {
1428
+ for (const idx of invalidArgs) {
1429
+ const paramInput = simpleContainer.querySelector(`.expression-editor-param input[data-param-index="${idx}"]`);
1430
+ if (paramInput) {
1431
+ paramInput.classList.add('validation-error-param');
1432
+ }
1433
+ }
1434
+ }, 0);
1435
+ }
1436
+ }
1437
+ else {
1438
+ technicalContainer.style.display = 'block';
1439
+ simpleContainer.style.display = 'none';
1440
+ if (invalidArgs.length > 0) {
1441
+ input.classList.add('validation-error-param');
1442
+ }
1443
+ setTimeout(() => input.blur(), 0);
1444
+ }
1445
+ }
1446
+ renderSimpleMode(container, input) {
1447
+ this.cleanupClickHandlers();
1448
+ const parsed = this.parseExpression(input.value);
1449
+ container.innerHTML = `
1450
+ <div class="expression-editor-field" data-container="bean">
1451
+ <label>Service</label>
1452
+ </div>
1453
+ <div class="expression-editor-field" data-container="method"></div>
1454
+ <div data-container="params"></div>
1455
+ `;
1456
+ const beanContainer = container.querySelector('[data-container="bean"]');
1457
+ this.renderCustomSelect(beanContainer, this.processBeans.map(b => ({
1458
+ value: b.name,
1459
+ label: this.camelCaseToReadable(b.name),
1460
+ description: b.description,
1461
+ })), parsed.beanName, 'Select service...', 'bean', beanName => {
1462
+ this.renderMethodDropdown(container, beanName, null, input);
1463
+ this.renderParameterInputs(container, beanName, null, [], input);
1464
+ this.buildAndSetExpression(container, input);
1465
+ });
1466
+ if (parsed.beanName) {
1467
+ this.renderMethodDropdown(container, parsed.beanName, parsed.methodName, input);
1468
+ }
1469
+ if (parsed.beanName && parsed.methodName) {
1470
+ this.renderParameterInputs(container, parsed.beanName, parsed.methodName, parsed.parameters, input);
1471
+ }
1472
+ }
1473
+ renderCustomSelect(container, options, selectedValue, placeholder, dataField, onChange) {
1474
+ const wrapper = document.createElement('div');
1475
+ wrapper.className = 'expression-editor-custom-select';
1476
+ wrapper.dataset.field = dataField;
1477
+ wrapper.dataset.value = selectedValue || '';
1478
+ const nativeSelect = document.createElement('select');
1479
+ nativeSelect.className = 'bio-properties-panel-input';
1480
+ nativeSelect.innerHTML =
1481
+ `<option value="" disabled ${!selectedValue ? 'selected' : ''}>${this.escapeHtml(placeholder)}</option>` +
1482
+ options
1483
+ .map(opt => `<option value="${this.escapeAttr(opt.value)}" ${opt.value === selectedValue ? 'selected' : ''}>${this.escapeHtml(opt.label)}</option>`)
1484
+ .join('');
1485
+ const selectedOption = options.find(o => o.value === selectedValue);
1486
+ if (selectedOption?.description) {
1487
+ nativeSelect.title = selectedOption.description;
1488
+ }
1489
+ const dropdown = document.createElement('div');
1490
+ dropdown.className = 'expression-editor-custom-select__dropdown';
1491
+ dropdown.style.display = 'none';
1492
+ let selectedIndex = options.findIndex(o => o.value === selectedValue);
1493
+ if (selectedIndex < 0)
1494
+ selectedIndex = 0;
1495
+ const renderItems = () => {
1496
+ dropdown.innerHTML = options
1497
+ .map((opt, i) => `
1498
+ <div class="expression-editor-custom-select__item${opt.value === selectedValue ? ' selected' : ''}" data-index="${i}" data-value="${this.escapeAttr(opt.value)}">
1499
+ <div class="expression-editor-custom-select__label">${this.escapeHtml(opt.label)}</div>
1500
+ ${opt.description ? `<div class="expression-editor-custom-select__desc">${this.escapeHtml(opt.description)}</div>` : ''}
1501
+ </div>
1502
+ `)
1503
+ .join('');
1504
+ dropdown.querySelectorAll('.expression-editor-custom-select__item').forEach(item => {
1505
+ item.addEventListener('click', e => {
1506
+ e.stopPropagation();
1507
+ const value = item.dataset.value;
1508
+ const selected = options.find(o => o.value === value);
1509
+ wrapper.dataset.value = value;
1510
+ nativeSelect.value = value;
1511
+ nativeSelect.title = selected?.description || '';
1512
+ dropdown.style.display = 'none';
1513
+ onChange(value);
1514
+ });
1515
+ });
1516
+ };
1517
+ renderItems();
1518
+ nativeSelect.addEventListener('mousedown', e => {
1519
+ e.preventDefault();
1520
+ nativeSelect.focus();
1521
+ const isOpen = dropdown.style.display !== 'none';
1522
+ dropdown.style.display = isOpen ? 'none' : 'block';
1523
+ });
1524
+ nativeSelect.addEventListener('keydown', e => {
1525
+ if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
1526
+ e.preventDefault();
1527
+ if (dropdown.style.display === 'none') {
1528
+ dropdown.style.display = 'block';
1529
+ }
1530
+ const delta = e.key === 'ArrowDown' ? 1 : -1;
1531
+ selectedIndex = Math.max(0, Math.min(options.length - 1, selectedIndex + delta));
1532
+ dropdown.querySelectorAll('.expression-editor-custom-select__item').forEach((item, i) => {
1533
+ item.classList.toggle('highlighted', i === selectedIndex);
1534
+ });
1535
+ dropdown.children[selectedIndex]?.scrollIntoView({ block: 'nearest' });
1536
+ }
1537
+ else if (e.key === 'Enter' && dropdown.style.display !== 'none') {
1538
+ e.preventDefault();
1539
+ const opt = options[selectedIndex];
1540
+ if (opt) {
1541
+ wrapper.dataset.value = opt.value;
1542
+ nativeSelect.value = opt.value;
1543
+ nativeSelect.title = opt.description || '';
1544
+ dropdown.style.display = 'none';
1545
+ onChange(opt.value);
1546
+ }
1547
+ }
1548
+ else if (e.key === 'Escape') {
1549
+ dropdown.style.display = 'none';
1550
+ }
1551
+ else if (e.key === ' ' && dropdown.style.display === 'none') {
1552
+ e.preventDefault();
1553
+ dropdown.style.display = 'block';
1554
+ }
1555
+ });
1556
+ const closeHandler = (e) => {
1557
+ if (!wrapper.contains(e.target)) {
1558
+ dropdown.style.display = 'none';
1559
+ }
1560
+ };
1561
+ document.addEventListener('click', closeHandler);
1562
+ this.documentClickHandlers.push(closeHandler);
1563
+ wrapper.appendChild(nativeSelect);
1564
+ wrapper.appendChild(dropdown);
1565
+ container.appendChild(wrapper);
1566
+ }
1567
+ renderMethodDropdown(container, beanName, selectedMethod, input) {
1568
+ const methodContainer = container.querySelector('[data-container="method"]');
1569
+ if (!methodContainer)
1570
+ return;
1571
+ const bean = this.processBeans.find(b => b.name === beanName);
1572
+ if (!bean) {
1573
+ methodContainer.innerHTML = '';
1574
+ return;
1575
+ }
1576
+ methodContainer.innerHTML = '<label>Method</label>';
1577
+ this.renderCustomSelect(methodContainer, bean.methods.map(m => ({
1578
+ value: m.name,
1579
+ label: this.camelCaseToReadable(m.name),
1580
+ description: m.description,
1581
+ })), selectedMethod, 'Select method...', 'method', methodName => {
1582
+ this.renderParameterInputs(container, beanName, methodName, [], input);
1583
+ this.buildAndSetExpression(container, input);
1584
+ });
1585
+ }
1586
+ renderParameterInputs(container, beanName, methodName, values, input) {
1587
+ const paramsContainer = container.querySelector('[data-container="params"]');
1588
+ if (!paramsContainer)
1589
+ return;
1590
+ if (!methodName) {
1591
+ paramsContainer.innerHTML = '';
1592
+ return;
1593
+ }
1594
+ const bean = this.processBeans.find(b => b.name === beanName);
1595
+ const method = bean?.methods.find(m => m.name === methodName);
1596
+ if (!method || method.parameters.length === 0) {
1597
+ paramsContainer.innerHTML = '';
1598
+ return;
1599
+ }
1600
+ paramsContainer.innerHTML = method.parameters
1601
+ .map((p, i) => `
1602
+ <div class="expression-editor-param">
1603
+ <label>${this.escapeHtml(p.name)} <span class="type">(${this.escapeHtml(p.type)})</span></label>
1604
+ <input type="text" class="expression-editor-input" data-param-index="${i}" value="${this.escapeAttr(values[i] || '')}">
1605
+ </div>
1606
+ `)
1607
+ .join('');
1608
+ paramsContainer.querySelectorAll('input').forEach(paramInput => {
1609
+ paramInput.addEventListener('input', () => {
1610
+ this.buildAndSetExpression(container, input);
1611
+ });
1612
+ });
1613
+ }
1614
+ buildAndSetExpression(simpleContainer, input) {
1615
+ const beanSelect = simpleContainer.querySelector('[data-field="bean"]');
1616
+ const methodSelect = simpleContainer.querySelector('[data-field="method"]');
1617
+ const paramInputs = simpleContainer.querySelectorAll('[data-param-index]');
1618
+ const bean = beanSelect?.dataset.value;
1619
+ const method = methodSelect?.dataset.value;
1620
+ if (!bean || !method) {
1621
+ input.value = '';
1622
+ input.dispatchEvent(new Event('input', { bubbles: true }));
1623
+ return;
1624
+ }
1625
+ const params = Array.from(paramInputs).map(i => i.value);
1626
+ input.value = `\${${bean}.${method}(${params.join(', ')})}`;
1627
+ input.dispatchEvent(new Event('input', { bubbles: true }));
1628
+ }
1629
+ parseExpression(expr) {
1630
+ const match = expr.match(/^\$\{([a-zA-Z_]\w*)\.([a-zA-Z_]\w*)\((.*)\)\}$/);
1631
+ if (!match)
1632
+ return { beanName: null, methodName: null, parameters: [] };
1633
+ return {
1634
+ beanName: match[1],
1635
+ methodName: match[2],
1636
+ parameters: this.parseParameters(match[3]),
1637
+ };
1638
+ }
1639
+ parseParameters(paramsStr) {
1640
+ const params = [];
1641
+ let current = '';
1642
+ let depth = 0;
1643
+ let inString = false;
1644
+ let stringChar = '';
1645
+ for (const char of paramsStr) {
1646
+ if (!inString && (char === '"' || char === "'")) {
1647
+ inString = true;
1648
+ stringChar = char;
1649
+ current += char;
1650
+ }
1651
+ else if (inString && char === stringChar) {
1652
+ inString = false;
1653
+ current += char;
1654
+ }
1655
+ else if (!inString && (char === '(' || char === '[')) {
1656
+ depth++;
1657
+ current += char;
1658
+ }
1659
+ else if (!inString && (char === ')' || char === ']')) {
1660
+ depth--;
1661
+ current += char;
1662
+ }
1663
+ else if (!inString && char === ',' && depth === 0) {
1664
+ params.push(current.trim());
1665
+ current = '';
1666
+ }
1667
+ else {
1668
+ current += char;
1669
+ }
1670
+ }
1671
+ if (current.trim())
1672
+ params.push(current.trim());
1673
+ return params;
1674
+ }
1675
+ escapeHtml(text) {
1676
+ const div = document.createElement('div');
1677
+ div.textContent = text;
1678
+ return div.innerHTML;
1679
+ }
1680
+ escapeAttr(text) {
1681
+ return text
1682
+ .replace(/&/g, '&amp;')
1683
+ .replace(/"/g, '&quot;')
1684
+ .replace(/'/g, '&#39;')
1685
+ .replace(/</g, '&lt;')
1686
+ .replace(/>/g, '&gt;');
1687
+ }
1688
+ camelCaseToReadable(text) {
1689
+ return text
1690
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
1691
+ .replace(/^./, str => str.toUpperCase());
1692
+ }
1693
+ injectStyles() {
1694
+ if (this.stylesInjected)
1695
+ return;
1696
+ this.stylesInjected = true;
1697
+ const style = document.createElement('style');
1698
+ style.textContent = `
1699
+ /* Expression Editor Toggle UI */
1700
+ .expression-editor-wrapper {
1701
+ width: 100%;
1702
+ }
1703
+ .expression-editor-toggle {
1704
+ display: flex;
1705
+ gap: 0;
1706
+ margin-bottom: 8px;
1707
+ }
1708
+ .expression-editor-toggle__btn {
1709
+ flex: 1;
1710
+ padding: 4px 8px;
1711
+ border: 1px solid #ccc;
1712
+ background: #fafafa;
1713
+ color: #333;
1714
+ cursor: pointer;
1715
+ font-size: 13px;
1716
+ font-family: inherit;
1717
+ }
1718
+ .expression-editor-toggle__btn:first-child {
1719
+ border-radius: 2px 0 0 2px;
1720
+ }
1721
+ .expression-editor-toggle__btn:last-child {
1722
+ border-radius: 0 2px 2px 0;
1723
+ border-left: none;
1724
+ }
1725
+ .expression-editor-toggle__btn.active {
1726
+ background: #2b79bd;
1727
+ color: white;
1728
+ border-color: #2b79bd;
1729
+ }
1730
+ .expression-editor-toggle__btn:hover:not(.active) {
1731
+ background: #fff;
1732
+ }
1733
+ .expression-editor-simple {
1734
+ display: flex;
1735
+ flex-direction: column;
1736
+ gap: 6px;
1737
+ }
1738
+ .expression-editor-field label,
1739
+ .expression-editor-param > label {
1740
+ display: block;
1741
+ font-size: var(--text-size-small, 12px);
1742
+ color: var(--label-color, #666);
1743
+ margin-bottom: 2px;
1744
+ }
1745
+ .expression-editor-field label .type,
1746
+ .expression-editor-param label .type {
1747
+ color: var(--description-color, #808080);
1748
+ }
1749
+ .expression-editor-select,
1750
+ .expression-editor-input {
1751
+ display: block;
1752
+ width: 100%;
1753
+ padding: 3px 6px 2px;
1754
+ border: 1px solid #ccc;
1755
+ border-radius: 2px;
1756
+ font-size: 14px;
1757
+ background-color: #fafafa;
1758
+ font-family: inherit;
1759
+ box-sizing: border-box;
1760
+ }
1761
+ .expression-editor-select:focus,
1762
+ .expression-editor-input:focus {
1763
+ outline: none;
1764
+ background-color: hsl(205, 100%, 95%);
1765
+ border-color: hsl(205, 100%, 50%);
1766
+ }
1767
+ /* Override bpmn-js input styles to prevent focus-within highlighting */
1768
+ .expression-editor-technical input,
1769
+ .expression-editor-technical textarea {
1770
+ background-color: #fafafa !important;
1771
+ border-color: #ccc !important;
1772
+ }
1773
+ /* Override native select and input styles in simple mode */
1774
+ .expression-editor-simple select.bio-properties-panel-input,
1775
+ .expression-editor-simple .expression-editor-input {
1776
+ background-color: #fafafa !important;
1777
+ border-color: #ccc !important;
1778
+ }
1779
+ .expression-editor-simple select.bio-properties-panel-input:focus,
1780
+ .expression-editor-simple .expression-editor-input:focus {
1781
+ background-color: hsl(205, 100%, 95%) !important;
1782
+ border-color: hsl(205, 100%, 50%) !important;
1783
+ }
1784
+ .expression-editor-technical input:focus,
1785
+ .expression-editor-technical textarea:focus {
1786
+ background-color: hsl(205, 100%, 95%) !important;
1787
+ border-color: hsl(205, 100%, 50%) !important;
1788
+ }
1789
+ .expression-editor-param {
1790
+ padding-left: 8px;
1791
+ border-left: 2px solid #ccc;
1792
+ margin-top: 4px;
1793
+ }
1794
+ .expression-editor-description {
1795
+ font-size: var(--text-size-small, 12px);
1796
+ color: var(--description-color, #808080);
1797
+ margin-top: 4px;
1798
+ font-style: italic;
1799
+ }
1800
+
1801
+ /* Custom Select (Listbox) */
1802
+ .expression-editor-custom-select {
1803
+ position: relative;
1804
+ width: 100%;
1805
+ }
1806
+ .expression-editor-custom-select select {
1807
+ width: 100%;
1808
+ }
1809
+ .expression-editor-custom-select__dropdown {
1810
+ position: absolute;
1811
+ top: 100%;
1812
+ left: 0;
1813
+ right: 0;
1814
+ max-height: 200px;
1815
+ overflow-y: auto;
1816
+ background: #fff;
1817
+ border: 1px solid #ccc;
1818
+ border-radius: 2px;
1819
+ box-shadow: 0 2px 6px rgba(0,0,0,0.15);
1820
+ z-index: 1000;
1821
+ margin-top: 2px;
1822
+ }
1823
+ .expression-editor-custom-select__item {
1824
+ padding: 8px;
1825
+ cursor: pointer;
1826
+ border-bottom: 1px solid #eee;
1827
+ }
1828
+ .expression-editor-custom-select__item:last-child {
1829
+ border-bottom: none;
1830
+ }
1831
+ .expression-editor-custom-select__item:hover,
1832
+ .expression-editor-custom-select__item.selected,
1833
+ .expression-editor-custom-select__item.highlighted {
1834
+ background: hsl(205, 100%, 95%);
1835
+ }
1836
+ .expression-editor-custom-select__label {
1837
+ font-weight: 500;
1838
+ font-size: 14px;
1839
+ color: #333;
1840
+ }
1841
+ .expression-editor-custom-select__desc {
1842
+ font-size: 11px;
1843
+ color: #666;
1844
+ margin-top: 2px;
1845
+ }
1846
+ `;
1847
+ document.head.appendChild(style);
1848
+ }
1849
+ }
1850
+ const ExpressionAutocompleteModule = {
1851
+ __init__: ['expressionAutocomplete'],
1852
+ expressionAutocomplete: ['type', ExpressionAutocomplete],
1853
+ };
1854
+
1094
1855
  /*
1095
1856
  * Copyright 2015-2025 Ritense BV, the Netherlands.
1096
1857
  *
@@ -1123,7 +1884,7 @@ const ValtimoPropertiesProviderModule = {
1123
1884
  * limitations under the License.
1124
1885
  */
1125
1886
  class ProcessManagementBuilderComponent {
1126
- constructor(breadcrumbService, iconService, logger, modalService, notificationService, pageHeaderService, pageTitleService, processLinkService, processLinkStateService, processManagementEditorService, processManagementService, processService, route, router, translateService, pluginTranslationService, editPermissionsService, processLinkBuildingBlockApiService) {
1887
+ constructor(breadcrumbService, iconService, logger, modalService, notificationService, pageHeaderService, pageTitleService, processLinkService, processLinkStateService, processManagementEditorService, processManagementService, processService, route, router, translateService, pluginTranslationService, editPermissionsService, processLinkBuildingBlockApiService, processBeanService) {
1127
1888
  this.breadcrumbService = breadcrumbService;
1128
1889
  this.iconService = iconService;
1129
1890
  this.logger = logger;
@@ -1142,26 +1903,40 @@ class ProcessManagementBuilderComponent {
1142
1903
  this.pluginTranslationService = pluginTranslationService;
1143
1904
  this.editPermissionsService = editPermissionsService;
1144
1905
  this.processLinkBuildingBlockApiService = processLinkBuildingBlockApiService;
1906
+ this.processBeanService = processBeanService;
1145
1907
  this._selectedProcess$ = new BehaviorSubject(null);
1146
1908
  this.loading$ = new BehaviorSubject(true);
1147
1909
  this._validationErrorElementIds = [];
1148
1910
  this._validationHoverHandler = null;
1149
1911
  this._validationOutHandler = null;
1912
+ this._selectionChangedHandler = null;
1913
+ this._fieldInputCleanupFns = [];
1914
+ this._expressionAutocomplete = null;
1915
+ this._activityMarkerElementIds = [];
1916
+ this._activityMarkerUpdateTimeout = null;
1917
+ this._autofilledElements = [];
1918
+ this._autofilledElementIds = [];
1150
1919
  this.isReadOnlyProcess$ = new BehaviorSubject(false);
1151
1920
  this.isSystemProcess$ = new BehaviorSubject(false);
1152
1921
  this.draft$ = new BehaviorSubject(false);
1153
1922
  this.canInitializeDocument$ = new BehaviorSubject(false);
1154
1923
  this.startableByUser$ = new BehaviorSubject(false);
1155
1924
  this.validationErrors$ = this.processManagementEditorService.validationErrors$;
1925
+ this.$markersVisible = signal(true);
1156
1926
  this.testIds = PROCESS_MANAGEMENT_BUILDER_TEST_IDS;
1157
1927
  this.selectedProcessDefinitionXml$ = this.processManagementEditorService.selectionProcessDefinition$.pipe(filter(selectedProcessDefinition => !!selectedProcessDefinition?.id), distinctUntilChanged((previous, current) => isEqual(previous, current)), tap(selectedProcessDefinition => {
1158
1928
  this.loading$.next(true);
1159
1929
  this.pageTitleService.setCustomPageTitle(selectedProcessDefinition?.name || '-');
1160
1930
  }), switchMap(selectedProcessDefinition => this.processService.getProcessDefinitionXml(selectedProcessDefinition.id)), tap(result => {
1161
1931
  this.cleanUpListenersOnModeler();
1162
- this._bpmnModeler?.importXML(result.bpmn20Xml);
1163
- this._bpmnViewer?.importXML(result.bpmn20Xml);
1164
- this.draft$.next(this.parseDraftFromXml(result.bpmn20Xml));
1932
+ this._autofilledElements = result.autofilledElements ?? [];
1933
+ this.processManagementEditorService.setAutofilledElements(this._autofilledElements);
1934
+ this._bpmnModeler?.importXML(result.bpmn20Xml).then(() => {
1935
+ this.highlightAutofilledElements();
1936
+ });
1937
+ this._bpmnViewer?.importXML(result.bpmn20Xml).then(() => {
1938
+ this.highlightAutofilledElements();
1939
+ });
1165
1940
  this.isReadOnlyProcess$.next(result.readOnly);
1166
1941
  this.isSystemProcess$.next(result.systemProcess);
1167
1942
  this.loading$.next(false);
@@ -1228,8 +2003,9 @@ class ProcessManagementBuilderComponent {
1228
2003
  if (!activityId || !businessId)
1229
2004
  return;
1230
2005
  this.processManagementEditorService.updateProcessLinksOnIdChange(activityId, businessId);
2006
+ this.scheduleActivityMarkerUpdate();
1231
2007
  };
1232
- this.iconService.registerAll([Deploy16, ListChecked16, Return16]);
2008
+ this.iconService.registerAll([View16, ViewOff16]);
1233
2009
  this.setProcessManagementWindow();
1234
2010
  }
1235
2011
  ngAfterViewInit() {
@@ -1242,10 +2018,15 @@ class ProcessManagementBuilderComponent {
1242
2018
  this.subscribeToProcessLinkUpdateEvents();
1243
2019
  this.subscribeToProcessLinkCreateEvents();
1244
2020
  this.subscribeToProcessLinkDeleteEvents();
2021
+ this.subscribeToAutofillDismissEvents();
1245
2022
  this.initEditing();
1246
2023
  }
1247
2024
  ngOnDestroy() {
1248
2025
  this.clearValidationErrors();
2026
+ this.clearActivityMarkers();
2027
+ if (this._activityMarkerUpdateTimeout) {
2028
+ clearTimeout(this._activityMarkerUpdateTimeout);
2029
+ }
1249
2030
  this._bpmnModeler?.destroy();
1250
2031
  this._bpmnViewer?.destroy();
1251
2032
  this._subscriptions.unsubscribe();
@@ -1255,19 +2036,50 @@ class ProcessManagementBuilderComponent {
1255
2036
  this.breadcrumbService.clearThirdBreadcrumb();
1256
2037
  this.breadcrumbService.clearFourthBreadcrumb();
1257
2038
  }
1258
- export(isReadOnlyProcess) {
2039
+ exportBpmn(isReadOnlyProcess) {
1259
2040
  (isReadOnlyProcess ? from(this._bpmnViewer.saveXML()) : from(this._bpmnModeler.saveXML()))
1260
2041
  .pipe(take(1))
1261
2042
  .subscribe(result => {
1262
2043
  const file = new Blob([result.xml ?? ''], { type: 'text/xml' });
1263
- const link = document.createElement('a');
1264
- link.download = 'diagram.bpmn';
1265
- link.href = window.URL.createObjectURL(file);
1266
- link.click();
1267
- window.URL.revokeObjectURL(link.href);
1268
- link.remove();
2044
+ const processDefinitionKey = this.processManagementEditorService.selectionProcessDefinition?.key;
2045
+ this.downloadFile(file, processDefinitionKey ? `${processDefinitionKey}.bpmn` : 'diagram.bpmn');
2046
+ });
2047
+ }
2048
+ export() {
2049
+ const processDefinitionId = this.processManagementEditorService.selectionProcessDefinition?.id;
2050
+ if (!processDefinitionId) {
2051
+ this.showNotification('exportError');
2052
+ return;
2053
+ }
2054
+ this.processManagementService
2055
+ .exportProcessDefinition(processDefinitionId)
2056
+ .pipe(take(1))
2057
+ .subscribe({
2058
+ next: response => {
2059
+ const blob = response.body;
2060
+ if (!blob) {
2061
+ this.showNotification('exportError');
2062
+ return;
2063
+ }
2064
+ this.downloadFile(blob, this.getFileName(response));
2065
+ },
2066
+ error: () => {
2067
+ this.showNotification('exportError');
2068
+ },
1269
2069
  });
1270
2070
  }
2071
+ getFileName(response) {
2072
+ const contentDisposition = response.headers.get('Content-Disposition') ?? '';
2073
+ return contentDisposition.split('filename=')[1]?.replace(/"/g, '').trim() || 'process.zip';
2074
+ }
2075
+ downloadFile(file, fileName) {
2076
+ const link = document.createElement('a');
2077
+ link.download = fileName;
2078
+ link.href = window.URL.createObjectURL(file);
2079
+ link.click();
2080
+ window.URL.revokeObjectURL(link.href);
2081
+ link.remove();
2082
+ }
1271
2083
  validateProcessDefinition(isReadOnlyProcess) {
1272
2084
  combineLatest([
1273
2085
  from(isReadOnlyProcess ? this._bpmnViewer.saveXML() : this._bpmnModeler.saveXML()),
@@ -1281,6 +2093,8 @@ class ProcessManagementBuilderComponent {
1281
2093
  ...link,
1282
2094
  processDefinitionId: '-',
1283
2095
  })),
2096
+ canInitializeDocument: this.canInitializeDocument$.getValue(),
2097
+ startableByUser: this.startableByUser$.getValue(),
1284
2098
  });
1285
2099
  }))
1286
2100
  .subscribe({
@@ -1321,6 +2135,7 @@ class ProcessManagementBuilderComponent {
1321
2135
  .subscribe({
1322
2136
  next: context => {
1323
2137
  this.clearValidationErrors();
2138
+ this.processManagementEditorService.clearDismissedAutofills();
1324
2139
  if (context === 'independent') {
1325
2140
  this.reload();
1326
2141
  this.showNotification('success');
@@ -1369,6 +2184,7 @@ class ProcessManagementBuilderComponent {
1369
2184
  .subscribe({
1370
2185
  next: () => {
1371
2186
  this.clearValidationErrors();
2187
+ this.processManagementEditorService.clearDismissedAutofills();
1372
2188
  this.navigateBack('success');
1373
2189
  },
1374
2190
  error: (error) => {
@@ -1400,27 +2216,6 @@ class ProcessManagementBuilderComponent {
1400
2216
  return;
1401
2217
  this.showNotification(notification);
1402
2218
  }
1403
- onValidationErrorClick(elementId) {
1404
- const modeler = this.isReadOnlyProcess$.getValue() ? this._bpmnViewer : this._bpmnModeler;
1405
- const elementRegistry = modeler.get('elementRegistry');
1406
- const canvas = modeler.get('canvas');
1407
- const element = elementRegistry.get(elementId);
1408
- if (!element)
1409
- return;
1410
- try {
1411
- const selection = modeler.get('selection');
1412
- selection?.select?.(element);
1413
- }
1414
- catch {
1415
- // Viewer may not expose the selection service.
1416
- }
1417
- try {
1418
- canvas.scrollToElement(element);
1419
- }
1420
- catch {
1421
- // ignore
1422
- }
1423
- }
1424
2219
  onProcessToggleChange(field, value) {
1425
2220
  if (field === 'draft')
1426
2221
  this.draft$.next(value);
@@ -1440,7 +2235,6 @@ class ProcessManagementBuilderComponent {
1440
2235
  this._pendingDeployAction = null;
1441
2236
  }
1442
2237
  validateAndDeploy(isReadOnlyProcess, deployAction) {
1443
- // Skip validation for draft processes
1444
2238
  if (this.draft$.getValue()) {
1445
2239
  deployAction();
1446
2240
  return;
@@ -1457,27 +2251,25 @@ class ProcessManagementBuilderComponent {
1457
2251
  ...link,
1458
2252
  processDefinitionId: '-',
1459
2253
  })),
2254
+ canInitializeDocument: this.canInitializeDocument$.getValue(),
2255
+ startableByUser: this.startableByUser$.getValue(),
1460
2256
  });
1461
2257
  }))
1462
2258
  .subscribe({
1463
2259
  next: validationResult => {
1464
2260
  if (!validationResult.isValid) {
1465
- // Has errors - show them and block deployment
1466
2261
  this.highlightValidationErrors(validationResult.errors);
1467
2262
  }
1468
2263
  else if (validationResult.hasWarnings) {
1469
- // Only warnings - show confirmation dialog
1470
2264
  this.highlightValidationErrors(validationResult.errors);
1471
2265
  this._pendingDeployAction = deployAction;
1472
2266
  this.showWarningConfirmationModal$.next(true);
1473
2267
  }
1474
2268
  else {
1475
- // No issues - proceed with deployment
1476
2269
  deployAction();
1477
2270
  }
1478
2271
  },
1479
2272
  error: () => {
1480
- // Validation endpoint failed - proceed with deployment anyway (server will validate again)
1481
2273
  deployAction();
1482
2274
  },
1483
2275
  });
@@ -1489,6 +2281,7 @@ class ProcessManagementBuilderComponent {
1489
2281
  processManagementWindow.processManagementEditorService = this.processManagementEditorService;
1490
2282
  processManagementWindow.translateService = this.translateService;
1491
2283
  processManagementWindow.pluginTranslationService = this.pluginTranslationService;
2284
+ processManagementWindow.processLinkService = this.processLinkService;
1492
2285
  }
1493
2286
  showNotification(notification) {
1494
2287
  if (!notification)
@@ -1496,6 +2289,7 @@ class ProcessManagementBuilderComponent {
1496
2289
  let type;
1497
2290
  if (notification === 'alreadyExists' ||
1498
2291
  notification === 'validationError' ||
2292
+ notification === 'exportError' ||
1499
2293
  notification === 'error') {
1500
2294
  type = 'error';
1501
2295
  }
@@ -1620,6 +2414,10 @@ class ProcessManagementBuilderComponent {
1620
2414
  };
1621
2415
  eventBus.on('element.hover', this._validationHoverHandler);
1622
2416
  eventBus.on('element.out', this._validationOutHandler);
2417
+ this._selectionChangedHandler = (event) => {
2418
+ this.highlightInvalidFieldsInPropertiesPanel(event.newSelection, errors);
2419
+ };
2420
+ eventBus.on('selection.changed', this._selectionChangedHandler);
1623
2421
  const selection = modeler.get('selection');
1624
2422
  const selected = selection.get();
1625
2423
  if (selected?.length > 0) {
@@ -1628,6 +2426,86 @@ class ProcessManagementBuilderComponent {
1628
2426
  selection.select(current);
1629
2427
  }
1630
2428
  }
2429
+ highlightInvalidFieldsInPropertiesPanel(newSelection, errors) {
2430
+ document.querySelectorAll('.validation-error-field').forEach(el => {
2431
+ el.classList.remove('validation-error-field');
2432
+ });
2433
+ document.querySelectorAll('.validation-error-param').forEach(el => {
2434
+ el.classList.remove('validation-error-param');
2435
+ });
2436
+ if (!newSelection?.length)
2437
+ return;
2438
+ const selectedId = newSelection[0]?.id;
2439
+ if (!selectedId)
2440
+ return;
2441
+ const elementErrors = errors.filter(e => e.elementId === selectedId);
2442
+ setTimeout(() => {
2443
+ for (const error of elementErrors) {
2444
+ const listenerEntryId = error.listenerType != null && error.listenerIndex != null
2445
+ ? `${selectedId}-${error.listenerType}-${error.listenerIndex}`
2446
+ : null;
2447
+ if (error.invalidFields) {
2448
+ for (const fieldId of error.invalidFields) {
2449
+ let entry = null;
2450
+ if (listenerEntryId) {
2451
+ const listenerEntry = document.querySelector(`[data-entry-id="${listenerEntryId}"]`);
2452
+ if (listenerEntry) {
2453
+ entry = listenerEntry.querySelector(`[data-entry-id="${fieldId}"]`);
2454
+ }
2455
+ }
2456
+ if (!entry) {
2457
+ entry = document.querySelector(`[data-entry-id="${fieldId}"]`);
2458
+ }
2459
+ if (entry) {
2460
+ entry.classList.add('validation-error-field');
2461
+ const input = entry.querySelector('input, textarea, select');
2462
+ if (input) {
2463
+ const handler = () => {
2464
+ entry.classList.remove('validation-error-field');
2465
+ input.removeEventListener('input', handler);
2466
+ input.removeEventListener('change', handler);
2467
+ };
2468
+ input.addEventListener('input', handler);
2469
+ input.addEventListener('change', handler);
2470
+ this._fieldInputCleanupFns.push(() => {
2471
+ input.removeEventListener('input', handler);
2472
+ input.removeEventListener('change', handler);
2473
+ });
2474
+ }
2475
+ }
2476
+ }
2477
+ }
2478
+ if (error.invalidArguments && error.invalidArguments.length > 0) {
2479
+ let scopeElement = null;
2480
+ if (listenerEntryId) {
2481
+ scopeElement = document.querySelector(`[data-entry-id="${listenerEntryId}"]`);
2482
+ }
2483
+ const wrapper = scopeElement
2484
+ ? scopeElement.querySelector('.expression-editor-wrapper')
2485
+ : document.querySelector('.expression-editor-wrapper');
2486
+ if (wrapper) {
2487
+ wrapper.dataset.invalidArgs = JSON.stringify(error.invalidArguments);
2488
+ }
2489
+ for (const idx of error.invalidArguments) {
2490
+ const paramInput = scopeElement
2491
+ ? scopeElement.querySelector(`.expression-editor-param input[data-param-index="${idx}"]`)
2492
+ : document.querySelector(`.expression-editor-param input[data-param-index="${idx}"]`);
2493
+ if (paramInput) {
2494
+ paramInput.classList.add('validation-error-param');
2495
+ const handler = () => {
2496
+ paramInput.classList.remove('validation-error-param');
2497
+ paramInput.removeEventListener('input', handler);
2498
+ };
2499
+ paramInput.addEventListener('input', handler);
2500
+ this._fieldInputCleanupFns.push(() => {
2501
+ paramInput.removeEventListener('input', handler);
2502
+ });
2503
+ }
2504
+ }
2505
+ }
2506
+ }
2507
+ }, 50);
2508
+ }
1631
2509
  clearValidationErrors() {
1632
2510
  const modeler = this.isReadOnlyProcess$.getValue() ? this._bpmnViewer : this._bpmnModeler;
1633
2511
  if (!modeler)
@@ -1644,6 +2522,21 @@ class ProcessManagementBuilderComponent {
1644
2522
  eventBus.off('element.out', this._validationOutHandler);
1645
2523
  this._validationOutHandler = null;
1646
2524
  }
2525
+ if (this._selectionChangedHandler) {
2526
+ eventBus.off('selection.changed', this._selectionChangedHandler);
2527
+ this._selectionChangedHandler = null;
2528
+ }
2529
+ this._fieldInputCleanupFns.forEach(fn => fn());
2530
+ this._fieldInputCleanupFns = [];
2531
+ document.querySelectorAll('.validation-error-field').forEach(el => {
2532
+ el.classList.remove('validation-error-field');
2533
+ });
2534
+ document.querySelectorAll('.validation-error-param').forEach(el => {
2535
+ el.classList.remove('validation-error-param');
2536
+ });
2537
+ document.querySelectorAll('.expression-editor-wrapper[data-invalid-args]').forEach(el => {
2538
+ delete el.dataset.invalidArgs;
2539
+ });
1647
2540
  for (const elementId of this._validationErrorElementIds) {
1648
2541
  try {
1649
2542
  canvas.removeMarker(elementId, 'highlight-overlay-error');
@@ -1661,6 +2554,209 @@ class ProcessManagementBuilderComponent {
1661
2554
  // ignore
1662
2555
  }
1663
2556
  }
2557
+ highlightAutofilledElements() {
2558
+ this.clearAutofilledHighlights();
2559
+ if (!this._autofilledElements?.length)
2560
+ return;
2561
+ const modeler = this.isReadOnlyProcess$.getValue() ? this._bpmnViewer : this._bpmnModeler;
2562
+ if (!modeler)
2563
+ return;
2564
+ const overlays = modeler.get('overlays');
2565
+ for (const element of this._autofilledElements) {
2566
+ try {
2567
+ this._autofilledElementIds.push(element.activityId);
2568
+ const tooltipText = this.getAutofilledTooltip();
2569
+ overlays.add(element.activityId, 'autofilled-indicator', {
2570
+ position: { top: -12, left: -12 },
2571
+ html: this.buildAutofilledOverlayElement(element.activityId, tooltipText),
2572
+ });
2573
+ }
2574
+ catch (e) {
2575
+ // Element may not exist on the canvas
2576
+ }
2577
+ }
2578
+ }
2579
+ clearAutofilledHighlights() {
2580
+ const modeler = this.isReadOnlyProcess$.getValue() ? this._bpmnViewer : this._bpmnModeler;
2581
+ if (!modeler)
2582
+ return;
2583
+ const overlays = modeler.get('overlays');
2584
+ this._autofilledElementIds = [];
2585
+ try {
2586
+ overlays.remove({ type: 'autofilled-indicator' });
2587
+ }
2588
+ catch (e) {
2589
+ // ignore
2590
+ }
2591
+ }
2592
+ buildAutofilledOverlayElement(elementId, tooltipText) {
2593
+ const container = document.createElement('div');
2594
+ container.className = 'autofilled-indicator-overlay';
2595
+ container.dataset.elementId = elementId;
2596
+ const icon = document.createElement('span');
2597
+ icon.className = 'autofilled-indicator-icon';
2598
+ icon.innerHTML = '!';
2599
+ container.appendChild(icon);
2600
+ const tooltip = document.createElement('span');
2601
+ tooltip.className = 'autofilled-indicator-tooltip';
2602
+ tooltip.textContent = tooltipText;
2603
+ container.appendChild(tooltip);
2604
+ return container;
2605
+ }
2606
+ getAutofilledTooltip() {
2607
+ return this.translateService.instant('processManagement.autofilled.generic');
2608
+ }
2609
+ getElementListeners(element) {
2610
+ const extensionElements = element?.businessObject?.extensionElements;
2611
+ const values = extensionElements?.values || [];
2612
+ const executionListeners = values.filter((v) => v.$type === 'camunda:ExecutionListener');
2613
+ const taskListeners = values.filter((v) => v.$type === 'camunda:TaskListener');
2614
+ return {
2615
+ hasExecutionListener: executionListeners.length > 0,
2616
+ hasTaskListener: taskListeners.length > 0,
2617
+ executionListenerCount: executionListeners.length,
2618
+ taskListenerCount: taskListeners.length,
2619
+ };
2620
+ }
2621
+ toggleMarkerVisibility() {
2622
+ this.$markersVisible.update(v => !v);
2623
+ if (this.$markersVisible()) {
2624
+ this.updateActivityMarkers();
2625
+ }
2626
+ else {
2627
+ this.clearActivityMarkers();
2628
+ }
2629
+ }
2630
+ updateActivityMarkers() {
2631
+ this.clearActivityMarkers();
2632
+ if (!this.$markersVisible())
2633
+ return;
2634
+ const modeler = this.isReadOnlyProcess$.getValue() ? this._bpmnViewer : this._bpmnModeler;
2635
+ if (!modeler)
2636
+ return;
2637
+ const overlays = modeler.get('overlays');
2638
+ const elementRegistry = modeler.get('elementRegistry');
2639
+ const processLinks = this.processManagementEditorService.processLinksForSelectedDefinition;
2640
+ const processLinkActivityIds = new Set(processLinks.map(pl => pl.activityId));
2641
+ const elementMarkers = new Map();
2642
+ elementRegistry.forEach((element) => {
2643
+ if (!element.id || element.type === 'label')
2644
+ return;
2645
+ const listeners = this.getElementListeners(element);
2646
+ const hasProcessLink = processLinkActivityIds.has(element.id);
2647
+ if (listeners.hasExecutionListener || listeners.hasTaskListener || hasProcessLink) {
2648
+ elementMarkers.set(element.id, {
2649
+ hasExecutionListener: listeners.hasExecutionListener,
2650
+ hasTaskListener: listeners.hasTaskListener,
2651
+ hasProcessLink,
2652
+ executionListenerCount: listeners.executionListenerCount,
2653
+ taskListenerCount: listeners.taskListenerCount,
2654
+ });
2655
+ }
2656
+ });
2657
+ for (const [elementId, info] of elementMarkers) {
2658
+ this._activityMarkerElementIds.push(elementId);
2659
+ const badges = this.buildActivityMarkerBadges(info, elementId);
2660
+ if (badges) {
2661
+ try {
2662
+ const element = elementRegistry.get(elementId);
2663
+ const position = this.calculateMarkerPosition(element);
2664
+ overlays.add(elementId, 'activity-marker', {
2665
+ position,
2666
+ html: badges,
2667
+ });
2668
+ }
2669
+ catch (e) {
2670
+ // Element may not exist on canvas
2671
+ }
2672
+ }
2673
+ }
2674
+ }
2675
+ calculateMarkerPosition(element) {
2676
+ if (element?.waypoints?.length > 1) {
2677
+ const waypoints = element.waypoints;
2678
+ const lastPoint = waypoints[waypoints.length - 1];
2679
+ const secondLastPoint = waypoints[waypoints.length - 2];
2680
+ // Compute bounding box from waypoints (same as diagram-js getBBox)
2681
+ const minX = Math.min(...waypoints.map((wp) => wp.x));
2682
+ const minY = Math.min(...waypoints.map((wp) => wp.y));
2683
+ // Direction of the final segment
2684
+ const dx = lastPoint.x - secondLastPoint.x;
2685
+ const dy = lastPoint.y - secondLastPoint.y;
2686
+ const len = Math.sqrt(dx * dx + dy * dy);
2687
+ // Offset back from arrow tip along the line
2688
+ const backOffset = 30;
2689
+ const backX = len > 0 ? (-dx / len) * backOffset : 0;
2690
+ const backY = len > 0 ? (-dy / len) * backOffset : 0;
2691
+ // Perpendicular offset: above for horizontal lines, right for vertical lines
2692
+ const perpOffset = 20;
2693
+ const isMoreHorizontal = Math.abs(dx) > Math.abs(dy);
2694
+ const perpX = isMoreHorizontal ? 0 : perpOffset;
2695
+ const perpY = isMoreHorizontal ? -perpOffset : 0;
2696
+ return {
2697
+ top: lastPoint.y - minY + backY + perpY - 11,
2698
+ left: lastPoint.x - minX + backX + perpX - 11,
2699
+ };
2700
+ }
2701
+ return { top: -12, right: 12 };
2702
+ }
2703
+ buildActivityMarkerBadges(info, elementId) {
2704
+ const container = document.createElement('div');
2705
+ container.className = 'activity-marker-overlay';
2706
+ container.dataset.elementId = elementId;
2707
+ if (info.hasProcessLink) {
2708
+ const tooltip = this.translateService.instant('processManagement.markers.processLink');
2709
+ container.appendChild(this.buildMarkerBadge('process-link', 'P', tooltip));
2710
+ }
2711
+ if (info.hasExecutionListener) {
2712
+ const countSuffix = info.executionListenerCount > 1 ? ` (${info.executionListenerCount})` : '';
2713
+ const tooltip = this.translateService.instant('processManagement.markers.executionListener') + countSuffix;
2714
+ container.appendChild(this.buildMarkerBadge('execution-listener', 'E', tooltip));
2715
+ }
2716
+ if (info.hasTaskListener) {
2717
+ const countSuffix = info.taskListenerCount > 1 ? ` (${info.taskListenerCount})` : '';
2718
+ const tooltip = this.translateService.instant('processManagement.markers.taskListener') + countSuffix;
2719
+ container.appendChild(this.buildMarkerBadge('task-listener', 'T', tooltip));
2720
+ }
2721
+ if (container.children.length === 0)
2722
+ return null;
2723
+ return container;
2724
+ }
2725
+ buildMarkerBadge(type, label, tooltip) {
2726
+ const badge = document.createElement('div');
2727
+ badge.className = `activity-marker-badge activity-marker-badge--${type}`;
2728
+ const icon = document.createElement('span');
2729
+ icon.className = 'activity-marker-badge__icon';
2730
+ icon.textContent = label;
2731
+ badge.appendChild(icon);
2732
+ const text = document.createElement('span');
2733
+ text.className = 'activity-marker-badge__text';
2734
+ text.textContent = tooltip;
2735
+ badge.appendChild(text);
2736
+ return badge;
2737
+ }
2738
+ clearActivityMarkers() {
2739
+ const modeler = this.isReadOnlyProcess$.getValue() ? this._bpmnViewer : this._bpmnModeler;
2740
+ if (!modeler)
2741
+ return;
2742
+ const overlays = modeler.get('overlays');
2743
+ this._activityMarkerElementIds = [];
2744
+ try {
2745
+ overlays.remove({ type: 'activity-marker' });
2746
+ }
2747
+ catch (e) {
2748
+ // ignore
2749
+ }
2750
+ }
2751
+ scheduleActivityMarkerUpdate() {
2752
+ if (this._activityMarkerUpdateTimeout) {
2753
+ clearTimeout(this._activityMarkerUpdateTimeout);
2754
+ }
2755
+ this._activityMarkerUpdateTimeout = setTimeout(() => {
2756
+ this.updateActivityMarkers();
2757
+ this._activityMarkerUpdateTimeout = null;
2758
+ }, 300);
2759
+ }
1664
2760
  setSelectedProcessDefinitionToLatest(processDefinitions) {
1665
2761
  const latest = getLatestProcessDefinition(processDefinitions);
1666
2762
  if (!latest)
@@ -1675,11 +2771,16 @@ class ProcessManagementBuilderComponent {
1675
2771
  CamundaPlatformPropertiesProviderModule,
1676
2772
  camundaPlatformBehaviors,
1677
2773
  ValtimoPropertiesProviderModule,
2774
+ ExpressionAutocompleteModule,
1678
2775
  ],
1679
2776
  moddleExtensions: { camunda: CamundaBpmnModdle },
1680
2777
  propertiesPanel: { parent: this.modelerPanelElementRef.nativeElement },
1681
2778
  });
1682
2779
  this._bpmnModeler?.attachTo(this.modelerElementRef.nativeElement);
2780
+ // Initialize expression autocomplete
2781
+ this._expressionAutocomplete = this._bpmnModeler.get('expressionAutocomplete');
2782
+ this._expressionAutocomplete?.setPanelContainer(this.modelerPanelElementRef.nativeElement);
2783
+ this.loadProcessBeansForAutocomplete();
1683
2784
  this._bpmnModeler.on('commandStack.changed', () => {
1684
2785
  this.changesPending$.next(true);
1685
2786
  });
@@ -1695,6 +2796,17 @@ class ProcessManagementBuilderComponent {
1695
2796
  });
1696
2797
  this.processManagementEditorService.setActivityIdBusinessIdMap(idMap);
1697
2798
  this.listenToActivityChangesOnModeler();
2799
+ this.updateActivityMarkers();
2800
+ });
2801
+ }
2802
+ loadProcessBeansForAutocomplete() {
2803
+ this.processBeanService.getProcessBeans().subscribe({
2804
+ next: beans => {
2805
+ this._expressionAutocomplete?.setProcessBeans(beans);
2806
+ },
2807
+ error: err => {
2808
+ this.logger.warn('Failed to load process beans for autocomplete', err);
2809
+ },
1698
2810
  });
1699
2811
  }
1700
2812
  initViewer() {
@@ -1713,6 +2825,7 @@ class ProcessManagementBuilderComponent {
1713
2825
  });
1714
2826
  this._bpmnViewer.on('import.done', () => {
1715
2827
  disableCommands(this._bpmnViewer);
2828
+ this.updateActivityMarkers();
1716
2829
  });
1717
2830
  }
1718
2831
  reload() {
@@ -1763,6 +2876,7 @@ class ProcessManagementBuilderComponent {
1763
2876
  this.processManagementEditorService.createProcessLink(event);
1764
2877
  this.processLinkStateService.stopSaving();
1765
2878
  this.processLinkStateService.closeModal();
2879
+ this.updateActivityMarkers();
1766
2880
  const buildingBlockProcessLinkCreateDto = event;
1767
2881
  if (buildingBlockProcessLinkCreateDto.buildingBlockDefinitionKey &&
1768
2882
  buildingBlockProcessLinkCreateDto.buildingBlockDefinitionVersionTag) {
@@ -1775,9 +2889,31 @@ class ProcessManagementBuilderComponent {
1775
2889
  this.processManagementEditorService.deleteProcessLink(event);
1776
2890
  this.processLinkStateService.stopSaving();
1777
2891
  this.processLinkStateService.closeModal();
2892
+ this.updateActivityMarkers();
1778
2893
  this.unsetCalledElementForBuildingBlockProcessLink(event.activityId);
1779
2894
  }));
1780
2895
  }
2896
+ subscribeToAutofillDismissEvents() {
2897
+ this._subscriptions.add(this.processManagementEditorService.autofillDismissed$.subscribe(activityId => {
2898
+ this.removeAutofillOverlay(activityId);
2899
+ }));
2900
+ }
2901
+ removeAutofillOverlay(activityId) {
2902
+ const modeler = this.isReadOnlyProcess$.getValue() ? this._bpmnViewer : this._bpmnModeler;
2903
+ if (!modeler)
2904
+ return;
2905
+ const overlays = modeler.get('overlays');
2906
+ try {
2907
+ overlays.remove({ element: activityId, type: 'autofilled-indicator' });
2908
+ }
2909
+ catch (e) {
2910
+ // ignore
2911
+ }
2912
+ const idx = this._autofilledElementIds.indexOf(activityId);
2913
+ if (idx > -1) {
2914
+ this._autofilledElementIds.splice(idx, 1);
2915
+ }
2916
+ }
1781
2917
  initIfCreate() {
1782
2918
  if (this._selectedProcess$.getValue() !== 'create')
1783
2919
  return;
@@ -1809,12 +2945,17 @@ class ProcessManagementBuilderComponent {
1809
2945
  .subscribe(result => {
1810
2946
  const processDefinitionResult = result;
1811
2947
  this.cleanUpListenersOnModeler();
1812
- this._bpmnModeler?.importXML(processDefinitionResult.bpmn20Xml);
1813
- this._bpmnViewer?.importXML(processDefinitionResult.bpmn20Xml);
1814
- this.draft$.next(processDefinitionResult.draft ??
1815
- this.parseDraftFromXml(processDefinitionResult.bpmn20Xml));
2948
+ this._autofilledElements = processDefinitionResult.autofilledElements ?? [];
2949
+ this.processManagementEditorService.setAutofilledElements(this._autofilledElements);
2950
+ this._bpmnModeler?.importXML(processDefinitionResult.bpmn20Xml).then(() => {
2951
+ this.highlightAutofilledElements();
2952
+ });
2953
+ this._bpmnViewer?.importXML(processDefinitionResult.bpmn20Xml).then(() => {
2954
+ this.highlightAutofilledElements();
2955
+ });
1816
2956
  this.canInitializeDocument$.next(!!processDefinitionResult?.processCaseLink?.canInitializeDocument);
1817
2957
  this.startableByUser$.next(!!processDefinitionResult?.processCaseLink?.startableByUser);
2958
+ this.draft$.next(!!processDefinitionResult?.draft);
1818
2959
  this.loading$.next(false);
1819
2960
  }));
1820
2961
  }
@@ -1889,11 +3030,22 @@ class ProcessManagementBuilderComponent {
1889
3030
  }
1890
3031
  clearBuildingBlockCalledElement(editor, activityId);
1891
3032
  }
3033
+ onValidationErrorClick(elementId) {
3034
+ const modeler = this.isReadOnlyProcess$.getValue() ? this._bpmnViewer : this._bpmnModeler;
3035
+ const canvas = modeler.get('canvas');
3036
+ const selection = modeler.get('selection');
3037
+ const elementRegistry = modeler.get('elementRegistry');
3038
+ const element = elementRegistry.get(elementId);
3039
+ if (!element)
3040
+ return;
3041
+ canvas.scrollToElement(element, { top: 100, bottom: 100, left: 100, right: 100 });
3042
+ selection.select(element);
3043
+ }
1892
3044
  getValidationErrorMessage(error) {
1893
3045
  if (error.errorCode) {
1894
- const translationKey = `processManagement.expressionErrors.${error.errorCode}`;
3046
+ const translationKey = `processManagement.validationErrorCodes.${error.errorCode}`;
1895
3047
  const translated = this.translateService.instant(translationKey, {
1896
- expression: error.expression ? `'${error.expression}'` : '',
3048
+ expression: error.expression ?? '',
1897
3049
  });
1898
3050
  if (translated !== translationKey) {
1899
3051
  return translated;
@@ -1915,13 +3067,13 @@ class ProcessManagementBuilderComponent {
1915
3067
  container.appendChild(text);
1916
3068
  return container;
1917
3069
  }
1918
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementBuilderComponent, deps: [{ token: i1$1.BreadcrumbService }, { token: i2$2.IconService }, { token: i3.NGXLogger }, { token: i1$1.ModalService }, { token: i2$1.GlobalNotificationService }, { token: i1$1.PageHeaderService }, { token: i1$1.PageTitleService }, { token: i5.ProcessLinkService }, { token: i5.ProcessLinkStateService }, { token: ProcessManagementEditorService }, { token: ProcessManagementService }, { token: i7.ProcessService }, { token: i8.ActivatedRoute }, { token: i8.Router }, { token: i9.TranslateService }, { token: i10.PluginTranslationService }, { token: i2$1.EditPermissionsService }, { token: i5.ProcessLinkBuildingBlockApiService }], target: i0.ɵɵFactoryTarget.Component }); }
3070
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementBuilderComponent, deps: [{ token: i1$1.BreadcrumbService }, { token: i2$2.IconService }, { token: i3.NGXLogger }, { token: i1$1.ModalService }, { token: i2.GlobalNotificationService }, { token: i1$1.PageHeaderService }, { token: i1$1.PageTitleService }, { token: i5.ProcessLinkService }, { token: i5.ProcessLinkStateService }, { token: ProcessManagementEditorService }, { token: ProcessManagementService }, { token: i7.ProcessService }, { token: i8.ActivatedRoute }, { token: i8.Router }, { token: i9.TranslateService }, { token: i10.PluginTranslationService }, { token: i2.EditPermissionsService }, { token: i5.ProcessLinkBuildingBlockApiService }, { token: ProcessBeanService }], target: i0.ɵɵFactoryTarget.Component }); }
1919
3071
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.25", type: ProcessManagementBuilderComponent, isStandalone: true, selector: "valtimo-process-management-builder", providers: [
1920
3072
  ProcessManagementEditorService,
1921
3073
  ProcessLinkStateService,
1922
3074
  ProcessLinkStepService,
1923
3075
  ProcessLinkButtonService,
1924
- ], viewQueries: [{ propertyName: "modelerElementRef", first: true, predicate: ["modeler"], descendants: true }, { propertyName: "modelerPanelElementRef", first: true, predicate: ["modelerPanel"], descendants: true }, { propertyName: "viewerElementRef", first: true, predicate: ["viewer"], descendants: true }, { propertyName: "viewerPanelElementRef", first: true, predicate: ["viewerPanel"], descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div\n fitPage\n [disableOverflow]=\"true\"\n *ngIf=\"{\n processDefinitionVersions: processDefinitionVersions$ | async,\n selectedProcessDefinitionXml: selectedProcessDefinitionXml$ | async,\n loading: loading$ | async,\n isReadOnlyProcess: isReadOnlyProcess$ | async,\n hasEditPermissions: hasEditPermissions$ | async,\n } as obs\"\n data-carbon-theme=\"g10\"\n class=\"bpmn__container\"\n>\n <div\n class=\"bpmn__modeler\"\n [style.display]=\"obs.isReadOnlyProcess || !obs.hasEditPermissions ? 'none' : 'flex'\"\n >\n <div class=\"bpmn__modeler-canvas\" #modeler>\n <div\n class=\"validation-errors-list\"\n *ngIf=\"validationErrors$ | async as validationErrors\"\n [style.display]=\"validationErrors.length > 0 ? '' : 'none'\"\n >\n <details open>\n <summary class=\"validation-errors-list__header\">\n <span>{{\n 'processManagement.validationErrorsCount'\n | translate: {count: validationErrors.length}\n }}</span>\n <svg\n class=\"validation-errors-list__arrow\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"m11.657 8-4.95 4.95a1 1 0 0 1-1.414-1.414L8.828 8 5.293 4.464A1 1 0 1 1 6.707 3.05L11.657 8Z\"\n />\n </svg>\n </summary>\n\n <div class=\"validation-errors-list__items\">\n <button\n *ngFor=\"let error of validationErrors\"\n class=\"validation-errors-list__item\"\n [class.warning]=\"error.severity === 'WARNING'\"\n (click)=\"onValidationErrorClick(error.elementId)\"\n >\n <span\n class=\"validation-errors-list__icon\"\n [class.warning]=\"error.severity === 'WARNING'\"\n >{{ error.severity === 'WARNING' ? '!' : '!' }}</span\n >\n\n <span class=\"validation-errors-list__details\">\n <span class=\"validation-errors-list__element\">{{\n error.elementName || error.elementId\n }}</span>\n\n <span\n class=\"validation-errors-list__reason\"\n [class.warning]=\"error.severity === 'WARNING'\"\n >{{ getValidationErrorMessage(error) }}</span\n >\n </span>\n </button>\n </div>\n </details>\n </div>\n </div>\n\n <div class=\"bpmn__modeler-panel\" #modelerPanel></div>\n </div>\n\n <div\n class=\"bpmn__modeler\"\n [style.display]=\"obs.isReadOnlyProcess || !obs.hasEditPermissions ? 'flex' : 'none'\"\n >\n <div class=\"bpmn__modeler-canvas\" #viewer></div>\n\n <div class=\"bpmn__modeler-panel\" #viewerPanel></div>\n </div>\n</div>\n\n<valtimo-process-link-modal></valtimo-process-link-modal>\n\n<valtimo-confirmation-modal\n [showModalSubject$]=\"showWarningConfirmationModal$\"\n [titleTranslationKey]=\"'processManagement.warningConfirmation.title'\"\n [contentTranslationKey]=\"'processManagement.warningConfirmation.content'\"\n [confirmButtonTextTranslationKey]=\"'processManagement.warningConfirmation.confirm'\"\n [cancelButtonTextTranslationKey]=\"'interface.cancel'\"\n (confirmEvent)=\"onWarningConfirmationConfirm()\"\n (cancelEvent)=\"onWarningConfirmationCancel()\"\n></valtimo-confirmation-modal>\n\n<ng-container renderInPageHeader [fullWidth]=\"true\">\n <ng-template>\n <div\n class=\"page-header-actions\"\n *ngIf=\"{\n processDefinitionVersionsListItems: processDefinitionVersionsListItems$ | async,\n loading: loading$ | async,\n changesPending: changesPending$ | async,\n isReadOnlyProcess: isReadOnlyProcess$ | async,\n isSystemProcess: isSystemProcess$ | async,\n compactMode: compactMode$ | async,\n creatingNewProcess: creatingNewProcess$ | async,\n context: context$ | async,\n hasEditPermissions: hasEditPermissions$ | async,\n draft: draft$ | async,\n canInitializeDocument: canInitializeDocument$ | async,\n startableByUser: startableByUser$ | async,\n updatingProcessDefinitionCaseDefinition: updatingProcessDefinitionCaseDefinition$ | async,\n } as actionsObs\"\n >\n <div class=\"page-header-actions__left-container\">\n <cds-dropdown\n *ngIf=\"!actionsObs.creatingNewProcess && actionsObs?.context === 'independent'\"\n class=\"page-header-actions__version-dropdown\"\n (selected)=\"selectedVersionChange($event)\"\n [disabled]=\"\n actionsObs.loading ||\n (actionsObs.processDefinitionVersionsListItems || []).length === 0 ||\n (actionsObs.processDefinitionVersionsListItems || []).length === 1\n \"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n >\n <cds-dropdown-list\n [items]=\"actionsObs.processDefinitionVersionsListItems || []\"\n ></cds-dropdown-list>\n </cds-dropdown>\n\n <div\n class=\"page-header-actions__tags\"\n *ngIf=\"\n actionsObs.isReadOnlyProcess ||\n !actionsObs.hasEditPermissions ||\n actionsObs.isSystemProcess\n \"\n >\n <cds-tag\n *ngIf=\"actionsObs.isReadOnlyProcess || !actionsObs.hasEditPermissions\"\n type=\"blue\"\n >{{ 'processManagement.readOnly' | translate }}</cds-tag\n >\n\n <cds-tag *ngIf=\"actionsObs.isSystemProcess\" type=\"red\">{{\n 'processManagement.systemProcess' | translate\n }}</cds-tag>\n </div>\n\n <div class=\"page-header-actions__toggles\">\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processManagement.draftTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.draft' | translate\"\n [offText]=\"'processManagement.draft' | translate\"\n [checked]=\"actionsObs.draft\"\n [disabled]=\"actionsObs.loading || !actionsObs.hasEditPermissions\"\n (checkedChange)=\"onProcessToggleChange('draft', $event)\"\n [attr.data-test-id]=\"testIds.draftToggle\"\n ></cds-toggle>\n </cds-tooltip>\n\n @if (actionsObs.context === 'case') {\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processCaseConnection.processCreatesCaseTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.canInitializeDocument' | translate\"\n [offText]=\"'processManagement.canInitializeDocument' | translate\"\n [checked]=\"actionsObs.canInitializeDocument\"\n [disabled]=\"\n actionsObs.loading ||\n actionsObs.updatingProcessDefinitionCaseDefinition ||\n !actionsObs.hasEditPermissions\n \"\n (checkedChange)=\"onProcessToggleChange('canInitializeDocument', $event)\"\n [attr.data-test-id]=\"testIds.startsCaseToggle\"\n ></cds-toggle>\n </cds-tooltip>\n\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processCaseConnection.startableWithinCaseTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.startableByUser' | translate\"\n [offText]=\"'processManagement.startableByUser' | translate\"\n [checked]=\"actionsObs.startableByUser\"\n [disabled]=\"\n actionsObs.loading ||\n actionsObs.updatingProcessDefinitionCaseDefinition ||\n !actionsObs.hasEditPermissions\n \"\n (checkedChange)=\"onProcessToggleChange('startableByUser', $event)\"\n [attr.data-test-id]=\"testIds.startableByUserToggle\"\n ></cds-toggle\n ></cds-tooltip>\n }\n </div>\n </div>\n\n <div class=\"page-header-actions__buttons\">\n <v-overflow-menu class=\"overflow-button\" placement=\"bottom-end\">\n <v-overflow-menu-trigger overflowTrigger></v-overflow-menu-trigger>\n <v-overflow-menu-option\n [disabled]=\"actionsObs.loading\"\n (selected)=\"export(actionsObs.isReadOnlyProcess)\"\n >{{ 'interface.export' | translate }}\n </v-overflow-menu-option>\n </v-overflow-menu>\n\n <button\n *ngIf=\"actionsObs.context === 'case'\"\n cdsButton=\"tertiary\"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n (click)=\"navigateBack(null)\"\n >\n {{ 'interface.back' | translate }}\n <svg class=\"cds--btn__icon\" cdsIcon=\"return\" size=\"16\"></svg>\n </button>\n\n <button\n cdsButton=\"secondary\"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n [disabled]=\"actionsObs.loading\"\n (click)=\"validateProcessDefinition(actionsObs.isReadOnlyProcess)\"\n >\n {{ 'processManagement.validate' | translate }}\n <svg class=\"cds--btn__icon\" cdsIcon=\"list--checked\" size=\"16\"></svg>\n </button>\n\n <button\n [disabled]=\"!actionsObs.changesPending\"\n cdsButton=\"primary\"\n (click)=\"\n !actionsObs.creatingNewProcess\n ? deployChanges(actionsObs.isReadOnlyProcess)\n : deployNewProcessDefinition()\n \"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n [attr.data-test-id]=\"testIds.deployButton\"\n >\n {{ 'processManagement.deploy' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"deploy\" size=\"16\"></svg>\n </button>\n </div>\n </div>\n </ng-template>\n</ng-container>\n", styles: [":host{display:flex;flex-direction:column;gap:24px}.bpmn__container{position:relative;background-color:var(--cds-layer);width:100%}.bpmn__modeler{width:100%;height:100%;flex-direction:row;padding:1px;box-sizing:border-box;outline:1px solid var(--cds-border-subtle);outline-offset:-1px}.bpmn__modeler ::ng-deep .djs-container>svg{outline:none!important}.bpmn__modeler-canvas{width:100%;position:relative}.bpmn__modeler-panel{width:481px;padding-left:1px;box-shadow:inset 1px 0 0 0 var(--cds-border-subtle);box-sizing:border-box}.bpmn__loading{width:100%;height:100%;display:flex;justify-content:center;align-items:center;background-color:var(--cds-background-selected)}.page-header-actions{display:flex;width:100%;justify-content:space-between;align-items:center;gap:16px}.page-header-actions__left-container{display:flex;gap:16px;align-items:center}.page-header-actions__tags{display:flex;gap:8px;align-items:center}.page-header-actions__version-dropdown{width:150px}.page-header-actions__toggles{display:flex;gap:16px;align-items:center}.page-header-actions__toggles ::ng-deep cds-toggle{display:inline-flex;align-items:center}.page-header-actions__toggles ::ng-deep .cds--toggle__label-text{display:none}.page-header-actions__buttons{display:flex;gap:16px;align-items:center;flex-shrink:0}.valtimo-process-builder__header{display:flex;justify-content:space-between}.valtimo-process-builder__actions>*:not(:last-child){margin-right:8px}.validation-errors-list{position:absolute;top:8px;right:8px;z-index:10;width:320px;max-height:250px;overflow-y:auto;border:1px solid var(--cds-border-subtle);background-color:var(--cds-layer);border-radius:4px;box-shadow:0 2px 6px #00000026}.validation-errors-list details[open]>summary .validation-errors-list__arrow{transform:rotate(90deg)}.validation-errors-list__header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;font-size:14px;font-weight:600;color:var(--cds-support-error, #da1e28);cursor:pointer;list-style:none;-webkit-user-select:none;user-select:none}.validation-errors-list__header::-webkit-details-marker{display:none}.validation-errors-list__arrow{display:inline-flex;width:16px;height:16px;fill:currentColor;transition:transform .15s ease;flex-shrink:0}.validation-errors-list__items{display:flex;flex-direction:column;border-top:1px solid var(--cds-border-subtle)}.validation-errors-list__item{display:flex;align-items:flex-start;gap:10px;padding:10px 16px;border:none;border-bottom:1px solid var(--cds-border-subtle);border-left:3px solid var(--cds-support-error, #da1e28);background-color:var(--cds-notification-error-background, #fff1f1);text-align:left;cursor:pointer;font-family:inherit}.validation-errors-list__item.warning{background-color:var(--cds-notification-warning-background, #fdf6dd);border-left-color:var(--cds-support-warning, #f1c21b)}.validation-errors-list__item:last-child{border-bottom:none}.validation-errors-list__item:hover{filter:brightness(.97)}.validation-errors-list__icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;min-width:18px;margin-top:1px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700;line-height:0}.validation-errors-list__icon.warning{background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616)}.validation-errors-list__details{display:flex;flex-direction:column;gap:2px}.validation-errors-list__element{font-size:13px;font-weight:600;color:var(--cds-text-primary)}.validation-errors-list__reason{font-size:13px;color:var(--cds-text-primary)}::ng-deep .highlight-overlay-error:not(.djs-connection) .djs-visual>:nth-child(1){stroke:var(--cds-support-error, #da1e28)!important}::ng-deep .highlight-overlay-warning:not(.djs-connection) .djs-visual>:nth-child(1){stroke:var(--cds-support-warning, #f1c21b)!important}::ng-deep .djs-overlay-validation-error{overflow:visible!important;pointer-events:all!important}::ng-deep .validation-error-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .validation-error-overlay__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:14px;font-weight:700;line-height:0}::ng-deep .validation-error-overlay__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-error, #da1e28);color:var(--cds-support-error, #da1e28);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .validation-error-overlay:hover ::ng-deep .validation-error-overlay__text,::ng-deep .validation-error-overlay--active ::ng-deep .validation-error-overlay__text{display:block}::ng-deep .validation-warning-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .validation-warning-overlay__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616);font-size:14px;font-weight:700;line-height:0}::ng-deep .validation-warning-overlay__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .validation-warning-overlay:hover ::ng-deep .validation-warning-overlay__text,::ng-deep .validation-warning-overlay--active ::ng-deep .validation-warning-overlay__text{display:block}::ng-deep .validation-errors-panel{padding:8px 12px;display:flex;flex-direction:column;gap:8px}::ng-deep .validation-errors-panel__item{display:flex;align-items:flex-start;gap:8px;padding:8px 12px;background-color:var(--cds-notification-error-background, #fff1f1);border-left:3px solid var(--cds-support-error, #da1e28)}::ng-deep .validation-errors-panel__item.warning{background-color:var(--cds-notification-warning-background, #fdf6dd);border-left-color:var(--cds-support-warning, #f1c21b)}::ng-deep .validation-errors-panel__icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;min-width:18px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700;line-height:0}::ng-deep .validation-errors-panel__icon.warning{background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616)}::ng-deep .validation-errors-panel__reason{color:var(--cds-text-primary, #161616);font-size:13px;line-height:18px}::ng-deep .process-link-properties-panel{padding:8px 12px 16px;width:100%;display:flex;flex-direction:column;gap:16px}::ng-deep .process-link-properties-panel__buttons,::ng-deep .process-link-properties-panel__header{width:100%;display:flex;gap:16px}::ng-deep .process-link-properties-panel__header{align-items:flex-start;justify-content:space-between;border-bottom:1px solid var(--cds-border-subtle-00);padding-bottom:8px;padding-left:8px;padding-right:8px}::ng-deep .process-link-properties-panel__title{color:var(--cds-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;margin:auto 0}::ng-deep .process-link-properties-panel__title-container{display:flex;flex-direction:column;gap:4px}::ng-deep .process-link-properties-panel__title-container :last-child{color:var(--cds-text-helper);font-style:italic}::ng-deep .process-link-properties-panel .cds--tag{margin:0}::ng-deep .process-link-properties-panel .cds--btn{flex-shrink:1;width:100%;display:flex;align-items:center}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "directive", type: FitPageDirective, selector: "[fitPage]", inputs: ["spaceAdjustment", "fitPageDisabled", "disableOverflow", "bottomMargin"] }, { kind: "ngmodule", type: LoadingModule }, { kind: "directive", type: RenderInPageHeaderDirective, selector: "[renderInPageHeader]", inputs: ["fullWidth"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i2$2.Dropdown, selector: "cds-dropdown, ibm-dropdown", inputs: ["id", "label", "hideLabel", "helperText", "placeholder", "displayValue", "clearText", "size", "type", "theme", "disabled", "readonly", "skeleton", "inline", "disableArrowKeys", "invalid", "invalidText", "warn", "warnText", "appendInline", "scrollableContainer", "itemValueKey", "selectionFeedback", "menuButtonLabel", "selectedLabel", "dropUp", "fluid"], outputs: ["selected", "onClose", "close"] }, { kind: "component", type: i2$2.DropdownList, selector: "cds-dropdown-list, ibm-dropdown-list", inputs: ["ariaLabel", "items", "listTpl", "type", "showTitles"], outputs: ["select", "scroll", "blurIntent"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: SelectModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2$2.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "ngmodule", type: IconModule }, { kind: "directive", type: i2$2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i9.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i2$2.Tag, selector: "cds-tag, ibm-tag", inputs: ["type", "size", "class", "skeleton"] }, { kind: "ngmodule", type: ProcessLinkModule }, { kind: "component", type: i5.ProcessLinkModalComponent, selector: "valtimo-process-link-modal" }, { kind: "component", type: OverflowMenuComponent, selector: "v-overflow-menu", inputs: ["open", "placement", "menuWidth", "offsetX", "offsetY", "closeOnSelect", "useHostAsReference", "portalToBody"], outputs: ["openChange"] }, { kind: "component", type: OverflowMenuOptionComponent, selector: "v-overflow-menu-option", inputs: ["disabled", "type", "testId", "optionId"], outputs: ["selected"] }, { kind: "component", type: OverflowMenuTriggerComponent, selector: "v-overflow-menu-trigger", inputs: ["compact"] }, { kind: "ngmodule", type: ToggleModule }, { kind: "component", type: i2$2.Toggle, selector: "cds-toggle, ibm-toggle", inputs: ["offText", "onText", "label", "size", "hideLabel", "ariaLabel", "skeleton"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "component", type: i2$2.Tooltip, selector: "cds-tooltip, ibm-tooltip", inputs: ["id", "enterDelayMs", "leaveDelayMs", "disabled", "description", "templateContext"] }, { kind: "ngmodule", type: ConfirmationModalModule }, { kind: "component", type: i1$1.ConfirmationModalComponent, selector: "valtimo-confirmation-modal", inputs: ["titleTranslationKey", "title", "content", "contentTranslationKey", "confirmButtonText", "confirmButtonTextTranslationKey", "confirmButtonType", "showOptionalButton", "optionalButtonText", "optionalButtonTextTranslationKey", "optionalButtonType", "cancelButtonText", "cancelButtonTextTranslationKey", "cancelButtonType", "showModalSubject$", "outputOnConfirm", "outputOnOptional", "spacerAfterCancelButton"], outputs: ["confirmEvent", "optionalEvent", "cancelEvent"] }] }); }
3076
+ ], viewQueries: [{ propertyName: "modelerElementRef", first: true, predicate: ["modeler"], descendants: true }, { propertyName: "modelerPanelElementRef", first: true, predicate: ["modelerPanel"], descendants: true }, { propertyName: "viewerElementRef", first: true, predicate: ["viewer"], descendants: true }, { propertyName: "viewerPanelElementRef", first: true, predicate: ["viewerPanel"], descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div\n fitPage\n [disableOverflow]=\"true\"\n *ngIf=\"{\n processDefinitionVersions: processDefinitionVersions$ | async,\n selectedProcessDefinitionXml: selectedProcessDefinitionXml$ | async,\n loading: loading$ | async,\n isReadOnlyProcess: isReadOnlyProcess$ | async,\n hasEditPermissions: hasEditPermissions$ | async,\n } as obs\"\n data-carbon-theme=\"g10\"\n class=\"bpmn__container\"\n>\n <div\n class=\"bpmn__modeler\"\n [style.display]=\"obs.isReadOnlyProcess || !obs.hasEditPermissions ? 'none' : 'flex'\"\n >\n <div class=\"bpmn__modeler-canvas\" #modeler>\n <cds-tooltip\n align=\"top-right\"\n [autoAlign]=\"true\"\n [description]=\"'processManagement.markers.toggleTooltip' | translate\"\n class=\"markers-visibility-toggle-wrapper\"\n >\n <button\n type=\"button\"\n class=\"markers-visibility-toggle\"\n (click)=\"toggleMarkerVisibility()\"\n [attr.data-test-id]=\"testIds.markersVisibilityToggle\"\n >\n <svg cdsIcon=\"view\" *ngIf=\"$markersVisible()\" size=\"16\"></svg>\n <svg cdsIcon=\"view--off\" *ngIf=\"!$markersVisible()\" size=\"16\"></svg>\n <span class=\"markers-visibility-toggle__label\">\n {{ ($markersVisible() ? 'processManagement.markers.hide' : 'processManagement.markers.show') | translate }}\n </span>\n </button>\n </cds-tooltip>\n\n <div\n class=\"validation-errors-list\"\n *ngIf=\"validationErrors$ | async as validationErrors\"\n [style.display]=\"validationErrors.length > 0 ? '' : 'none'\"\n >\n <details open>\n <summary class=\"validation-errors-list__header\">\n <span>{{\n 'processManagement.validationErrorsCount'\n | translate: {count: validationErrors.length}\n }}</span>\n <svg\n class=\"validation-errors-list__arrow\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"m11.657 8-4.95 4.95a1 1 0 0 1-1.414-1.414L8.828 8 5.293 4.464A1 1 0 1 1 6.707 3.05L11.657 8Z\"\n />\n </svg>\n </summary>\n\n <div class=\"validation-errors-list__items\">\n <button\n *ngFor=\"let error of validationErrors\"\n class=\"validation-errors-list__item\"\n [class.warning]=\"error.severity === 'WARNING'\"\n (click)=\"onValidationErrorClick(error.elementId)\"\n >\n <span\n class=\"validation-errors-list__icon\"\n [class.warning]=\"error.severity === 'WARNING'\"\n >{{ error.severity === 'WARNING' ? '!' : '!' }}</span\n >\n\n <span class=\"validation-errors-list__details\">\n <span class=\"validation-errors-list__element\">{{\n error.elementName || error.elementId\n }}</span>\n\n <span\n class=\"validation-errors-list__reason\"\n [class.warning]=\"error.severity === 'WARNING'\"\n >{{ getValidationErrorMessage(error) }}</span\n >\n </span>\n </button>\n </div>\n </details>\n </div>\n </div>\n\n <div class=\"bpmn__modeler-panel\" #modelerPanel></div>\n </div>\n\n <div\n class=\"bpmn__modeler\"\n [style.display]=\"obs.isReadOnlyProcess || !obs.hasEditPermissions ? 'flex' : 'none'\"\n >\n <div class=\"bpmn__modeler-canvas\" #viewer>\n <cds-tooltip\n align=\"top-right\"\n [autoAlign]=\"true\"\n [description]=\"'processManagement.markers.toggleTooltip' | translate\"\n class=\"markers-visibility-toggle-wrapper\"\n >\n <button\n type=\"button\"\n class=\"markers-visibility-toggle\"\n (click)=\"toggleMarkerVisibility()\"\n [attr.data-test-id]=\"testIds.markersVisibilityToggle\"\n >\n <svg cdsIcon=\"view\" *ngIf=\"$markersVisible()\" size=\"16\"></svg>\n <svg cdsIcon=\"view--off\" *ngIf=\"!$markersVisible()\" size=\"16\"></svg>\n <span class=\"markers-visibility-toggle__label\">\n {{ ($markersVisible() ? 'processManagement.markers.hide' : 'processManagement.markers.show') | translate }}\n </span>\n </button>\n </cds-tooltip>\n </div>\n\n <div class=\"bpmn__modeler-panel\" #viewerPanel></div>\n </div>\n</div>\n\n<valtimo-process-link-modal></valtimo-process-link-modal>\n\n<valtimo-confirmation-modal\n [showModalSubject$]=\"showWarningConfirmationModal$\"\n [titleTranslationKey]=\"'processManagement.warningConfirmation.title'\"\n [contentTranslationKey]=\"'processManagement.warningConfirmation.content'\"\n [confirmButtonTextTranslationKey]=\"'processManagement.warningConfirmation.confirm'\"\n [cancelButtonTextTranslationKey]=\"'interface.cancel'\"\n (confirmEvent)=\"onWarningConfirmationConfirm()\"\n (cancelEvent)=\"onWarningConfirmationCancel()\"\n></valtimo-confirmation-modal>\n\n<ng-container renderInPageHeader [fullWidth]=\"true\">\n <ng-template>\n <div\n class=\"page-header-actions\"\n *ngIf=\"{\n processDefinitionVersionsListItems: processDefinitionVersionsListItems$ | async,\n loading: loading$ | async,\n changesPending: changesPending$ | async,\n isReadOnlyProcess: isReadOnlyProcess$ | async,\n isSystemProcess: isSystemProcess$ | async,\n compactMode: compactMode$ | async,\n creatingNewProcess: creatingNewProcess$ | async,\n context: context$ | async,\n hasEditPermissions: hasEditPermissions$ | async,\n draft: draft$ | async,\n canInitializeDocument: canInitializeDocument$ | async,\n startableByUser: startableByUser$ | async,\n updatingProcessDefinitionCaseDefinition: updatingProcessDefinitionCaseDefinition$ | async,\n } as actionsObs\"\n >\n <div class=\"page-header-actions__left-container\">\n <cds-dropdown\n *ngIf=\"!actionsObs.creatingNewProcess && actionsObs?.context === 'independent'\"\n class=\"page-header-actions__version-dropdown\"\n (selected)=\"selectedVersionChange($event)\"\n [disabled]=\"\n actionsObs.loading ||\n (actionsObs.processDefinitionVersionsListItems || []).length === 0 ||\n (actionsObs.processDefinitionVersionsListItems || []).length === 1\n \"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n >\n <cds-dropdown-list\n [items]=\"actionsObs.processDefinitionVersionsListItems || []\"\n ></cds-dropdown-list>\n </cds-dropdown>\n\n <div\n class=\"page-header-actions__tags\"\n *ngIf=\"\n actionsObs.isReadOnlyProcess ||\n !actionsObs.hasEditPermissions ||\n actionsObs.isSystemProcess\n \"\n >\n <cds-tag\n *ngIf=\"actionsObs.isReadOnlyProcess || !actionsObs.hasEditPermissions\"\n type=\"blue\"\n >{{ 'processManagement.readOnly' | translate }}</cds-tag\n >\n\n <cds-tag *ngIf=\"actionsObs.isSystemProcess\" type=\"red\">{{\n 'processManagement.systemProcess' | translate\n }}</cds-tag>\n </div>\n\n <div class=\"page-header-actions__toggles\">\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processManagement.draftTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.draft' | translate\"\n [offText]=\"'processManagement.draft' | translate\"\n [checked]=\"actionsObs.draft\"\n [disabled]=\"actionsObs.loading || !actionsObs.hasEditPermissions\"\n (checkedChange)=\"onProcessToggleChange('draft', $event)\"\n [attr.data-test-id]=\"testIds.draftToggle\"\n ></cds-toggle>\n </cds-tooltip>\n\n @if (actionsObs.context === 'case') {\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processCaseConnection.processCreatesCaseTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.canInitializeDocument' | translate\"\n [offText]=\"'processManagement.canInitializeDocument' | translate\"\n [checked]=\"actionsObs.canInitializeDocument\"\n [disabled]=\"\n actionsObs.loading ||\n actionsObs.updatingProcessDefinitionCaseDefinition ||\n !actionsObs.hasEditPermissions\n \"\n (checkedChange)=\"onProcessToggleChange('canInitializeDocument', $event)\"\n [attr.data-test-id]=\"testIds.startsCaseToggle\"\n ></cds-toggle>\n </cds-tooltip>\n\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processCaseConnection.startableWithinCaseTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.startableByUser' | translate\"\n [offText]=\"'processManagement.startableByUser' | translate\"\n [checked]=\"actionsObs.startableByUser\"\n [disabled]=\"\n actionsObs.loading ||\n actionsObs.updatingProcessDefinitionCaseDefinition ||\n !actionsObs.hasEditPermissions\n \"\n (checkedChange)=\"onProcessToggleChange('startableByUser', $event)\"\n [attr.data-test-id]=\"testIds.startableByUserToggle\"\n ></cds-toggle\n ></cds-tooltip>\n }\n </div>\n </div>\n\n <div class=\"page-header-actions__buttons\">\n <v-overflow-menu class=\"overflow-button\" placement=\"bottom-end\">\n <v-overflow-menu-trigger overflowTrigger></v-overflow-menu-trigger>\n <v-overflow-menu-option\n *ngIf=\"actionsObs.context !== 'case'\"\n [disabled]=\"actionsObs.loading\"\n [attr.data-test-id]=\"testIds.exportOption\"\n (selected)=\"export()\"\n >{{ 'interface.export' | translate }}\n </v-overflow-menu-option>\n\n <v-overflow-menu-option\n [disabled]=\"actionsObs.loading\"\n (selected)=\"exportBpmn(actionsObs.isReadOnlyProcess)\"\n >{{ 'processManagement.exportBpmn' | translate }}\n </v-overflow-menu-option>\n </v-overflow-menu>\n\n <button\n *ngIf=\"actionsObs.context === 'case'\"\n cdsButton=\"tertiary\"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n (click)=\"navigateBack(null)\"\n >\n {{ 'interface.back' | translate }}\n <svg class=\"cds--btn__icon\" cdsIcon=\"return\" size=\"16\"></svg>\n </button>\n\n <button\n cdsButton=\"secondary\"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n [disabled]=\"actionsObs.loading\"\n (click)=\"validateProcessDefinition(actionsObs.isReadOnlyProcess)\"\n >\n {{ 'processManagement.validate' | translate }}\n <svg class=\"cds--btn__icon\" cdsIcon=\"list--checked\" size=\"16\"></svg>\n </button>\n\n <button\n [disabled]=\"!actionsObs.changesPending\"\n cdsButton=\"primary\"\n (click)=\"\n !actionsObs.creatingNewProcess\n ? deployChanges(actionsObs.isReadOnlyProcess)\n : deployNewProcessDefinition()\n \"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n [attr.data-test-id]=\"testIds.deployButton\"\n >\n {{ 'processManagement.deploy' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"deploy\" size=\"16\"></svg>\n </button>\n </div>\n </div>\n </ng-template>\n</ng-container>\n", styles: [":host{display:flex;flex-direction:column;gap:24px}.bpmn__container{position:relative;background-color:var(--cds-layer);width:100%}.bpmn__modeler{width:100%;height:100%;flex-direction:row;padding:1px;box-sizing:border-box;outline:1px solid var(--cds-border-subtle);outline-offset:-1px}.bpmn__modeler ::ng-deep .djs-container>svg{outline:none!important}.bpmn__modeler-canvas{width:100%;position:relative}.bpmn__modeler-canvas .markers-visibility-toggle-wrapper{position:absolute;bottom:55px;right:15px;z-index:100}.bpmn__modeler-canvas .markers-visibility-toggle{display:flex;align-items:center;gap:6px;height:32px;padding:0 10px;border:none;border-radius:2px;background-color:var(--cds-layer);cursor:pointer;color:var(--cds-text-secondary);transition:background-color .15s,color .15s}.bpmn__modeler-canvas .markers-visibility-toggle:hover{background-color:var(--cds-layer-hover);color:var(--cds-text-primary)}.bpmn__modeler-canvas .markers-visibility-toggle:focus{outline:2px solid var(--cds-focus);outline-offset:-2px}.bpmn__modeler-canvas .markers-visibility-toggle__label{font-size:12px;white-space:nowrap}.bpmn__modeler-panel{width:481px;padding-left:1px;box-shadow:inset 1px 0 0 0 var(--cds-border-subtle);box-sizing:border-box}.bpmn__loading{width:100%;height:100%;display:flex;justify-content:center;align-items:center;background-color:var(--cds-background-selected)}.page-header-actions{display:flex;width:100%;justify-content:space-between;align-items:center;gap:16px}.page-header-actions__left-container{display:flex;gap:16px;align-items:center}.page-header-actions__tags{display:flex;gap:8px;align-items:center}.page-header-actions__version-dropdown{width:150px}.page-header-actions__toggles{display:flex;gap:16px;align-items:center}.page-header-actions__toggles ::ng-deep cds-toggle{display:inline-flex;align-items:center}.page-header-actions__toggles ::ng-deep .cds--toggle__label-text{display:none}.page-header-actions__buttons{display:flex;gap:16px;align-items:center;flex-shrink:0}.valtimo-process-builder__header{display:flex;justify-content:space-between}.valtimo-process-builder__actions>*:not(:last-child){margin-right:8px}.validation-errors-list{position:absolute;top:8px;right:8px;z-index:10;width:320px;max-height:250px;overflow-y:auto;border:1px solid var(--cds-border-subtle);background-color:var(--cds-layer);border-radius:4px;box-shadow:0 2px 6px #00000026}.validation-errors-list details[open]>summary .validation-errors-list__arrow{transform:rotate(90deg)}.validation-errors-list__header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;font-size:14px;font-weight:600;color:var(--cds-support-error, #da1e28);cursor:pointer;list-style:none;-webkit-user-select:none;user-select:none}.validation-errors-list__header::-webkit-details-marker{display:none}.validation-errors-list__arrow{display:inline-flex;width:16px;height:16px;fill:currentColor;transition:transform .15s ease;flex-shrink:0}.validation-errors-list__items{display:flex;flex-direction:column;border-top:1px solid var(--cds-border-subtle)}.validation-errors-list__item{display:flex;align-items:flex-start;gap:10px;padding:10px 16px;border:none;border-bottom:1px solid var(--cds-border-subtle);border-left:3px solid var(--cds-support-error, #da1e28);background-color:var(--cds-notification-error-background, #fff1f1);text-align:left;cursor:pointer;font-family:inherit}.validation-errors-list__item.warning{background-color:var(--cds-notification-warning-background, #fdf6dd);border-left-color:var(--cds-support-warning, #f1c21b)}.validation-errors-list__item:last-child{border-bottom:none}.validation-errors-list__item:hover{filter:brightness(.97)}.validation-errors-list__icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;min-width:18px;margin-top:1px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700;line-height:0}.validation-errors-list__icon.warning{background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616)}.validation-errors-list__details{display:flex;flex-direction:column;gap:2px}.validation-errors-list__element{font-size:13px;font-weight:600;color:var(--cds-text-primary)}.validation-errors-list__reason{font-size:13px;color:var(--cds-text-primary)}::ng-deep .highlight-overlay-error:not(.djs-connection) .djs-visual>:nth-child(1){stroke:var(--cds-support-error, #da1e28)!important}::ng-deep .highlight-overlay-warning:not(.djs-connection) .djs-visual>:nth-child(1){stroke:var(--cds-support-warning, #f1c21b)!important}::ng-deep .djs-overlay-validation-error{overflow:visible!important;pointer-events:all!important}::ng-deep .validation-error-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .validation-error-overlay__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:14px;font-weight:700;line-height:0}::ng-deep .validation-error-overlay__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-error, #da1e28);color:var(--cds-support-error, #da1e28);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .validation-error-overlay:hover ::ng-deep .validation-error-overlay__text,::ng-deep .validation-error-overlay--active ::ng-deep .validation-error-overlay__text{display:block}::ng-deep .validation-warning-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .validation-warning-overlay__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616);font-size:14px;font-weight:700;line-height:0}::ng-deep .validation-warning-overlay__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .validation-warning-overlay:hover ::ng-deep .validation-warning-overlay__text,::ng-deep .validation-warning-overlay--active ::ng-deep .validation-warning-overlay__text{display:block}::ng-deep .djs-overlay-activity-marker{overflow:visible!important;pointer-events:all!important}::ng-deep .activity-marker-overlay{display:flex;gap:2px}::ng-deep .activity-marker-badge{position:relative;cursor:pointer;pointer-events:all}::ng-deep .activity-marker-badge__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;font-size:14px;font-weight:700;line-height:0}::ng-deep .activity-marker-badge__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .activity-marker-badge:hover ::ng-deep .activity-marker-badge__text,::ng-deep .activity-marker-badge--active ::ng-deep .activity-marker-badge__text{display:block}::ng-deep .activity-marker-badge--process-link ::ng-deep .activity-marker-badge__icon{background-color:var(--cds-support-info, #0043ce);color:var(--cds-text-on-color, #ffffff)}::ng-deep .activity-marker-badge--process-link ::ng-deep .activity-marker-badge__text{border:1px solid var(--cds-support-info, #0043ce);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff)}::ng-deep .activity-marker-badge--execution-listener ::ng-deep .activity-marker-badge__icon{background-color:var(--cds-purple-60, #8a3ffc);color:var(--cds-text-on-color, #ffffff)}::ng-deep .activity-marker-badge--execution-listener ::ng-deep .activity-marker-badge__text{border:1px solid var(--cds-purple-60, #8a3ffc);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff)}::ng-deep .activity-marker-badge--task-listener ::ng-deep .activity-marker-badge__icon{background-color:var(--cds-teal-50, #009d9a);color:var(--cds-text-on-color, #ffffff)}::ng-deep .activity-marker-badge--task-listener ::ng-deep .activity-marker-badge__text{border:1px solid var(--cds-teal-50, #009d9a);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff)}::ng-deep .validation-errors-panel{padding:8px 12px;display:flex;flex-direction:column;gap:8px}::ng-deep .validation-errors-panel__item{display:flex;align-items:flex-start;gap:8px;padding:8px 12px;background-color:var(--cds-notification-error-background, #fff1f1);border-left:3px solid var(--cds-support-error, #da1e28)}::ng-deep .validation-errors-panel__item.warning{background-color:var(--cds-notification-warning-background, #fdf6dd);border-left-color:var(--cds-support-warning, #f1c21b)}::ng-deep .validation-errors-panel__icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;min-width:18px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700;line-height:0}::ng-deep .validation-errors-panel__icon.warning{background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616)}::ng-deep .validation-errors-panel__reason{color:var(--cds-text-primary, #161616);font-size:13px;line-height:18px}::ng-deep .bio-properties-panel-entry.validation-error-field .bio-properties-panel-input,::ng-deep .bio-properties-panel-entry.validation-error-field .bio-properties-panel-textfield,::ng-deep .bio-properties-panel-entry.validation-error-field .bio-properties-panel-feel-editor-container{border:2px solid var(--cds-support-error, #da1e28)!important;background-color:var(--cds-notification-error-background, #fff1f1)!important}::ng-deep .expression-editor-param input.validation-error-param,::ng-deep input.expression-editor-input.validation-error-param,::ng-deep .expression-editor-technical input.validation-error-param,::ng-deep .expression-editor-technical textarea.validation-error-param{border:2px solid #da1e28!important;background-color:#fff1f1!important;border-color:#da1e28!important}::ng-deep .process-link-properties-panel{padding:8px 12px 16px;width:100%;display:flex;flex-direction:column;gap:16px}::ng-deep .process-link-properties-panel__buttons,::ng-deep .process-link-properties-panel__header{width:100%;display:flex;gap:16px}::ng-deep .process-link-properties-panel__header{align-items:flex-start;justify-content:space-between;border-bottom:1px solid var(--cds-border-subtle-00);padding-bottom:8px;padding-left:8px;padding-right:8px}::ng-deep .process-link-properties-panel__title{color:var(--cds-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;margin:auto 0}::ng-deep .process-link-properties-panel__title-container{display:flex;flex-direction:column;gap:4px}::ng-deep .process-link-properties-panel__title-container :last-child{color:var(--cds-text-helper);font-style:italic}::ng-deep .process-link-properties-panel .cds--tag{margin:0}::ng-deep .process-link-properties-panel .cds--btn{flex-shrink:1;width:100%;display:flex;align-items:center}::ng-deep .djs-overlay-autofilled-indicator{overflow:visible!important;pointer-events:all!important}::ng-deep .autofilled-indicator-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .autofilled-indicator-overlay .autofilled-indicator-icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-info, #0043ce);color:var(--cds-text-on-color, #ffffff);font-size:14px;font-weight:700;line-height:0}::ng-deep .autofilled-indicator-overlay .autofilled-indicator-tooltip{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-info, #0043ce);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .autofilled-indicator-overlay:hover .autofilled-indicator-tooltip{display:block}::ng-deep .autofilled-notification-panel{display:flex;align-items:center;gap:8px;padding:8px 12px;background-color:var(--cds-layer-02, #f4f4f4);border-left:3px solid var(--cds-support-info, #0043ce);margin-bottom:8px}::ng-deep .autofilled-notification-panel__icon{display:flex;align-items:center;justify-content:center;min-width:18px;height:18px;border-radius:50%;background-color:var(--cds-support-info, #0043ce);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700}::ng-deep .autofilled-notification-panel__message{flex:1;font-size:12px;color:var(--cds-text-primary, #161616)}::ng-deep .autofilled-notification-panel__dismiss{background:none;border:none;cursor:pointer;padding:2px 6px;font-size:16px;color:var(--cds-text-secondary, #525252);line-height:1}::ng-deep .autofilled-notification-panel__dismiss:hover{color:var(--cds-text-primary, #161616)}\n/*!\n * Copyright 2015-2026 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "directive", type: FitPageDirective, selector: "[fitPage]", inputs: ["spaceAdjustment", "fitPageDisabled", "disableOverflow", "bottomMargin"] }, { kind: "ngmodule", type: LoadingModule }, { kind: "directive", type: RenderInPageHeaderDirective, selector: "[renderInPageHeader]", inputs: ["fullWidth"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i2$2.Dropdown, selector: "cds-dropdown, ibm-dropdown", inputs: ["id", "label", "hideLabel", "helperText", "placeholder", "displayValue", "clearText", "size", "type", "theme", "disabled", "readonly", "skeleton", "inline", "disableArrowKeys", "invalid", "invalidText", "warn", "warnText", "appendInline", "scrollableContainer", "itemValueKey", "selectionFeedback", "menuButtonLabel", "selectedLabel", "dropUp", "fluid"], outputs: ["selected", "onClose", "close"] }, { kind: "component", type: i2$2.DropdownList, selector: "cds-dropdown-list, ibm-dropdown-list", inputs: ["ariaLabel", "items", "listTpl", "type", "showTitles"], outputs: ["select", "scroll", "blurIntent"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: SelectModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2$2.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "ngmodule", type: IconModule }, { kind: "directive", type: i2$2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i9.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i2$2.Tag, selector: "cds-tag, ibm-tag", inputs: ["type", "size", "class", "skeleton"] }, { kind: "ngmodule", type: ProcessLinkModule }, { kind: "component", type: i5.ProcessLinkModalComponent, selector: "valtimo-process-link-modal" }, { kind: "ngmodule", type: ToggleModule }, { kind: "component", type: i2$2.Toggle, selector: "cds-toggle, ibm-toggle", inputs: ["offText", "onText", "label", "size", "hideLabel", "ariaLabel", "skeleton"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "component", type: i2$2.Tooltip, selector: "cds-tooltip, ibm-tooltip", inputs: ["id", "enterDelayMs", "leaveDelayMs", "disabled", "description", "templateContext"] }, { kind: "ngmodule", type: ConfirmationModalModule }, { kind: "component", type: i1$1.ConfirmationModalComponent, selector: "valtimo-confirmation-modal", inputs: ["titleTranslationKey", "title", "content", "contentTranslationKey", "confirmButtonText", "confirmButtonTextTranslationKey", "confirmButtonType", "showOptionalButton", "optionalButtonText", "optionalButtonTextTranslationKey", "optionalButtonType", "cancelButtonText", "cancelButtonTextTranslationKey", "cancelButtonType", "showModalSubject$", "outputOnConfirm", "outputOnOptional", "spacerAfterCancelButton"], outputs: ["confirmEvent", "optionalEvent", "cancelEvent"] }, { kind: "ngmodule", type: OverflowMenuModule }, { kind: "component", type: i1$1.OverflowMenuComponent, selector: "v-overflow-menu", inputs: ["open", "placement", "menuWidth", "offsetX", "offsetY", "closeOnSelect", "useHostAsReference", "portalToBody"], outputs: ["openChange"] }, { kind: "component", type: i1$1.OverflowMenuOptionComponent, selector: "v-overflow-menu-option", inputs: ["disabled", "type", "testId", "optionId"], outputs: ["selected"] }, { kind: "component", type: i1$1.OverflowMenuTriggerComponent, selector: "v-overflow-menu-trigger", inputs: ["compact", "label"] }] }); }
1925
3077
  }
1926
3078
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementBuilderComponent, decorators: [{
1927
3079
  type: Component,
@@ -1938,20 +3090,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
1938
3090
  TranslateModule,
1939
3091
  TagModule,
1940
3092
  ProcessLinkModule,
1941
- ProcessLinkModule,
1942
- OverflowMenuComponent,
1943
- OverflowMenuOptionComponent,
1944
- OverflowMenuTriggerComponent,
1945
3093
  ToggleModule,
1946
3094
  TooltipModule,
1947
3095
  ConfirmationModalModule,
3096
+ OverflowMenuModule,
1948
3097
  ], providers: [
1949
3098
  ProcessManagementEditorService,
1950
3099
  ProcessLinkStateService,
1951
3100
  ProcessLinkStepService,
1952
3101
  ProcessLinkButtonService,
1953
- ], template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div\n fitPage\n [disableOverflow]=\"true\"\n *ngIf=\"{\n processDefinitionVersions: processDefinitionVersions$ | async,\n selectedProcessDefinitionXml: selectedProcessDefinitionXml$ | async,\n loading: loading$ | async,\n isReadOnlyProcess: isReadOnlyProcess$ | async,\n hasEditPermissions: hasEditPermissions$ | async,\n } as obs\"\n data-carbon-theme=\"g10\"\n class=\"bpmn__container\"\n>\n <div\n class=\"bpmn__modeler\"\n [style.display]=\"obs.isReadOnlyProcess || !obs.hasEditPermissions ? 'none' : 'flex'\"\n >\n <div class=\"bpmn__modeler-canvas\" #modeler>\n <div\n class=\"validation-errors-list\"\n *ngIf=\"validationErrors$ | async as validationErrors\"\n [style.display]=\"validationErrors.length > 0 ? '' : 'none'\"\n >\n <details open>\n <summary class=\"validation-errors-list__header\">\n <span>{{\n 'processManagement.validationErrorsCount'\n | translate: {count: validationErrors.length}\n }}</span>\n <svg\n class=\"validation-errors-list__arrow\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"m11.657 8-4.95 4.95a1 1 0 0 1-1.414-1.414L8.828 8 5.293 4.464A1 1 0 1 1 6.707 3.05L11.657 8Z\"\n />\n </svg>\n </summary>\n\n <div class=\"validation-errors-list__items\">\n <button\n *ngFor=\"let error of validationErrors\"\n class=\"validation-errors-list__item\"\n [class.warning]=\"error.severity === 'WARNING'\"\n (click)=\"onValidationErrorClick(error.elementId)\"\n >\n <span\n class=\"validation-errors-list__icon\"\n [class.warning]=\"error.severity === 'WARNING'\"\n >{{ error.severity === 'WARNING' ? '!' : '!' }}</span\n >\n\n <span class=\"validation-errors-list__details\">\n <span class=\"validation-errors-list__element\">{{\n error.elementName || error.elementId\n }}</span>\n\n <span\n class=\"validation-errors-list__reason\"\n [class.warning]=\"error.severity === 'WARNING'\"\n >{{ getValidationErrorMessage(error) }}</span\n >\n </span>\n </button>\n </div>\n </details>\n </div>\n </div>\n\n <div class=\"bpmn__modeler-panel\" #modelerPanel></div>\n </div>\n\n <div\n class=\"bpmn__modeler\"\n [style.display]=\"obs.isReadOnlyProcess || !obs.hasEditPermissions ? 'flex' : 'none'\"\n >\n <div class=\"bpmn__modeler-canvas\" #viewer></div>\n\n <div class=\"bpmn__modeler-panel\" #viewerPanel></div>\n </div>\n</div>\n\n<valtimo-process-link-modal></valtimo-process-link-modal>\n\n<valtimo-confirmation-modal\n [showModalSubject$]=\"showWarningConfirmationModal$\"\n [titleTranslationKey]=\"'processManagement.warningConfirmation.title'\"\n [contentTranslationKey]=\"'processManagement.warningConfirmation.content'\"\n [confirmButtonTextTranslationKey]=\"'processManagement.warningConfirmation.confirm'\"\n [cancelButtonTextTranslationKey]=\"'interface.cancel'\"\n (confirmEvent)=\"onWarningConfirmationConfirm()\"\n (cancelEvent)=\"onWarningConfirmationCancel()\"\n></valtimo-confirmation-modal>\n\n<ng-container renderInPageHeader [fullWidth]=\"true\">\n <ng-template>\n <div\n class=\"page-header-actions\"\n *ngIf=\"{\n processDefinitionVersionsListItems: processDefinitionVersionsListItems$ | async,\n loading: loading$ | async,\n changesPending: changesPending$ | async,\n isReadOnlyProcess: isReadOnlyProcess$ | async,\n isSystemProcess: isSystemProcess$ | async,\n compactMode: compactMode$ | async,\n creatingNewProcess: creatingNewProcess$ | async,\n context: context$ | async,\n hasEditPermissions: hasEditPermissions$ | async,\n draft: draft$ | async,\n canInitializeDocument: canInitializeDocument$ | async,\n startableByUser: startableByUser$ | async,\n updatingProcessDefinitionCaseDefinition: updatingProcessDefinitionCaseDefinition$ | async,\n } as actionsObs\"\n >\n <div class=\"page-header-actions__left-container\">\n <cds-dropdown\n *ngIf=\"!actionsObs.creatingNewProcess && actionsObs?.context === 'independent'\"\n class=\"page-header-actions__version-dropdown\"\n (selected)=\"selectedVersionChange($event)\"\n [disabled]=\"\n actionsObs.loading ||\n (actionsObs.processDefinitionVersionsListItems || []).length === 0 ||\n (actionsObs.processDefinitionVersionsListItems || []).length === 1\n \"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n >\n <cds-dropdown-list\n [items]=\"actionsObs.processDefinitionVersionsListItems || []\"\n ></cds-dropdown-list>\n </cds-dropdown>\n\n <div\n class=\"page-header-actions__tags\"\n *ngIf=\"\n actionsObs.isReadOnlyProcess ||\n !actionsObs.hasEditPermissions ||\n actionsObs.isSystemProcess\n \"\n >\n <cds-tag\n *ngIf=\"actionsObs.isReadOnlyProcess || !actionsObs.hasEditPermissions\"\n type=\"blue\"\n >{{ 'processManagement.readOnly' | translate }}</cds-tag\n >\n\n <cds-tag *ngIf=\"actionsObs.isSystemProcess\" type=\"red\">{{\n 'processManagement.systemProcess' | translate\n }}</cds-tag>\n </div>\n\n <div class=\"page-header-actions__toggles\">\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processManagement.draftTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.draft' | translate\"\n [offText]=\"'processManagement.draft' | translate\"\n [checked]=\"actionsObs.draft\"\n [disabled]=\"actionsObs.loading || !actionsObs.hasEditPermissions\"\n (checkedChange)=\"onProcessToggleChange('draft', $event)\"\n [attr.data-test-id]=\"testIds.draftToggle\"\n ></cds-toggle>\n </cds-tooltip>\n\n @if (actionsObs.context === 'case') {\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processCaseConnection.processCreatesCaseTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.canInitializeDocument' | translate\"\n [offText]=\"'processManagement.canInitializeDocument' | translate\"\n [checked]=\"actionsObs.canInitializeDocument\"\n [disabled]=\"\n actionsObs.loading ||\n actionsObs.updatingProcessDefinitionCaseDefinition ||\n !actionsObs.hasEditPermissions\n \"\n (checkedChange)=\"onProcessToggleChange('canInitializeDocument', $event)\"\n [attr.data-test-id]=\"testIds.startsCaseToggle\"\n ></cds-toggle>\n </cds-tooltip>\n\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processCaseConnection.startableWithinCaseTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.startableByUser' | translate\"\n [offText]=\"'processManagement.startableByUser' | translate\"\n [checked]=\"actionsObs.startableByUser\"\n [disabled]=\"\n actionsObs.loading ||\n actionsObs.updatingProcessDefinitionCaseDefinition ||\n !actionsObs.hasEditPermissions\n \"\n (checkedChange)=\"onProcessToggleChange('startableByUser', $event)\"\n [attr.data-test-id]=\"testIds.startableByUserToggle\"\n ></cds-toggle\n ></cds-tooltip>\n }\n </div>\n </div>\n\n <div class=\"page-header-actions__buttons\">\n <v-overflow-menu class=\"overflow-button\" placement=\"bottom-end\">\n <v-overflow-menu-trigger overflowTrigger></v-overflow-menu-trigger>\n <v-overflow-menu-option\n [disabled]=\"actionsObs.loading\"\n (selected)=\"export(actionsObs.isReadOnlyProcess)\"\n >{{ 'interface.export' | translate }}\n </v-overflow-menu-option>\n </v-overflow-menu>\n\n <button\n *ngIf=\"actionsObs.context === 'case'\"\n cdsButton=\"tertiary\"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n (click)=\"navigateBack(null)\"\n >\n {{ 'interface.back' | translate }}\n <svg class=\"cds--btn__icon\" cdsIcon=\"return\" size=\"16\"></svg>\n </button>\n\n <button\n cdsButton=\"secondary\"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n [disabled]=\"actionsObs.loading\"\n (click)=\"validateProcessDefinition(actionsObs.isReadOnlyProcess)\"\n >\n {{ 'processManagement.validate' | translate }}\n <svg class=\"cds--btn__icon\" cdsIcon=\"list--checked\" size=\"16\"></svg>\n </button>\n\n <button\n [disabled]=\"!actionsObs.changesPending\"\n cdsButton=\"primary\"\n (click)=\"\n !actionsObs.creatingNewProcess\n ? deployChanges(actionsObs.isReadOnlyProcess)\n : deployNewProcessDefinition()\n \"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n [attr.data-test-id]=\"testIds.deployButton\"\n >\n {{ 'processManagement.deploy' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"deploy\" size=\"16\"></svg>\n </button>\n </div>\n </div>\n </ng-template>\n</ng-container>\n", styles: [":host{display:flex;flex-direction:column;gap:24px}.bpmn__container{position:relative;background-color:var(--cds-layer);width:100%}.bpmn__modeler{width:100%;height:100%;flex-direction:row;padding:1px;box-sizing:border-box;outline:1px solid var(--cds-border-subtle);outline-offset:-1px}.bpmn__modeler ::ng-deep .djs-container>svg{outline:none!important}.bpmn__modeler-canvas{width:100%;position:relative}.bpmn__modeler-panel{width:481px;padding-left:1px;box-shadow:inset 1px 0 0 0 var(--cds-border-subtle);box-sizing:border-box}.bpmn__loading{width:100%;height:100%;display:flex;justify-content:center;align-items:center;background-color:var(--cds-background-selected)}.page-header-actions{display:flex;width:100%;justify-content:space-between;align-items:center;gap:16px}.page-header-actions__left-container{display:flex;gap:16px;align-items:center}.page-header-actions__tags{display:flex;gap:8px;align-items:center}.page-header-actions__version-dropdown{width:150px}.page-header-actions__toggles{display:flex;gap:16px;align-items:center}.page-header-actions__toggles ::ng-deep cds-toggle{display:inline-flex;align-items:center}.page-header-actions__toggles ::ng-deep .cds--toggle__label-text{display:none}.page-header-actions__buttons{display:flex;gap:16px;align-items:center;flex-shrink:0}.valtimo-process-builder__header{display:flex;justify-content:space-between}.valtimo-process-builder__actions>*:not(:last-child){margin-right:8px}.validation-errors-list{position:absolute;top:8px;right:8px;z-index:10;width:320px;max-height:250px;overflow-y:auto;border:1px solid var(--cds-border-subtle);background-color:var(--cds-layer);border-radius:4px;box-shadow:0 2px 6px #00000026}.validation-errors-list details[open]>summary .validation-errors-list__arrow{transform:rotate(90deg)}.validation-errors-list__header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;font-size:14px;font-weight:600;color:var(--cds-support-error, #da1e28);cursor:pointer;list-style:none;-webkit-user-select:none;user-select:none}.validation-errors-list__header::-webkit-details-marker{display:none}.validation-errors-list__arrow{display:inline-flex;width:16px;height:16px;fill:currentColor;transition:transform .15s ease;flex-shrink:0}.validation-errors-list__items{display:flex;flex-direction:column;border-top:1px solid var(--cds-border-subtle)}.validation-errors-list__item{display:flex;align-items:flex-start;gap:10px;padding:10px 16px;border:none;border-bottom:1px solid var(--cds-border-subtle);border-left:3px solid var(--cds-support-error, #da1e28);background-color:var(--cds-notification-error-background, #fff1f1);text-align:left;cursor:pointer;font-family:inherit}.validation-errors-list__item.warning{background-color:var(--cds-notification-warning-background, #fdf6dd);border-left-color:var(--cds-support-warning, #f1c21b)}.validation-errors-list__item:last-child{border-bottom:none}.validation-errors-list__item:hover{filter:brightness(.97)}.validation-errors-list__icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;min-width:18px;margin-top:1px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700;line-height:0}.validation-errors-list__icon.warning{background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616)}.validation-errors-list__details{display:flex;flex-direction:column;gap:2px}.validation-errors-list__element{font-size:13px;font-weight:600;color:var(--cds-text-primary)}.validation-errors-list__reason{font-size:13px;color:var(--cds-text-primary)}::ng-deep .highlight-overlay-error:not(.djs-connection) .djs-visual>:nth-child(1){stroke:var(--cds-support-error, #da1e28)!important}::ng-deep .highlight-overlay-warning:not(.djs-connection) .djs-visual>:nth-child(1){stroke:var(--cds-support-warning, #f1c21b)!important}::ng-deep .djs-overlay-validation-error{overflow:visible!important;pointer-events:all!important}::ng-deep .validation-error-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .validation-error-overlay__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:14px;font-weight:700;line-height:0}::ng-deep .validation-error-overlay__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-error, #da1e28);color:var(--cds-support-error, #da1e28);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .validation-error-overlay:hover ::ng-deep .validation-error-overlay__text,::ng-deep .validation-error-overlay--active ::ng-deep .validation-error-overlay__text{display:block}::ng-deep .validation-warning-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .validation-warning-overlay__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616);font-size:14px;font-weight:700;line-height:0}::ng-deep .validation-warning-overlay__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .validation-warning-overlay:hover ::ng-deep .validation-warning-overlay__text,::ng-deep .validation-warning-overlay--active ::ng-deep .validation-warning-overlay__text{display:block}::ng-deep .validation-errors-panel{padding:8px 12px;display:flex;flex-direction:column;gap:8px}::ng-deep .validation-errors-panel__item{display:flex;align-items:flex-start;gap:8px;padding:8px 12px;background-color:var(--cds-notification-error-background, #fff1f1);border-left:3px solid var(--cds-support-error, #da1e28)}::ng-deep .validation-errors-panel__item.warning{background-color:var(--cds-notification-warning-background, #fdf6dd);border-left-color:var(--cds-support-warning, #f1c21b)}::ng-deep .validation-errors-panel__icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;min-width:18px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700;line-height:0}::ng-deep .validation-errors-panel__icon.warning{background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616)}::ng-deep .validation-errors-panel__reason{color:var(--cds-text-primary, #161616);font-size:13px;line-height:18px}::ng-deep .process-link-properties-panel{padding:8px 12px 16px;width:100%;display:flex;flex-direction:column;gap:16px}::ng-deep .process-link-properties-panel__buttons,::ng-deep .process-link-properties-panel__header{width:100%;display:flex;gap:16px}::ng-deep .process-link-properties-panel__header{align-items:flex-start;justify-content:space-between;border-bottom:1px solid var(--cds-border-subtle-00);padding-bottom:8px;padding-left:8px;padding-right:8px}::ng-deep .process-link-properties-panel__title{color:var(--cds-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;margin:auto 0}::ng-deep .process-link-properties-panel__title-container{display:flex;flex-direction:column;gap:4px}::ng-deep .process-link-properties-panel__title-container :last-child{color:var(--cds-text-helper);font-style:italic}::ng-deep .process-link-properties-panel .cds--tag{margin:0}::ng-deep .process-link-properties-panel .cds--btn{flex-shrink:1;width:100%;display:flex;align-items:center}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"] }]
1954
- }], ctorParameters: () => [{ type: i1$1.BreadcrumbService }, { type: i2$2.IconService }, { type: i3.NGXLogger }, { type: i1$1.ModalService }, { type: i2$1.GlobalNotificationService }, { type: i1$1.PageHeaderService }, { type: i1$1.PageTitleService }, { type: i5.ProcessLinkService }, { type: i5.ProcessLinkStateService }, { type: ProcessManagementEditorService }, { type: ProcessManagementService }, { type: i7.ProcessService }, { type: i8.ActivatedRoute }, { type: i8.Router }, { type: i9.TranslateService }, { type: i10.PluginTranslationService }, { type: i2$1.EditPermissionsService }, { type: i5.ProcessLinkBuildingBlockApiService }], propDecorators: { modelerElementRef: [{
3102
+ ], template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div\n fitPage\n [disableOverflow]=\"true\"\n *ngIf=\"{\n processDefinitionVersions: processDefinitionVersions$ | async,\n selectedProcessDefinitionXml: selectedProcessDefinitionXml$ | async,\n loading: loading$ | async,\n isReadOnlyProcess: isReadOnlyProcess$ | async,\n hasEditPermissions: hasEditPermissions$ | async,\n } as obs\"\n data-carbon-theme=\"g10\"\n class=\"bpmn__container\"\n>\n <div\n class=\"bpmn__modeler\"\n [style.display]=\"obs.isReadOnlyProcess || !obs.hasEditPermissions ? 'none' : 'flex'\"\n >\n <div class=\"bpmn__modeler-canvas\" #modeler>\n <cds-tooltip\n align=\"top-right\"\n [autoAlign]=\"true\"\n [description]=\"'processManagement.markers.toggleTooltip' | translate\"\n class=\"markers-visibility-toggle-wrapper\"\n >\n <button\n type=\"button\"\n class=\"markers-visibility-toggle\"\n (click)=\"toggleMarkerVisibility()\"\n [attr.data-test-id]=\"testIds.markersVisibilityToggle\"\n >\n <svg cdsIcon=\"view\" *ngIf=\"$markersVisible()\" size=\"16\"></svg>\n <svg cdsIcon=\"view--off\" *ngIf=\"!$markersVisible()\" size=\"16\"></svg>\n <span class=\"markers-visibility-toggle__label\">\n {{ ($markersVisible() ? 'processManagement.markers.hide' : 'processManagement.markers.show') | translate }}\n </span>\n </button>\n </cds-tooltip>\n\n <div\n class=\"validation-errors-list\"\n *ngIf=\"validationErrors$ | async as validationErrors\"\n [style.display]=\"validationErrors.length > 0 ? '' : 'none'\"\n >\n <details open>\n <summary class=\"validation-errors-list__header\">\n <span>{{\n 'processManagement.validationErrorsCount'\n | translate: {count: validationErrors.length}\n }}</span>\n <svg\n class=\"validation-errors-list__arrow\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"m11.657 8-4.95 4.95a1 1 0 0 1-1.414-1.414L8.828 8 5.293 4.464A1 1 0 1 1 6.707 3.05L11.657 8Z\"\n />\n </svg>\n </summary>\n\n <div class=\"validation-errors-list__items\">\n <button\n *ngFor=\"let error of validationErrors\"\n class=\"validation-errors-list__item\"\n [class.warning]=\"error.severity === 'WARNING'\"\n (click)=\"onValidationErrorClick(error.elementId)\"\n >\n <span\n class=\"validation-errors-list__icon\"\n [class.warning]=\"error.severity === 'WARNING'\"\n >{{ error.severity === 'WARNING' ? '!' : '!' }}</span\n >\n\n <span class=\"validation-errors-list__details\">\n <span class=\"validation-errors-list__element\">{{\n error.elementName || error.elementId\n }}</span>\n\n <span\n class=\"validation-errors-list__reason\"\n [class.warning]=\"error.severity === 'WARNING'\"\n >{{ getValidationErrorMessage(error) }}</span\n >\n </span>\n </button>\n </div>\n </details>\n </div>\n </div>\n\n <div class=\"bpmn__modeler-panel\" #modelerPanel></div>\n </div>\n\n <div\n class=\"bpmn__modeler\"\n [style.display]=\"obs.isReadOnlyProcess || !obs.hasEditPermissions ? 'flex' : 'none'\"\n >\n <div class=\"bpmn__modeler-canvas\" #viewer>\n <cds-tooltip\n align=\"top-right\"\n [autoAlign]=\"true\"\n [description]=\"'processManagement.markers.toggleTooltip' | translate\"\n class=\"markers-visibility-toggle-wrapper\"\n >\n <button\n type=\"button\"\n class=\"markers-visibility-toggle\"\n (click)=\"toggleMarkerVisibility()\"\n [attr.data-test-id]=\"testIds.markersVisibilityToggle\"\n >\n <svg cdsIcon=\"view\" *ngIf=\"$markersVisible()\" size=\"16\"></svg>\n <svg cdsIcon=\"view--off\" *ngIf=\"!$markersVisible()\" size=\"16\"></svg>\n <span class=\"markers-visibility-toggle__label\">\n {{ ($markersVisible() ? 'processManagement.markers.hide' : 'processManagement.markers.show') | translate }}\n </span>\n </button>\n </cds-tooltip>\n </div>\n\n <div class=\"bpmn__modeler-panel\" #viewerPanel></div>\n </div>\n</div>\n\n<valtimo-process-link-modal></valtimo-process-link-modal>\n\n<valtimo-confirmation-modal\n [showModalSubject$]=\"showWarningConfirmationModal$\"\n [titleTranslationKey]=\"'processManagement.warningConfirmation.title'\"\n [contentTranslationKey]=\"'processManagement.warningConfirmation.content'\"\n [confirmButtonTextTranslationKey]=\"'processManagement.warningConfirmation.confirm'\"\n [cancelButtonTextTranslationKey]=\"'interface.cancel'\"\n (confirmEvent)=\"onWarningConfirmationConfirm()\"\n (cancelEvent)=\"onWarningConfirmationCancel()\"\n></valtimo-confirmation-modal>\n\n<ng-container renderInPageHeader [fullWidth]=\"true\">\n <ng-template>\n <div\n class=\"page-header-actions\"\n *ngIf=\"{\n processDefinitionVersionsListItems: processDefinitionVersionsListItems$ | async,\n loading: loading$ | async,\n changesPending: changesPending$ | async,\n isReadOnlyProcess: isReadOnlyProcess$ | async,\n isSystemProcess: isSystemProcess$ | async,\n compactMode: compactMode$ | async,\n creatingNewProcess: creatingNewProcess$ | async,\n context: context$ | async,\n hasEditPermissions: hasEditPermissions$ | async,\n draft: draft$ | async,\n canInitializeDocument: canInitializeDocument$ | async,\n startableByUser: startableByUser$ | async,\n updatingProcessDefinitionCaseDefinition: updatingProcessDefinitionCaseDefinition$ | async,\n } as actionsObs\"\n >\n <div class=\"page-header-actions__left-container\">\n <cds-dropdown\n *ngIf=\"!actionsObs.creatingNewProcess && actionsObs?.context === 'independent'\"\n class=\"page-header-actions__version-dropdown\"\n (selected)=\"selectedVersionChange($event)\"\n [disabled]=\"\n actionsObs.loading ||\n (actionsObs.processDefinitionVersionsListItems || []).length === 0 ||\n (actionsObs.processDefinitionVersionsListItems || []).length === 1\n \"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n >\n <cds-dropdown-list\n [items]=\"actionsObs.processDefinitionVersionsListItems || []\"\n ></cds-dropdown-list>\n </cds-dropdown>\n\n <div\n class=\"page-header-actions__tags\"\n *ngIf=\"\n actionsObs.isReadOnlyProcess ||\n !actionsObs.hasEditPermissions ||\n actionsObs.isSystemProcess\n \"\n >\n <cds-tag\n *ngIf=\"actionsObs.isReadOnlyProcess || !actionsObs.hasEditPermissions\"\n type=\"blue\"\n >{{ 'processManagement.readOnly' | translate }}</cds-tag\n >\n\n <cds-tag *ngIf=\"actionsObs.isSystemProcess\" type=\"red\">{{\n 'processManagement.systemProcess' | translate\n }}</cds-tag>\n </div>\n\n <div class=\"page-header-actions__toggles\">\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processManagement.draftTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.draft' | translate\"\n [offText]=\"'processManagement.draft' | translate\"\n [checked]=\"actionsObs.draft\"\n [disabled]=\"actionsObs.loading || !actionsObs.hasEditPermissions\"\n (checkedChange)=\"onProcessToggleChange('draft', $event)\"\n [attr.data-test-id]=\"testIds.draftToggle\"\n ></cds-toggle>\n </cds-tooltip>\n\n @if (actionsObs.context === 'case') {\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processCaseConnection.processCreatesCaseTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.canInitializeDocument' | translate\"\n [offText]=\"'processManagement.canInitializeDocument' | translate\"\n [checked]=\"actionsObs.canInitializeDocument\"\n [disabled]=\"\n actionsObs.loading ||\n actionsObs.updatingProcessDefinitionCaseDefinition ||\n !actionsObs.hasEditPermissions\n \"\n (checkedChange)=\"onProcessToggleChange('canInitializeDocument', $event)\"\n [attr.data-test-id]=\"testIds.startsCaseToggle\"\n ></cds-toggle>\n </cds-tooltip>\n\n <cds-tooltip\n align=\"bottom-left\"\n [autoAlign]=\"true\"\n [description]=\"'processCaseConnection.startableWithinCaseTooltip' | translate\"\n >\n <cds-toggle\n size=\"sm\"\n [onText]=\"'processManagement.startableByUser' | translate\"\n [offText]=\"'processManagement.startableByUser' | translate\"\n [checked]=\"actionsObs.startableByUser\"\n [disabled]=\"\n actionsObs.loading ||\n actionsObs.updatingProcessDefinitionCaseDefinition ||\n !actionsObs.hasEditPermissions\n \"\n (checkedChange)=\"onProcessToggleChange('startableByUser', $event)\"\n [attr.data-test-id]=\"testIds.startableByUserToggle\"\n ></cds-toggle\n ></cds-tooltip>\n }\n </div>\n </div>\n\n <div class=\"page-header-actions__buttons\">\n <v-overflow-menu class=\"overflow-button\" placement=\"bottom-end\">\n <v-overflow-menu-trigger overflowTrigger></v-overflow-menu-trigger>\n <v-overflow-menu-option\n *ngIf=\"actionsObs.context !== 'case'\"\n [disabled]=\"actionsObs.loading\"\n [attr.data-test-id]=\"testIds.exportOption\"\n (selected)=\"export()\"\n >{{ 'interface.export' | translate }}\n </v-overflow-menu-option>\n\n <v-overflow-menu-option\n [disabled]=\"actionsObs.loading\"\n (selected)=\"exportBpmn(actionsObs.isReadOnlyProcess)\"\n >{{ 'processManagement.exportBpmn' | translate }}\n </v-overflow-menu-option>\n </v-overflow-menu>\n\n <button\n *ngIf=\"actionsObs.context === 'case'\"\n cdsButton=\"tertiary\"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n (click)=\"navigateBack(null)\"\n >\n {{ 'interface.back' | translate }}\n <svg class=\"cds--btn__icon\" cdsIcon=\"return\" size=\"16\"></svg>\n </button>\n\n <button\n cdsButton=\"secondary\"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n [disabled]=\"actionsObs.loading\"\n (click)=\"validateProcessDefinition(actionsObs.isReadOnlyProcess)\"\n >\n {{ 'processManagement.validate' | translate }}\n <svg class=\"cds--btn__icon\" cdsIcon=\"list--checked\" size=\"16\"></svg>\n </button>\n\n <button\n [disabled]=\"!actionsObs.changesPending\"\n cdsButton=\"primary\"\n (click)=\"\n !actionsObs.creatingNewProcess\n ? deployChanges(actionsObs.isReadOnlyProcess)\n : deployNewProcessDefinition()\n \"\n [size]=\"actionsObs.compactMode ? 'sm' : 'md'\"\n [attr.data-test-id]=\"testIds.deployButton\"\n >\n {{ 'processManagement.deploy' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"deploy\" size=\"16\"></svg>\n </button>\n </div>\n </div>\n </ng-template>\n</ng-container>\n", styles: [":host{display:flex;flex-direction:column;gap:24px}.bpmn__container{position:relative;background-color:var(--cds-layer);width:100%}.bpmn__modeler{width:100%;height:100%;flex-direction:row;padding:1px;box-sizing:border-box;outline:1px solid var(--cds-border-subtle);outline-offset:-1px}.bpmn__modeler ::ng-deep .djs-container>svg{outline:none!important}.bpmn__modeler-canvas{width:100%;position:relative}.bpmn__modeler-canvas .markers-visibility-toggle-wrapper{position:absolute;bottom:55px;right:15px;z-index:100}.bpmn__modeler-canvas .markers-visibility-toggle{display:flex;align-items:center;gap:6px;height:32px;padding:0 10px;border:none;border-radius:2px;background-color:var(--cds-layer);cursor:pointer;color:var(--cds-text-secondary);transition:background-color .15s,color .15s}.bpmn__modeler-canvas .markers-visibility-toggle:hover{background-color:var(--cds-layer-hover);color:var(--cds-text-primary)}.bpmn__modeler-canvas .markers-visibility-toggle:focus{outline:2px solid var(--cds-focus);outline-offset:-2px}.bpmn__modeler-canvas .markers-visibility-toggle__label{font-size:12px;white-space:nowrap}.bpmn__modeler-panel{width:481px;padding-left:1px;box-shadow:inset 1px 0 0 0 var(--cds-border-subtle);box-sizing:border-box}.bpmn__loading{width:100%;height:100%;display:flex;justify-content:center;align-items:center;background-color:var(--cds-background-selected)}.page-header-actions{display:flex;width:100%;justify-content:space-between;align-items:center;gap:16px}.page-header-actions__left-container{display:flex;gap:16px;align-items:center}.page-header-actions__tags{display:flex;gap:8px;align-items:center}.page-header-actions__version-dropdown{width:150px}.page-header-actions__toggles{display:flex;gap:16px;align-items:center}.page-header-actions__toggles ::ng-deep cds-toggle{display:inline-flex;align-items:center}.page-header-actions__toggles ::ng-deep .cds--toggle__label-text{display:none}.page-header-actions__buttons{display:flex;gap:16px;align-items:center;flex-shrink:0}.valtimo-process-builder__header{display:flex;justify-content:space-between}.valtimo-process-builder__actions>*:not(:last-child){margin-right:8px}.validation-errors-list{position:absolute;top:8px;right:8px;z-index:10;width:320px;max-height:250px;overflow-y:auto;border:1px solid var(--cds-border-subtle);background-color:var(--cds-layer);border-radius:4px;box-shadow:0 2px 6px #00000026}.validation-errors-list details[open]>summary .validation-errors-list__arrow{transform:rotate(90deg)}.validation-errors-list__header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;font-size:14px;font-weight:600;color:var(--cds-support-error, #da1e28);cursor:pointer;list-style:none;-webkit-user-select:none;user-select:none}.validation-errors-list__header::-webkit-details-marker{display:none}.validation-errors-list__arrow{display:inline-flex;width:16px;height:16px;fill:currentColor;transition:transform .15s ease;flex-shrink:0}.validation-errors-list__items{display:flex;flex-direction:column;border-top:1px solid var(--cds-border-subtle)}.validation-errors-list__item{display:flex;align-items:flex-start;gap:10px;padding:10px 16px;border:none;border-bottom:1px solid var(--cds-border-subtle);border-left:3px solid var(--cds-support-error, #da1e28);background-color:var(--cds-notification-error-background, #fff1f1);text-align:left;cursor:pointer;font-family:inherit}.validation-errors-list__item.warning{background-color:var(--cds-notification-warning-background, #fdf6dd);border-left-color:var(--cds-support-warning, #f1c21b)}.validation-errors-list__item:last-child{border-bottom:none}.validation-errors-list__item:hover{filter:brightness(.97)}.validation-errors-list__icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;min-width:18px;margin-top:1px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700;line-height:0}.validation-errors-list__icon.warning{background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616)}.validation-errors-list__details{display:flex;flex-direction:column;gap:2px}.validation-errors-list__element{font-size:13px;font-weight:600;color:var(--cds-text-primary)}.validation-errors-list__reason{font-size:13px;color:var(--cds-text-primary)}::ng-deep .highlight-overlay-error:not(.djs-connection) .djs-visual>:nth-child(1){stroke:var(--cds-support-error, #da1e28)!important}::ng-deep .highlight-overlay-warning:not(.djs-connection) .djs-visual>:nth-child(1){stroke:var(--cds-support-warning, #f1c21b)!important}::ng-deep .djs-overlay-validation-error{overflow:visible!important;pointer-events:all!important}::ng-deep .validation-error-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .validation-error-overlay__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:14px;font-weight:700;line-height:0}::ng-deep .validation-error-overlay__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-error, #da1e28);color:var(--cds-support-error, #da1e28);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .validation-error-overlay:hover ::ng-deep .validation-error-overlay__text,::ng-deep .validation-error-overlay--active ::ng-deep .validation-error-overlay__text{display:block}::ng-deep .validation-warning-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .validation-warning-overlay__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616);font-size:14px;font-weight:700;line-height:0}::ng-deep .validation-warning-overlay__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .validation-warning-overlay:hover ::ng-deep .validation-warning-overlay__text,::ng-deep .validation-warning-overlay--active ::ng-deep .validation-warning-overlay__text{display:block}::ng-deep .djs-overlay-activity-marker{overflow:visible!important;pointer-events:all!important}::ng-deep .activity-marker-overlay{display:flex;gap:2px}::ng-deep .activity-marker-badge{position:relative;cursor:pointer;pointer-events:all}::ng-deep .activity-marker-badge__icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;font-size:14px;font-weight:700;line-height:0}::ng-deep .activity-marker-badge__text{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .activity-marker-badge:hover ::ng-deep .activity-marker-badge__text,::ng-deep .activity-marker-badge--active ::ng-deep .activity-marker-badge__text{display:block}::ng-deep .activity-marker-badge--process-link ::ng-deep .activity-marker-badge__icon{background-color:var(--cds-support-info, #0043ce);color:var(--cds-text-on-color, #ffffff)}::ng-deep .activity-marker-badge--process-link ::ng-deep .activity-marker-badge__text{border:1px solid var(--cds-support-info, #0043ce);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff)}::ng-deep .activity-marker-badge--execution-listener ::ng-deep .activity-marker-badge__icon{background-color:var(--cds-purple-60, #8a3ffc);color:var(--cds-text-on-color, #ffffff)}::ng-deep .activity-marker-badge--execution-listener ::ng-deep .activity-marker-badge__text{border:1px solid var(--cds-purple-60, #8a3ffc);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff)}::ng-deep .activity-marker-badge--task-listener ::ng-deep .activity-marker-badge__icon{background-color:var(--cds-teal-50, #009d9a);color:var(--cds-text-on-color, #ffffff)}::ng-deep .activity-marker-badge--task-listener ::ng-deep .activity-marker-badge__text{border:1px solid var(--cds-teal-50, #009d9a);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff)}::ng-deep .validation-errors-panel{padding:8px 12px;display:flex;flex-direction:column;gap:8px}::ng-deep .validation-errors-panel__item{display:flex;align-items:flex-start;gap:8px;padding:8px 12px;background-color:var(--cds-notification-error-background, #fff1f1);border-left:3px solid var(--cds-support-error, #da1e28)}::ng-deep .validation-errors-panel__item.warning{background-color:var(--cds-notification-warning-background, #fdf6dd);border-left-color:var(--cds-support-warning, #f1c21b)}::ng-deep .validation-errors-panel__icon{display:flex;align-items:center;justify-content:center;width:18px;height:18px;min-width:18px;border-radius:50%;background-color:var(--cds-support-error, #da1e28);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700;line-height:0}::ng-deep .validation-errors-panel__icon.warning{background-color:var(--cds-support-warning, #f1c21b);color:var(--cds-text-primary, #161616)}::ng-deep .validation-errors-panel__reason{color:var(--cds-text-primary, #161616);font-size:13px;line-height:18px}::ng-deep .bio-properties-panel-entry.validation-error-field .bio-properties-panel-input,::ng-deep .bio-properties-panel-entry.validation-error-field .bio-properties-panel-textfield,::ng-deep .bio-properties-panel-entry.validation-error-field .bio-properties-panel-feel-editor-container{border:2px solid var(--cds-support-error, #da1e28)!important;background-color:var(--cds-notification-error-background, #fff1f1)!important}::ng-deep .expression-editor-param input.validation-error-param,::ng-deep input.expression-editor-input.validation-error-param,::ng-deep .expression-editor-technical input.validation-error-param,::ng-deep .expression-editor-technical textarea.validation-error-param{border:2px solid #da1e28!important;background-color:#fff1f1!important;border-color:#da1e28!important}::ng-deep .process-link-properties-panel{padding:8px 12px 16px;width:100%;display:flex;flex-direction:column;gap:16px}::ng-deep .process-link-properties-panel__buttons,::ng-deep .process-link-properties-panel__header{width:100%;display:flex;gap:16px}::ng-deep .process-link-properties-panel__header{align-items:flex-start;justify-content:space-between;border-bottom:1px solid var(--cds-border-subtle-00);padding-bottom:8px;padding-left:8px;padding-right:8px}::ng-deep .process-link-properties-panel__title{color:var(--cds-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;margin:auto 0}::ng-deep .process-link-properties-panel__title-container{display:flex;flex-direction:column;gap:4px}::ng-deep .process-link-properties-panel__title-container :last-child{color:var(--cds-text-helper);font-style:italic}::ng-deep .process-link-properties-panel .cds--tag{margin:0}::ng-deep .process-link-properties-panel .cds--btn{flex-shrink:1;width:100%;display:flex;align-items:center}::ng-deep .djs-overlay-autofilled-indicator{overflow:visible!important;pointer-events:all!important}::ng-deep .autofilled-indicator-overlay{position:relative;cursor:pointer;pointer-events:all}::ng-deep .autofilled-indicator-overlay .autofilled-indicator-icon{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background-color:var(--cds-support-info, #0043ce);color:var(--cds-text-on-color, #ffffff);font-size:14px;font-weight:700;line-height:0}::ng-deep .autofilled-indicator-overlay .autofilled-indicator-tooltip{display:none;position:absolute;bottom:100%;left:50%;transform:translate(-50%);margin-bottom:4px;border:1px solid var(--cds-support-info, #0043ce);color:var(--cds-text-primary, #161616);background-color:var(--cds-layer, #ffffff);padding:4px 8px;border-radius:2px;font-size:14px;white-space:nowrap;max-width:350px;overflow:hidden;text-overflow:ellipsis;z-index:10}::ng-deep .autofilled-indicator-overlay:hover .autofilled-indicator-tooltip{display:block}::ng-deep .autofilled-notification-panel{display:flex;align-items:center;gap:8px;padding:8px 12px;background-color:var(--cds-layer-02, #f4f4f4);border-left:3px solid var(--cds-support-info, #0043ce);margin-bottom:8px}::ng-deep .autofilled-notification-panel__icon{display:flex;align-items:center;justify-content:center;min-width:18px;height:18px;border-radius:50%;background-color:var(--cds-support-info, #0043ce);color:var(--cds-text-on-color, #ffffff);font-size:12px;font-weight:700}::ng-deep .autofilled-notification-panel__message{flex:1;font-size:12px;color:var(--cds-text-primary, #161616)}::ng-deep .autofilled-notification-panel__dismiss{background:none;border:none;cursor:pointer;padding:2px 6px;font-size:16px;color:var(--cds-text-secondary, #525252);line-height:1}::ng-deep .autofilled-notification-panel__dismiss:hover{color:var(--cds-text-primary, #161616)}\n/*!\n * Copyright 2015-2026 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"] }]
3103
+ }], ctorParameters: () => [{ type: i1$1.BreadcrumbService }, { type: i2$2.IconService }, { type: i3.NGXLogger }, { type: i1$1.ModalService }, { type: i2.GlobalNotificationService }, { type: i1$1.PageHeaderService }, { type: i1$1.PageTitleService }, { type: i5.ProcessLinkService }, { type: i5.ProcessLinkStateService }, { type: ProcessManagementEditorService }, { type: ProcessManagementService }, { type: i7.ProcessService }, { type: i8.ActivatedRoute }, { type: i8.Router }, { type: i9.TranslateService }, { type: i10.PluginTranslationService }, { type: i2.EditPermissionsService }, { type: i5.ProcessLinkBuildingBlockApiService }, { type: ProcessBeanService }], propDecorators: { modelerElementRef: [{
1955
3104
  type: ViewChild,
1956
3105
  args: ['modeler', { static: false }]
1957
3106
  }], modelerPanelElementRef: [{
@@ -2070,7 +3219,7 @@ class ProcessManagementListComponent {
2070
3219
  this.processToDelete$.next(process.processDefinition);
2071
3220
  this.showDeleteModal$.next(true);
2072
3221
  }
2073
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementListComponent, deps: [{ token: i2$2.IconService }, { token: i2$1.GlobalNotificationService }, { token: ProcessManagementService }, { token: ProcessManagementStateService }, { token: i9.TranslateService }, { token: i2$1.EnvironmentService }, { token: i8.ActivatedRoute }, { token: i2$1.EditPermissionsService }], target: i0.ɵɵFactoryTarget.Component }); }
3222
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementListComponent, deps: [{ token: i2$2.IconService }, { token: i2.GlobalNotificationService }, { token: ProcessManagementService }, { token: ProcessManagementStateService }, { token: i9.TranslateService }, { token: i2.EnvironmentService }, { token: i8.ActivatedRoute }, { token: i2.EditPermissionsService }], target: i0.ɵɵFactoryTarget.Component }); }
2074
3223
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: ProcessManagementListComponent, isStandalone: true, selector: "valtimo-process-management-list", outputs: { processSelected: "processSelected" }, ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<valtimo-carbon-list\n [actionItems]=\"ACTION_ITEMS\"\n [showActionItems]=\"hasEditPermissions$ | async\"\n [fields]=\"FIELDS\"\n [header]=\"false\"\n [items]=\"processDefinitions$ | async\"\n [loading]=\"loading$ | async\"\n (rowClicked)=\"editProcessDefinition($event)\"\n>\n <ng-container carbonToolbarContent>\n <button\n *ngIf=\"hasEditPermissions$ | async\"\n cdsButton=\"ghost\"\n iconOnly=\"true\"\n [attr.data-test-id]=\"testIds.uploadButton\"\n (click)=\"openModal()\"\n >\n <svg cdsIcon=\"upload\" size=\"16\"></svg>\n </button>\n\n <ng-container [ngTemplateOutlet]=\"createProcess\"></ng-container>\n </ng-container>\n\n <valtimo-no-results\n [action]=\"createProcess\"\n [title]=\"'processManagement.noResults.title' | translate\"\n [description]=\"'processManagement.noResults.' + $context() + 'Description' | translate\"\n ></valtimo-no-results>\n</valtimo-carbon-list>\n\n<valtimo-confirmation-modal\n confirmButtonTextTranslationKey=\"interface.delete\"\n confirmButtonType=\"danger\"\n contentTranslationKey=\"processManagement.deleteModal.content\"\n [outputOnConfirm]=\"processToDelete$ | async\"\n [showModalSubject$]=\"showDeleteModal$\"\n titleTranslationKey=\"processManagement.deleteModal.title\"\n (confirmEvent)=\"onDeleteConfirm($event)\"\n></valtimo-confirmation-modal>\n\n<ng-template #createProcess>\n <button *ngIf=\"hasEditPermissions$ | async\" cdsButton=\"primary\" [attr.data-test-id]=\"testIds.createProcessButton\" (click)=\"onCreateProcess()\">\n {{ 'processManagement.createProcess' | translate }}\n\n <svg cdsIcon=\"add\" size=\"16\" class=\"cds--btn__icon\"></svg>\n </button>\n</ng-template>\n", styles: ["/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2$2.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "ngmodule", type: CarbonListModule }, { kind: "component", type: i1$1.CarbonListComponent, selector: "valtimo-carbon-list", inputs: ["items", "fields", "tableTranslations", "paginatorConfig", "pagination", "loading", "skeletonRowCount", "actions", "actionItems", "showActionItems", "header", "hideColumnHeader", "initialSortState", "sortState", "isSearchable", "initialSearchValue", "searchDebounceMs", "invalidSearchFields", "searchFields", "enableSingleSelection", "lastColumnTemplate", "paginationIdentifier", "showSelectionColumn", "striped", "hideToolbar", "lockedTooltipTranslationKey", "movingRowsEnabled", "dragAndDrop", "dragAndDropDisabled", "expandedRowTemplate", "expandedRowKey", "trackByKey"], outputs: ["rowClicked", "paginationClicked", "paginationSet", "search", "sortChanged", "moveRow", "itemsReordered"] }, { kind: "component", type: i1$1.CarbonNoResultsComponent, selector: "valtimo-no-results", inputs: ["action", "description", "illustration", "title", "smallPadding", "collapseVertically", "alwaysRenderVertically"] }, { kind: "ngmodule", type: IconModule }, { kind: "directive", type: i2$2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i9.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ConfirmationModalModule }, { kind: "component", type: i1$1.ConfirmationModalComponent, selector: "valtimo-confirmation-modal", inputs: ["titleTranslationKey", "title", "content", "contentTranslationKey", "confirmButtonText", "confirmButtonTextTranslationKey", "confirmButtonType", "showOptionalButton", "optionalButtonText", "optionalButtonTextTranslationKey", "optionalButtonType", "cancelButtonText", "cancelButtonTextTranslationKey", "cancelButtonType", "showModalSubject$", "outputOnConfirm", "outputOnOptional", "spacerAfterCancelButton"], outputs: ["confirmEvent", "optionalEvent", "cancelEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2075
3224
  }
2076
3225
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementListComponent, decorators: [{
@@ -2084,7 +3233,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
2084
3233
  TranslateModule,
2085
3234
  ConfirmationModalModule,
2086
3235
  ], template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<valtimo-carbon-list\n [actionItems]=\"ACTION_ITEMS\"\n [showActionItems]=\"hasEditPermissions$ | async\"\n [fields]=\"FIELDS\"\n [header]=\"false\"\n [items]=\"processDefinitions$ | async\"\n [loading]=\"loading$ | async\"\n (rowClicked)=\"editProcessDefinition($event)\"\n>\n <ng-container carbonToolbarContent>\n <button\n *ngIf=\"hasEditPermissions$ | async\"\n cdsButton=\"ghost\"\n iconOnly=\"true\"\n [attr.data-test-id]=\"testIds.uploadButton\"\n (click)=\"openModal()\"\n >\n <svg cdsIcon=\"upload\" size=\"16\"></svg>\n </button>\n\n <ng-container [ngTemplateOutlet]=\"createProcess\"></ng-container>\n </ng-container>\n\n <valtimo-no-results\n [action]=\"createProcess\"\n [title]=\"'processManagement.noResults.title' | translate\"\n [description]=\"'processManagement.noResults.' + $context() + 'Description' | translate\"\n ></valtimo-no-results>\n</valtimo-carbon-list>\n\n<valtimo-confirmation-modal\n confirmButtonTextTranslationKey=\"interface.delete\"\n confirmButtonType=\"danger\"\n contentTranslationKey=\"processManagement.deleteModal.content\"\n [outputOnConfirm]=\"processToDelete$ | async\"\n [showModalSubject$]=\"showDeleteModal$\"\n titleTranslationKey=\"processManagement.deleteModal.title\"\n (confirmEvent)=\"onDeleteConfirm($event)\"\n></valtimo-confirmation-modal>\n\n<ng-template #createProcess>\n <button *ngIf=\"hasEditPermissions$ | async\" cdsButton=\"primary\" [attr.data-test-id]=\"testIds.createProcessButton\" (click)=\"onCreateProcess()\">\n {{ 'processManagement.createProcess' | translate }}\n\n <svg cdsIcon=\"add\" size=\"16\" class=\"cds--btn__icon\"></svg>\n </button>\n</ng-template>\n", styles: ["/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"] }]
2087
- }], ctorParameters: () => [{ type: i2$2.IconService }, { type: i2$1.GlobalNotificationService }, { type: ProcessManagementService }, { type: ProcessManagementStateService }, { type: i9.TranslateService }, { type: i2$1.EnvironmentService }, { type: i8.ActivatedRoute }, { type: i2$1.EditPermissionsService }], propDecorators: { processSelected: [{
3236
+ }], ctorParameters: () => [{ type: i2$2.IconService }, { type: i2.GlobalNotificationService }, { type: ProcessManagementService }, { type: ProcessManagementStateService }, { type: i9.TranslateService }, { type: i2.EnvironmentService }, { type: i8.ActivatedRoute }, { type: i2.EditPermissionsService }], propDecorators: { processSelected: [{
2088
3237
  type: Output
2089
3238
  }] } });
2090
3239
 
@@ -2103,45 +3252,205 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
2103
3252
  * See the License for the specific language governing permissions and
2104
3253
  * limitations under the License.
2105
3254
  */
3255
+ var UPLOAD_STEP;
3256
+ (function (UPLOAD_STEP) {
3257
+ UPLOAD_STEP["FILE_SELECT"] = "fileSelect";
3258
+ UPLOAD_STEP["REVIEW"] = "review";
3259
+ UPLOAD_STEP["SUMMARY"] = "summary";
3260
+ })(UPLOAD_STEP || (UPLOAD_STEP = {}));
2106
3261
  class ProcessManagementUploadComponent {
2107
- constructor(formBuilder, notificationService, processManagementService, processManagementStateService, processLinkService, translateService) {
3262
+ constructor(formBuilder, notificationService, processManagementService, processManagementStateService, processLinkService, translateService, changeDetectorRef) {
2108
3263
  this.formBuilder = formBuilder;
2109
3264
  this.notificationService = notificationService;
2110
3265
  this.processManagementService = processManagementService;
2111
3266
  this.processManagementStateService = processManagementStateService;
2112
3267
  this.processLinkService = processLinkService;
2113
3268
  this.translateService = translateService;
3269
+ this.changeDetectorRef = changeDetectorRef;
2114
3270
  this.modalOpen$ = this.processManagementStateService.openModal$;
2115
3271
  this.showReplaceConfirmationModal$ = new BehaviorSubject(false);
2116
3272
  this.replaceModalContent = '';
2117
3273
  this._conflictingProcessDefinitionId = null;
2118
- this.ACCEPTED_FILES = ['bpmn'];
3274
+ // Extensions need a leading dot: the file dialog only filters on valid accept tokens, and Carbon
3275
+ // matches a dropped file on its dot-prefixed extension
3276
+ this.ACCEPTED_FILES = ['.bpmn', '.zip'];
3277
+ this.UPLOAD_STEP = UPLOAD_STEP;
2119
3278
  this.form = this.formBuilder.group({
2120
3279
  file: this.formBuilder.control(new Set(), [Validators.required]),
2121
3280
  });
2122
- this.fileSelected$ = this.form.get('file')?.valueChanges.pipe(startWith(null), map$1(value => !!(value instanceof Set && value.size > 0)));
3281
+ // The current control value is read instead of the emitted one, so this also reports the selection
3282
+ // correctly when the footer is re-created after going back to the file select step
3283
+ this.fileSelected$ = this.form.get('file')?.valueChanges.pipe(startWith(null), map$1(() => {
3284
+ const value = this.form.get('file')?.value;
3285
+ return !!(value instanceof Set && value.size > 0);
3286
+ }));
3287
+ this.activeStep$ = new BehaviorSubject(UPLOAD_STEP.FILE_SELECT);
3288
+ this.preview$ = new BehaviorSubject(null);
3289
+ this.missingReferences$ = new BehaviorSubject([]);
3290
+ this.importing$ = new BehaviorSubject(false);
3291
+ /**
3292
+ * Leaving the file select step destroys cds-file-uploader, which empties the form control: every
3293
+ * cds-file emits (remove) from its own ngOnDestroy. So the selection is kept here to import it
3294
+ * afterwards, and to restore it when the user goes back.
3295
+ */
3296
+ this._selectedFile = null;
3297
+ this._selectedFileItems = null;
2123
3298
  }
2124
3299
  closeModal() {
2125
3300
  this.processManagementStateService.closeModal();
2126
3301
  setTimeout(() => {
2127
3302
  this.form.reset();
3303
+ this.activeStep$.next(UPLOAD_STEP.FILE_SELECT);
3304
+ this.preview$.next(null);
3305
+ this.missingReferences$.next([]);
3306
+ this.importing$.next(false);
3307
+ this._selectedFile = null;
3308
+ this._selectedFileItems = null;
2128
3309
  }, CARBON_CONSTANTS.modalAnimationMs);
2129
3310
  }
2130
3311
  uploadProcessBpmn() {
2131
- const bpmnFile = this.form.value?.file?.values()?.next()?.value?.file;
2132
- if (!bpmnFile)
3312
+ const file = this.form.value?.file?.values()?.next()?.value?.file;
3313
+ if (!file)
2133
3314
  return;
3315
+ // A package of an earlier selection must not be imported when another file is uploaded
3316
+ this._selectedFile = null;
3317
+ this._selectedFileItems = null;
3318
+ if (this.isZip(file)) {
3319
+ this.previewProcessPackage(file);
3320
+ return;
3321
+ }
2134
3322
  if (this.processManagementService.$context() === 'case') {
2135
- this.uploadForCase(bpmnFile);
3323
+ this.uploadForCase(file);
2136
3324
  }
2137
3325
  else {
2138
- this.uploadIndependent(bpmnFile);
3326
+ this.uploadIndependent(file);
3327
+ }
3328
+ }
3329
+ importProcessPackage() {
3330
+ const existingProcessDefinitionKeys = this.preview$.value?.existingProcessDefinitionKeys ?? [];
3331
+ // Ask before replacing, the same way uploading a single bpmn file does
3332
+ if (existingProcessDefinitionKeys.length > 0) {
3333
+ this.showReplaceConfirmation(this.translateService.instant('processManagement.upload.replaceContentWithDuplicates', {
3334
+ duplicates: existingProcessDefinitionKeys.join(', '),
3335
+ }));
3336
+ return;
3337
+ }
3338
+ this.executeImportProcessPackage();
3339
+ }
3340
+ showReplaceConfirmation(content) {
3341
+ this.replaceModalContent = content;
3342
+ // The content is bound from a plain field, so this OnPush component has to be checked again.
3343
+ // The bpmn flow sets it from an http error callback, which does not mark this view dirty itself.
3344
+ this.changeDetectorRef.markForCheck();
3345
+ this.showReplaceConfirmationModal$.next(true);
3346
+ }
3347
+ executeImportProcessPackage() {
3348
+ const file = this._selectedFile;
3349
+ if (!file)
3350
+ return;
3351
+ this.importing$.next(true);
3352
+ this.processManagementService
3353
+ .importProcessDefinition(this.toFormData(file), this._pluginConfigurationMapping?.getMappings())
3354
+ .pipe(take(1))
3355
+ .subscribe({
3356
+ next: result => {
3357
+ this.importing$.next(false);
3358
+ this.processManagementStateService.reloadDefinitions();
3359
+ if (result.missingReferences.length > 0) {
3360
+ // Keep the summary on screen: a toast disappears before it can be read
3361
+ this.missingReferences$.next(result.missingReferences);
3362
+ this.activeStep$.next(UPLOAD_STEP.SUMMARY);
3363
+ return;
3364
+ }
3365
+ this.notificationService.showNotification({
3366
+ type: 'success',
3367
+ title: this.translateService.instant('processManagement.upload.success'),
3368
+ });
3369
+ this.closeModal();
3370
+ },
3371
+ error: () => {
3372
+ this.importing$.next(false);
3373
+ this.notificationService.showNotification({
3374
+ type: 'error',
3375
+ title: this.translateService.instant('processManagement.upload.failure'),
3376
+ });
3377
+ },
3378
+ });
3379
+ }
3380
+ onBackClick() {
3381
+ this.activeStep$.next(UPLOAD_STEP.FILE_SELECT);
3382
+ // Restore the selection the file uploader dropped when it was destroyed
3383
+ if (this._selectedFileItems) {
3384
+ this.form.get('file')?.setValue(this._selectedFileItems);
2139
3385
  }
2140
3386
  }
3387
+ getMissingReferenceGroups(missingReferences) {
3388
+ return missingReferences.reduce((groups, missingReference) => {
3389
+ const group = groups.find(({ type }) => type === missingReference.type);
3390
+ if (group) {
3391
+ group.references = [...new Set([...group.references, missingReference.reference])];
3392
+ return groups;
3393
+ }
3394
+ return [...groups, { type: missingReference.type, references: [missingReference.reference] }];
3395
+ }, []);
3396
+ }
3397
+ getReplacedElementGroups(elementsToReplace) {
3398
+ return (elementsToReplace ?? []).reduce((groups, element) => {
3399
+ const group = groups.find(({ type }) => type === element.type);
3400
+ if (group) {
3401
+ group.keys = [...new Set([...group.keys, element.key])];
3402
+ return groups;
3403
+ }
3404
+ return [...groups, { type: element.type, keys: [element.key] }];
3405
+ }, []);
3406
+ }
3407
+ previewProcessPackage(file) {
3408
+ const fileItem = this.form.value?.file?.values()?.next()?.value;
3409
+ this.processManagementService
3410
+ .previewProcessDefinitionImport(this.toFormData(file))
3411
+ .pipe(take(1))
3412
+ .subscribe({
3413
+ next: preview => {
3414
+ this._selectedFile = file;
3415
+ this._selectedFileItems = this.form.value?.file ?? null;
3416
+ this.preview$.next(preview);
3417
+ this.missingReferences$.next(preview.missingReferences);
3418
+ // Nothing to review, so the package can be imported straight away. Elements that will be
3419
+ // replaced are shown in the review step first, so the replacement is a conscious choice.
3420
+ if (preview.pluginConfigurations.length === 0 &&
3421
+ preview.missingReferences.length === 0 &&
3422
+ preview.elementsToReplace.length === 0) {
3423
+ this.importProcessPackage();
3424
+ return;
3425
+ }
3426
+ this.activeStep$.next(UPLOAD_STEP.REVIEW);
3427
+ },
3428
+ error: () => {
3429
+ if (fileItem) {
3430
+ fileItem.invalid = true;
3431
+ fileItem.invalidTitle = this.translateService.instant('processManagement.upload.invalidZip.title');
3432
+ fileItem.invalidText = this.translateService.instant('processManagement.upload.invalidZip.text');
3433
+ }
3434
+ },
3435
+ });
3436
+ }
3437
+ isZip(file) {
3438
+ return file.name.toLowerCase().endsWith('.zip');
3439
+ }
3440
+ toFormData(file) {
3441
+ const formData = new FormData();
3442
+ formData.append('file', file, file.name);
3443
+ return formData;
3444
+ }
2141
3445
  confirmReplace() {
2142
3446
  const processDefinitionId = this._conflictingProcessDefinitionId;
2143
3447
  this.replaceModalContent = '';
2144
3448
  this._conflictingProcessDefinitionId = null;
3449
+ // A selected package is only set while importing a zip, which replaces through the import itself
3450
+ if (this._selectedFile) {
3451
+ this.executeImportProcessPackage();
3452
+ return;
3453
+ }
2145
3454
  if (!processDefinitionId) {
2146
3455
  this.notificationService.showNotification({
2147
3456
  type: 'error',
@@ -2192,11 +3501,9 @@ class ProcessManagementUploadComponent {
2192
3501
  error: (error) => {
2193
3502
  const isConflict = error instanceof HttpErrorResponse && error.status === 409;
2194
3503
  if (isConflict) {
2195
- const body = error
2196
- .error;
3504
+ const body = error.error;
2197
3505
  this._conflictingProcessDefinitionId = body?.processDefinitionId ?? null;
2198
- this.replaceModalContent = this.buildReplaceModalContent(body);
2199
- this.showReplaceConfirmationModal$.next(true);
3506
+ this.showReplaceConfirmation(this.buildReplaceModalContent(body));
2200
3507
  return;
2201
3508
  }
2202
3509
  this.notificationService.showNotification({
@@ -2221,11 +3528,9 @@ class ProcessManagementUploadComponent {
2221
3528
  error: (error) => {
2222
3529
  const isConflict = error instanceof HttpErrorResponse && error.status === 409;
2223
3530
  if (isConflict) {
2224
- const body = error
2225
- .error;
3531
+ const body = error.error;
2226
3532
  this._conflictingProcessDefinitionId = body?.processDefinitionId ?? null;
2227
- this.replaceModalContent = this.buildReplaceModalContent(body);
2228
- this.showReplaceConfirmationModal$.next(true);
3533
+ this.showReplaceConfirmation(this.buildReplaceModalContent(body));
2229
3534
  return;
2230
3535
  }
2231
3536
  this.notificationService.showNotification({
@@ -2244,8 +3549,8 @@ class ProcessManagementUploadComponent {
2244
3549
  }
2245
3550
  return this.translateService.instant('processManagement.upload.replaceContent');
2246
3551
  }
2247
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementUploadComponent, deps: [{ token: i1$2.FormBuilder }, { token: i2$1.GlobalNotificationService }, { token: ProcessManagementService }, { token: ProcessManagementStateService }, { token: i5.ProcessLinkService }, { token: i9.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
2248
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: ProcessManagementUploadComponent, isStandalone: true, selector: "valtimo-process-management-upload", ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<cds-modal valtimoCdsModal [open]=\"modalOpen$ | async\" size=\"sm\" (close)=\"closeModal()\">\n <cds-modal-header showCloseButton=\"true\" (closeSelect)=\"closeModal()\">\n <h3 cdsModalHeaderHeading>{{ 'processManagement.upload.modalTitle' | translate }}</h3>\n </cds-modal-header>\n\n <section cdsModalContent [cdsLayer]=\"1\" [formGroup]=\"form\">\n <cds-file-uploader\n [accept]=\"ACCEPTED_FILES\"\n [buttonText]=\"'processManagement.upload.buttonText' | translate\"\n [description]=\"'processManagement.upload.description' | translate\"\n [multiple]=\"false\"\n [title]=\"'processManagement.upload.title' | translate\"\n buttonType=\"primary\"\n formControlName=\"file\"\n >\n </cds-file-uploader>\n </section>\n\n <cds-modal-footer>\n <button cdsButton=\"secondary\" (click)=\"closeModal()\">\n {{ 'interface.cancel' | translate }}\n </button>\n\n <button\n cdsButton=\"primary\"\n [disabled]=\"(fileSelected$ | async) === false\"\n (click)=\"uploadProcessBpmn()\"\n >\n {{ 'interface.upload' | translate }}\n </button>\n </cds-modal-footer>\n</cds-modal>\n\n<valtimo-render-in-body>\n <valtimo-confirmation-modal\n confirmButtonTextTranslationKey=\"processManagement.upload.replaceConfirm\"\n confirmButtonType=\"danger\"\n cancelButtonTextTranslationKey=\"interface.cancel\"\n [content]=\"replaceModalContent\"\n [showModalSubject$]=\"showReplaceConfirmationModal$\"\n titleTranslationKey=\"processManagement.upload.replaceTitle\"\n (confirmEvent)=\"confirmReplace()\"\n (cancelEvent)=\"clearReplaceModal()\"\n ></valtimo-confirmation-modal>\n</valtimo-render-in-body>\n", styles: ["/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i9.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: FileUploaderModule }, { kind: "component", type: i2$2.FileUploader, selector: "cds-file-uploader, ibm-file-uploader", inputs: ["buttonText", "buttonType", "title", "description", "accept", "multiple", "skeleton", "size", "fileItemSize", "drop", "dropText", "fileUploaderId", "files", "disabled"], outputs: ["filesChange"] }, { kind: "ngmodule", type: ModalModule }, { kind: "component", type: i2$2.Modal, selector: "cds-modal, ibm-modal", inputs: ["size", "theme", "ariaLabel", "open", "trigger", "hasScrollingContent"], outputs: ["overlaySelected", "close"] }, { kind: "component", type: i2$2.ModalHeader, selector: "cds-modal-header, ibm-modal-header", inputs: ["theme", "closeLabel", "showCloseButton"], outputs: ["closeSelect"] }, { kind: "component", type: i2$2.ModalFooter, selector: "cds-modal-footer, ibm-modal-footer" }, { kind: "directive", type: i2$2.ModalContent, selector: "[cdsModalContent], [ibmModalContent]", inputs: ["hasForm"] }, { kind: "directive", type: i2$2.ModalHeaderHeading, selector: "[cdsModalHeaderHeading], [ibmModalHeaderHeading]" }, { kind: "ngmodule", type: LayerModule }, { kind: "directive", type: i2$2.LayerDirective, selector: "[cdsLayer], [ibmLayer]", inputs: ["ibmLayer", "cdsLayer"], exportAs: ["layer"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2$2.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "ngmodule", type: ConfirmationModalModule }, { kind: "component", type: i1$1.ConfirmationModalComponent, selector: "valtimo-confirmation-modal", inputs: ["titleTranslationKey", "title", "content", "contentTranslationKey", "confirmButtonText", "confirmButtonTextTranslationKey", "confirmButtonType", "showOptionalButton", "optionalButtonText", "optionalButtonTextTranslationKey", "optionalButtonType", "cancelButtonText", "cancelButtonTextTranslationKey", "cancelButtonType", "showModalSubject$", "outputOnConfirm", "outputOnOptional", "spacerAfterCancelButton"], outputs: ["confirmEvent", "optionalEvent", "cancelEvent"] }, { kind: "component", type: RenderInBodyComponent, selector: "valtimo-render-in-body" }, { kind: "directive", type: ValtimoCdsModalDirective, selector: "[valtimoCdsModal]", inputs: ["minContentHeight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3552
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementUploadComponent, deps: [{ token: i1$2.FormBuilder }, { token: i2.GlobalNotificationService }, { token: ProcessManagementService }, { token: ProcessManagementStateService }, { token: i5.ProcessLinkService }, { token: i9.TranslateService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3553
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: ProcessManagementUploadComponent, isStandalone: true, selector: "valtimo-process-management-upload", viewQueries: [{ propertyName: "_pluginConfigurationMapping", first: true, predicate: PluginConfigurationMappingComponent, descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<cds-modal valtimoCdsModal [open]=\"modalOpen$ | async\" size=\"sm\" (close)=\"closeModal()\">\n <cds-modal-header showCloseButton=\"true\" (closeSelect)=\"closeModal()\">\n <h3 cdsModalHeaderHeading>{{ 'processManagement.upload.modalTitle' | translate }}</h3>\n </cds-modal-header>\n\n <ng-container\n *ngIf=\"{\n activeStep: activeStep$ | async,\n preview: preview$ | async,\n missingReferences: missingReferences$ | async,\n importing: importing$ | async,\n } as obs\"\n >\n <section cdsModalContent [cdsLayer]=\"1\" [formGroup]=\"form\" [ngSwitch]=\"obs.activeStep\">\n <cds-file-uploader\n *ngSwitchCase=\"UPLOAD_STEP.FILE_SELECT\"\n [accept]=\"ACCEPTED_FILES\"\n [buttonText]=\"'processManagement.upload.buttonText' | translate\"\n [description]=\"'processManagement.upload.description' | translate\"\n [multiple]=\"false\"\n [title]=\"'processManagement.upload.title' | translate\"\n buttonType=\"primary\"\n formControlName=\"file\"\n >\n </cds-file-uploader>\n\n <div *ngSwitchCase=\"UPLOAD_STEP.REVIEW\" class=\"process-management-upload__review\">\n <ng-container *ngFor=\"let group of getMissingReferenceGroups(obs.missingReferences)\">\n <cds-inline-notification\n [notificationObj]=\"{\n type:\n group.type === 'SUB_PROCESS' || group.type === 'DECISION_DEFINITION'\n ? 'warning'\n : 'error',\n title:\n 'processManagement.upload.missingReference.' + group.type + '.title' | translate,\n message:\n ('processManagement.upload.missingReference.' + group.type + '.message'\n | translate) +\n ' ' +\n group.references.join(', '),\n showClose: false,\n lowContrast: true,\n }\"\n ></cds-inline-notification>\n </ng-container>\n\n <ng-container\n *ngFor=\"let group of getReplacedElementGroups(obs.preview?.elementsToReplace ?? [])\"\n >\n <cds-inline-notification\n [notificationObj]=\"{\n type: 'warning',\n title: 'processManagement.upload.willBeReplaced.' + group.type + '.title' | translate,\n message:\n ('processManagement.upload.willBeReplaced.' + group.type + '.message' | translate) +\n ' ' +\n group.keys.join(', '),\n showClose: false,\n lowContrast: true,\n }\"\n ></cds-inline-notification>\n </ng-container>\n\n <ng-container *ngIf=\"obs.preview?.pluginConfigurations?.length\">\n <p class=\"process-management-upload__description\">\n {{ 'processManagement.upload.pluginsDescription' | translate }}\n </p>\n\n <valtimo-plugin-configuration-mapping\n [pluginConfigurations]=\"obs.preview.pluginConfigurations\"\n ></valtimo-plugin-configuration-mapping>\n </ng-container>\n </div>\n\n <div *ngSwitchCase=\"UPLOAD_STEP.SUMMARY\" class=\"process-management-upload__review\">\n <cds-inline-notification\n [notificationObj]=\"{\n type: 'success',\n title: 'processManagement.upload.success' | translate,\n message: 'processManagement.upload.summaryDescription' | translate,\n showClose: false,\n lowContrast: true,\n }\"\n ></cds-inline-notification>\n\n <ng-container *ngFor=\"let group of getMissingReferenceGroups(obs.missingReferences)\">\n <cds-inline-notification\n [notificationObj]=\"{\n type: 'warning',\n title:\n 'processManagement.upload.missingReference.' + group.type + '.title' | translate,\n message:\n ('processManagement.upload.missingReference.' + group.type + '.message'\n | translate) +\n ' ' +\n group.references.join(', '),\n showClose: false,\n lowContrast: true,\n }\"\n ></cds-inline-notification>\n </ng-container>\n </div>\n </section>\n\n <cds-modal-footer>\n <ng-container *ngIf=\"obs.activeStep === UPLOAD_STEP.FILE_SELECT\">\n <button cdsButton=\"secondary\" (click)=\"closeModal()\">\n {{ 'interface.cancel' | translate }}\n </button>\n\n <button\n cdsButton=\"primary\"\n [disabled]=\"(fileSelected$ | async) === false || obs.importing\"\n (click)=\"uploadProcessBpmn()\"\n >\n {{ 'interface.upload' | translate }}\n </button>\n </ng-container>\n\n <ng-container *ngIf=\"obs.activeStep === UPLOAD_STEP.REVIEW\">\n <button cdsButton=\"secondary\" (click)=\"onBackClick()\">\n {{ 'interface.back' | translate }}\n </button>\n\n <button\n cdsButton=\"primary\"\n [disabled]=\"obs.preview?.canImport === false || obs.importing\"\n (click)=\"importProcessPackage()\"\n >\n {{ 'interface.upload' | translate }}\n </button>\n </ng-container>\n\n <button\n *ngIf=\"obs.activeStep === UPLOAD_STEP.SUMMARY\"\n cdsButton=\"primary\"\n (click)=\"closeModal()\"\n >\n {{ 'interface.close' | translate }}\n </button>\n </cds-modal-footer>\n </ng-container>\n</cds-modal>\n\n<valtimo-render-in-body>\n <valtimo-confirmation-modal\n confirmButtonTextTranslationKey=\"processManagement.upload.replaceConfirm\"\n confirmButtonType=\"danger\"\n cancelButtonTextTranslationKey=\"interface.cancel\"\n [content]=\"replaceModalContent\"\n [showModalSubject$]=\"showReplaceConfirmationModal$\"\n titleTranslationKey=\"processManagement.upload.replaceTitle\"\n (confirmEvent)=\"confirmReplace()\"\n (cancelEvent)=\"clearReplaceModal()\"\n ></valtimo-confirmation-modal>\n</valtimo-render-in-body>\n", styles: [".process-management-upload__review{display:flex;flex-direction:column;gap:16px}.process-management-upload__description{font-size:.875rem;line-height:1.25rem;color:var(--cds-text-secondary)}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i6.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i9.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: FileUploaderModule }, { kind: "component", type: i2$2.FileUploader, selector: "cds-file-uploader, ibm-file-uploader", inputs: ["buttonText", "buttonType", "title", "description", "accept", "multiple", "skeleton", "size", "fileItemSize", "drop", "dropText", "fileUploaderId", "files", "disabled"], outputs: ["filesChange"] }, { kind: "ngmodule", type: ModalModule }, { kind: "component", type: i2$2.Modal, selector: "cds-modal, ibm-modal", inputs: ["size", "theme", "ariaLabel", "open", "trigger", "hasScrollingContent"], outputs: ["overlaySelected", "close"] }, { kind: "component", type: i2$2.ModalHeader, selector: "cds-modal-header, ibm-modal-header", inputs: ["theme", "closeLabel", "showCloseButton"], outputs: ["closeSelect"] }, { kind: "component", type: i2$2.ModalFooter, selector: "cds-modal-footer, ibm-modal-footer" }, { kind: "directive", type: i2$2.ModalContent, selector: "[cdsModalContent], [ibmModalContent]", inputs: ["hasForm"] }, { kind: "directive", type: i2$2.ModalHeaderHeading, selector: "[cdsModalHeaderHeading], [ibmModalHeaderHeading]" }, { kind: "ngmodule", type: LayerModule }, { kind: "directive", type: i2$2.LayerDirective, selector: "[cdsLayer], [ibmLayer]", inputs: ["ibmLayer", "cdsLayer"], exportAs: ["layer"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2$2.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "ngmodule", type: ConfirmationModalModule }, { kind: "component", type: i1$1.ConfirmationModalComponent, selector: "valtimo-confirmation-modal", inputs: ["titleTranslationKey", "title", "content", "contentTranslationKey", "confirmButtonText", "confirmButtonTextTranslationKey", "confirmButtonType", "showOptionalButton", "optionalButtonText", "optionalButtonTextTranslationKey", "optionalButtonType", "cancelButtonText", "cancelButtonTextTranslationKey", "cancelButtonType", "showModalSubject$", "outputOnConfirm", "outputOnOptional", "spacerAfterCancelButton"], outputs: ["confirmEvent", "optionalEvent", "cancelEvent"] }, { kind: "component", type: RenderInBodyComponent, selector: "valtimo-render-in-body" }, { kind: "directive", type: ValtimoCdsModalDirective, selector: "[valtimoCdsModal]", inputs: ["minContentHeight"] }, { kind: "ngmodule", type: NotificationModule }, { kind: "component", type: i2$2.Notification, selector: "cds-notification, cds-inline-notification, ibm-notification, ibm-inline-notification", inputs: ["notificationObj"] }, { kind: "component", type: PluginConfigurationMappingComponent, selector: "valtimo-plugin-configuration-mapping", inputs: ["pluginConfigurations"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2249
3554
  }
2250
3555
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: ProcessManagementUploadComponent, decorators: [{
2251
3556
  type: Component,
@@ -2260,8 +3565,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
2260
3565
  ConfirmationModalModule,
2261
3566
  RenderInBodyComponent,
2262
3567
  ValtimoCdsModalDirective,
2263
- ], template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<cds-modal valtimoCdsModal [open]=\"modalOpen$ | async\" size=\"sm\" (close)=\"closeModal()\">\n <cds-modal-header showCloseButton=\"true\" (closeSelect)=\"closeModal()\">\n <h3 cdsModalHeaderHeading>{{ 'processManagement.upload.modalTitle' | translate }}</h3>\n </cds-modal-header>\n\n <section cdsModalContent [cdsLayer]=\"1\" [formGroup]=\"form\">\n <cds-file-uploader\n [accept]=\"ACCEPTED_FILES\"\n [buttonText]=\"'processManagement.upload.buttonText' | translate\"\n [description]=\"'processManagement.upload.description' | translate\"\n [multiple]=\"false\"\n [title]=\"'processManagement.upload.title' | translate\"\n buttonType=\"primary\"\n formControlName=\"file\"\n >\n </cds-file-uploader>\n </section>\n\n <cds-modal-footer>\n <button cdsButton=\"secondary\" (click)=\"closeModal()\">\n {{ 'interface.cancel' | translate }}\n </button>\n\n <button\n cdsButton=\"primary\"\n [disabled]=\"(fileSelected$ | async) === false\"\n (click)=\"uploadProcessBpmn()\"\n >\n {{ 'interface.upload' | translate }}\n </button>\n </cds-modal-footer>\n</cds-modal>\n\n<valtimo-render-in-body>\n <valtimo-confirmation-modal\n confirmButtonTextTranslationKey=\"processManagement.upload.replaceConfirm\"\n confirmButtonType=\"danger\"\n cancelButtonTextTranslationKey=\"interface.cancel\"\n [content]=\"replaceModalContent\"\n [showModalSubject$]=\"showReplaceConfirmationModal$\"\n titleTranslationKey=\"processManagement.upload.replaceTitle\"\n (confirmEvent)=\"confirmReplace()\"\n (cancelEvent)=\"clearReplaceModal()\"\n ></valtimo-confirmation-modal>\n</valtimo-render-in-body>\n", styles: ["/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"] }]
2264
- }], ctorParameters: () => [{ type: i1$2.FormBuilder }, { type: i2$1.GlobalNotificationService }, { type: ProcessManagementService }, { type: ProcessManagementStateService }, { type: i5.ProcessLinkService }, { type: i9.TranslateService }] });
3568
+ NotificationModule,
3569
+ PluginConfigurationMappingComponent,
3570
+ ], template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<cds-modal valtimoCdsModal [open]=\"modalOpen$ | async\" size=\"sm\" (close)=\"closeModal()\">\n <cds-modal-header showCloseButton=\"true\" (closeSelect)=\"closeModal()\">\n <h3 cdsModalHeaderHeading>{{ 'processManagement.upload.modalTitle' | translate }}</h3>\n </cds-modal-header>\n\n <ng-container\n *ngIf=\"{\n activeStep: activeStep$ | async,\n preview: preview$ | async,\n missingReferences: missingReferences$ | async,\n importing: importing$ | async,\n } as obs\"\n >\n <section cdsModalContent [cdsLayer]=\"1\" [formGroup]=\"form\" [ngSwitch]=\"obs.activeStep\">\n <cds-file-uploader\n *ngSwitchCase=\"UPLOAD_STEP.FILE_SELECT\"\n [accept]=\"ACCEPTED_FILES\"\n [buttonText]=\"'processManagement.upload.buttonText' | translate\"\n [description]=\"'processManagement.upload.description' | translate\"\n [multiple]=\"false\"\n [title]=\"'processManagement.upload.title' | translate\"\n buttonType=\"primary\"\n formControlName=\"file\"\n >\n </cds-file-uploader>\n\n <div *ngSwitchCase=\"UPLOAD_STEP.REVIEW\" class=\"process-management-upload__review\">\n <ng-container *ngFor=\"let group of getMissingReferenceGroups(obs.missingReferences)\">\n <cds-inline-notification\n [notificationObj]=\"{\n type:\n group.type === 'SUB_PROCESS' || group.type === 'DECISION_DEFINITION'\n ? 'warning'\n : 'error',\n title:\n 'processManagement.upload.missingReference.' + group.type + '.title' | translate,\n message:\n ('processManagement.upload.missingReference.' + group.type + '.message'\n | translate) +\n ' ' +\n group.references.join(', '),\n showClose: false,\n lowContrast: true,\n }\"\n ></cds-inline-notification>\n </ng-container>\n\n <ng-container\n *ngFor=\"let group of getReplacedElementGroups(obs.preview?.elementsToReplace ?? [])\"\n >\n <cds-inline-notification\n [notificationObj]=\"{\n type: 'warning',\n title: 'processManagement.upload.willBeReplaced.' + group.type + '.title' | translate,\n message:\n ('processManagement.upload.willBeReplaced.' + group.type + '.message' | translate) +\n ' ' +\n group.keys.join(', '),\n showClose: false,\n lowContrast: true,\n }\"\n ></cds-inline-notification>\n </ng-container>\n\n <ng-container *ngIf=\"obs.preview?.pluginConfigurations?.length\">\n <p class=\"process-management-upload__description\">\n {{ 'processManagement.upload.pluginsDescription' | translate }}\n </p>\n\n <valtimo-plugin-configuration-mapping\n [pluginConfigurations]=\"obs.preview.pluginConfigurations\"\n ></valtimo-plugin-configuration-mapping>\n </ng-container>\n </div>\n\n <div *ngSwitchCase=\"UPLOAD_STEP.SUMMARY\" class=\"process-management-upload__review\">\n <cds-inline-notification\n [notificationObj]=\"{\n type: 'success',\n title: 'processManagement.upload.success' | translate,\n message: 'processManagement.upload.summaryDescription' | translate,\n showClose: false,\n lowContrast: true,\n }\"\n ></cds-inline-notification>\n\n <ng-container *ngFor=\"let group of getMissingReferenceGroups(obs.missingReferences)\">\n <cds-inline-notification\n [notificationObj]=\"{\n type: 'warning',\n title:\n 'processManagement.upload.missingReference.' + group.type + '.title' | translate,\n message:\n ('processManagement.upload.missingReference.' + group.type + '.message'\n | translate) +\n ' ' +\n group.references.join(', '),\n showClose: false,\n lowContrast: true,\n }\"\n ></cds-inline-notification>\n </ng-container>\n </div>\n </section>\n\n <cds-modal-footer>\n <ng-container *ngIf=\"obs.activeStep === UPLOAD_STEP.FILE_SELECT\">\n <button cdsButton=\"secondary\" (click)=\"closeModal()\">\n {{ 'interface.cancel' | translate }}\n </button>\n\n <button\n cdsButton=\"primary\"\n [disabled]=\"(fileSelected$ | async) === false || obs.importing\"\n (click)=\"uploadProcessBpmn()\"\n >\n {{ 'interface.upload' | translate }}\n </button>\n </ng-container>\n\n <ng-container *ngIf=\"obs.activeStep === UPLOAD_STEP.REVIEW\">\n <button cdsButton=\"secondary\" (click)=\"onBackClick()\">\n {{ 'interface.back' | translate }}\n </button>\n\n <button\n cdsButton=\"primary\"\n [disabled]=\"obs.preview?.canImport === false || obs.importing\"\n (click)=\"importProcessPackage()\"\n >\n {{ 'interface.upload' | translate }}\n </button>\n </ng-container>\n\n <button\n *ngIf=\"obs.activeStep === UPLOAD_STEP.SUMMARY\"\n cdsButton=\"primary\"\n (click)=\"closeModal()\"\n >\n {{ 'interface.close' | translate }}\n </button>\n </cds-modal-footer>\n </ng-container>\n</cds-modal>\n\n<valtimo-render-in-body>\n <valtimo-confirmation-modal\n confirmButtonTextTranslationKey=\"processManagement.upload.replaceConfirm\"\n confirmButtonType=\"danger\"\n cancelButtonTextTranslationKey=\"interface.cancel\"\n [content]=\"replaceModalContent\"\n [showModalSubject$]=\"showReplaceConfirmationModal$\"\n titleTranslationKey=\"processManagement.upload.replaceTitle\"\n (confirmEvent)=\"confirmReplace()\"\n (cancelEvent)=\"clearReplaceModal()\"\n ></valtimo-confirmation-modal>\n</valtimo-render-in-body>\n", styles: [".process-management-upload__review{display:flex;flex-direction:column;gap:16px}.process-management-upload__description{font-size:.875rem;line-height:1.25rem;color:var(--cds-text-secondary)}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"] }]
3571
+ }], ctorParameters: () => [{ type: i1$2.FormBuilder }, { type: i2.GlobalNotificationService }, { type: ProcessManagementService }, { type: ProcessManagementStateService }, { type: i5.ProcessLinkService }, { type: i9.TranslateService }, { type: i0.ChangeDetectorRef }], propDecorators: { _pluginConfigurationMapping: [{
3572
+ type: ViewChild,
3573
+ args: [PluginConfigurationMappingComponent]
3574
+ }] } });
2265
3575
 
2266
3576
  /*
2267
3577
  * Copyright 2015-2025 Ritense BV, the Netherlands.