ngx-histaff-alpha 5.2.2 → 5.2.3

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 (50) hide show
  1. package/fesm2022/{ngx-histaff-alpha-core-form-design.component-DkGU3mLc.mjs → ngx-histaff-alpha-core-form-design.component-DUH4SkB7.mjs} +29 -11
  2. package/fesm2022/ngx-histaff-alpha-core-form-design.component-DUH4SkB7.mjs.map +1 -0
  3. package/fesm2022/ngx-histaff-alpha-core-workflow-consume.component-5bEZHFsi.mjs +64 -0
  4. package/fesm2022/ngx-histaff-alpha-core-workflow-consume.component-5bEZHFsi.mjs.map +1 -0
  5. package/fesm2022/ngx-histaff-alpha-live-form.component-Cl8EQ7M8.mjs +36 -0
  6. package/fesm2022/ngx-histaff-alpha-live-form.component-Cl8EQ7M8.mjs.map +1 -0
  7. package/fesm2022/{ngx-histaff-alpha-ngx-histaff-alpha-DG1v69l1.mjs → ngx-histaff-alpha-ngx-histaff-alpha-B6dYCMll.mjs} +278 -94
  8. package/fesm2022/ngx-histaff-alpha-ngx-histaff-alpha-B6dYCMll.mjs.map +1 -0
  9. package/fesm2022/{ngx-histaff-alpha-wf-basic-info.component-GP8my3qI.mjs → ngx-histaff-alpha-wf-basic-info.component-BL7fXjKU.mjs} +2 -2
  10. package/fesm2022/{ngx-histaff-alpha-wf-basic-info.component-GP8my3qI.mjs.map → ngx-histaff-alpha-wf-basic-info.component-BL7fXjKU.mjs.map} +1 -1
  11. package/fesm2022/{ngx-histaff-alpha-wf-form-assign.component-BuqyHWhW.mjs → ngx-histaff-alpha-wf-form-assign.component-BzsIRon0.mjs} +2 -2
  12. package/fesm2022/{ngx-histaff-alpha-wf-form-assign.component-BuqyHWhW.mjs.map → ngx-histaff-alpha-wf-form-assign.component-BzsIRon0.mjs.map} +1 -1
  13. package/fesm2022/ngx-histaff-alpha-wf-process-design.component-CQxxRCqC.mjs +1439 -0
  14. package/fesm2022/ngx-histaff-alpha-wf-process-design.component-CQxxRCqC.mjs.map +1 -0
  15. package/fesm2022/ngx-histaff-alpha.mjs +1 -1
  16. package/lib/app/libraries/core-button-group-vns/core-button-group-vns/EnumCoreButtonVNSCode.d.ts +2 -1
  17. package/lib/app/libraries/core-form/core-form/core-form.component.d.ts +2 -1
  18. package/lib/app/libraries/core-form-control-seeker/core-form-control-seeker/core-form-control-seeker.component.d.ts +3 -2
  19. package/lib/app/libraries/core-form-design/core-form-design.component.d.ts +2 -0
  20. package/lib/app/libraries/core-form-design/core-form-design.service.d.ts +2 -0
  21. package/lib/app/libraries/core-form-design/field-setting/mandatory-props/mandatory-props.component.d.ts +2 -0
  22. package/lib/app/libraries/core-form-design/form-metadata/form-metadata.component.d.ts +3 -1
  23. package/lib/app/libraries/core-form-design/live-form/live-form.component.d.ts +18 -0
  24. package/lib/app/libraries/core-header-params/enum-and-interfaces.d.ts +1 -1
  25. package/lib/app/libraries/core-radio-group/core-radio-group/core-radio-group.component.d.ts +8 -3
  26. package/lib/app/libraries/core-rule-tree/core-rule-tree.component.d.ts +1 -1
  27. package/lib/app/libraries/core-workflow-builder/constants/INITIAL_PROCESS_DEFINITION.d.ts +2 -0
  28. package/lib/app/libraries/core-workflow-builder/core-workflow-consume/core-workflow-consume.component.d.ts +9 -0
  29. package/lib/app/libraries/core-workflow-builder/core-workflow-list/core-workflow-list.component.d.ts +6 -4
  30. package/lib/app/libraries/core-workflow-builder/core-workflow.service.d.ts +13 -2
  31. package/lib/app/libraries/core-workflow-builder/enums/EnumActorSourceType.d.ts +10 -0
  32. package/lib/app/libraries/core-workflow-builder/interfaces/IActorAssignment.d.ts +7 -0
  33. package/lib/app/libraries/core-workflow-builder/interfaces/IStepConfig.d.ts +37 -4
  34. package/lib/app/libraries/core-workflow-builder/interfaces/IWfWorkflow.d.ts +3 -0
  35. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-node/wf-node.component.d.ts +3 -1
  36. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-process-design.component.d.ts +12 -3
  37. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-step-config-shell/wf-actor-selector/wf-actor-selector.component.d.ts +40 -0
  38. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-step-config-shell/wf-approver-config/wf-approver-config.component.d.ts +5 -0
  39. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-step-config-shell/wf-cc-config/wf-cc-config.component.d.ts +5 -0
  40. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-step-config-shell/wf-end-config/wf-end-config.component.d.ts +5 -0
  41. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-step-config-shell/wf-handler-config/wf-handler-config.component.d.ts +5 -0
  42. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-step-config-shell/wf-step-config-shell.component.d.ts +4 -5
  43. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-step-config-shell/wf-submit-config/wf-submit-config.component.d.ts +5 -0
  44. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-steps-preview/wf-steps-preview.component.d.ts +8 -0
  45. package/lib/app/libraries/core-workflow-builder/wf-process-design/wf-workflow-canvas.component.d.ts +32 -3
  46. package/package.json +1 -1
  47. package/fesm2022/ngx-histaff-alpha-core-form-design.component-DkGU3mLc.mjs.map +0 -1
  48. package/fesm2022/ngx-histaff-alpha-ngx-histaff-alpha-DG1v69l1.mjs.map +0 -1
  49. package/fesm2022/ngx-histaff-alpha-wf-process-design.component-D9Ba7Fkx.mjs +0 -1068
  50. package/fesm2022/ngx-histaff-alpha-wf-process-design.component-D9Ba7Fkx.mjs.map +0 -1
@@ -0,0 +1,1439 @@
1
+ import * as i0 from '@angular/core';
2
+ import { EventEmitter, inject, ElementRef, ViewChild, Output, Component, Renderer2, Input, input, ChangeDetectionStrategy, output, signal, computed, effect, ChangeDetectorRef, viewChild, Injectable, Directive, ViewChildren } from '@angular/core';
3
+ import { f as BaseComponent, w as CoreWorkflowService, H as EnumWorkflowStepType, M as MultiLanguageService, I as DomService, i as CoreDropdownComponent, p as CoreChecklistComponent, s as CoreDatePickerComponent, q as CoreFormControlSeekerComponent, v as CoreCurrencyInputComponent, j as TooltipDirective, m as TableCellPipe, T as TranslatePipe, a as EnumFormBaseContolType, l as EnumCoreFormControlSeekerSourceType, J as CoreParamControlComponent, t as CoreRadioGroupComponent, K as ApplicationHelpService, L as HotKeysDirective, b as EnumCoreButtonVNSCode, N as INITIAL_PROCESS_DEFINITION, c as CorePageHeaderComponent, F as FullscreenModalLoaderComponent } from './ngx-histaff-alpha-ngx-histaff-alpha-B6dYCMll.mjs';
4
+ import { AsyncPipe, NgTemplateOutlet, LowerCasePipe, NgStyle } from '@angular/common';
5
+ import * as i1 from '@angular/forms';
6
+ import { ReactiveFormsModule, FormGroup, FormControl, FormArray, FormsModule } from '@angular/forms';
7
+ import { BehaviorSubject, distinctUntilChanged } from 'rxjs';
8
+ import * as i1$1 from '@angular/router';
9
+
10
+ class WfInsertMenuComponent extends BaseComponent {
11
+ constructor(mls, renderer, domService) {
12
+ super(mls);
13
+ this.mls = mls;
14
+ this.renderer = renderer;
15
+ this.domService = domService;
16
+ this.insert = new EventEmitter();
17
+ this.coreWorkflowService = inject(CoreWorkflowService);
18
+ this.elRef = inject(ElementRef);
19
+ this.enumType = EnumWorkflowStepType;
20
+ }
21
+ onInsert(type) {
22
+ this.insert.emit({
23
+ type,
24
+ index: this.coreWorkflowService.insertContext$.value.index,
25
+ branchId: this.coreWorkflowService.insertContext$.value.branchId ?? 'root'
26
+ });
27
+ this.coreWorkflowService.insertContext$.next(null);
28
+ }
29
+ ngAfterViewInit() {
30
+ setTimeout(() => {
31
+ this.listenerFn = this.renderer.listen('window', 'click', (e) => {
32
+ e.stopPropagation();
33
+ if (this.container && !!!this.container.nativeElement.contains(e.target)) {
34
+ this.coreWorkflowService.insertContext$.next(null);
35
+ }
36
+ });
37
+ const rect = this.coreWorkflowService.insertAnchorPoint$.value;
38
+ const menuEl = this.elRef.nativeElement;
39
+ if (!rect)
40
+ return;
41
+ const menuHeight = menuEl.offsetHeight;
42
+ const zIndex = this.domService.getMaxZIndex() + 1;
43
+ menuEl.style.position = 'fixed';
44
+ menuEl.style.left = `${rect.right + 8}px`;
45
+ menuEl.style.top = `${rect.top}px`;
46
+ menuEl.style.zIndex = `${zIndex}`;
47
+ });
48
+ }
49
+ onCancelClicked() {
50
+ this.coreWorkflowService.insertContext$.next(null);
51
+ }
52
+ ngOnDestroy() {
53
+ this.subscriptions.forEach(x => x?.unsubscribe());
54
+ if (this.listenerFn)
55
+ this.listenerFn();
56
+ }
57
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfInsertMenuComponent, deps: [{ token: MultiLanguageService }, { token: i0.Renderer2 }, { token: DomService }], target: i0.ɵɵFactoryTarget.Component }); }
58
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: WfInsertMenuComponent, isStandalone: true, selector: "wf-insert-menu", outputs: { insert: "insert" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"wf-insert-menu-container\" #container>\r\n\r\n <div class=\"menu-item\" (click)=\"onInsert(enumType.Approval)\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\uD83D\uDFE7</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>Approver</div>\r\n </div>\r\n </div>\r\n <div class=\"menu-item\" (click)=\"onInsert(enumType.CC)\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\uD83D\uDFE6</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>CC</div>\r\n </div>\r\n </div>\r\n <div class=\"menu-item\" (click)=\"onInsert(enumType.Handle)\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\uD83D\uDFEA</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>Handler</div>\r\n </div>\r\n </div>\r\n <div class=\"menu-item\" (click)=\"onInsert(enumType.ConditionalBranch)\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\uD83C\uDF3F</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>Conditional Branch</div>\r\n </div>\r\n </div>\r\n <div class=\"menu-item\" (click)=\"onCancelClicked()\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\u274C</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>Cancel</div>\r\n </div>\r\n </div>\r\n</div>", styles: [".wf-insert-menu-container{width:220px;display:block;position:fixed;z-index:99;background:beige;padding:8px;box-shadow:.4rem 0 2rem #0000002e}.wf-insert-menu-container .menu-item{display:flex;align-items:center;justify-content:flex-start;cursor:pointer}.wf-insert-menu-container .menu-item .menu-item-icon-wrapper{width:24px;height:24px;display:flex}.wf-insert-menu-container .menu-item .menu-item-text{display:flex;align-items:center}.wf-insert-menu-container .insert-menu div{padding:6px 12px;cursor:pointer}.wf-insert-menu-container .insert-menu div:hover{background-color:#f3f4f6}.wf-insert-menu-container .cancel{color:red}.wf-insert-menu-overlay{position:absolute;top:0;left:0;z-index:99;pointer-events:none}\n"] }); }
59
+ }
60
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfInsertMenuComponent, decorators: [{
61
+ type: Component,
62
+ args: [{ selector: 'wf-insert-menu', imports: [], template: "<div class=\"wf-insert-menu-container\" #container>\r\n\r\n <div class=\"menu-item\" (click)=\"onInsert(enumType.Approval)\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\uD83D\uDFE7</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>Approver</div>\r\n </div>\r\n </div>\r\n <div class=\"menu-item\" (click)=\"onInsert(enumType.CC)\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\uD83D\uDFE6</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>CC</div>\r\n </div>\r\n </div>\r\n <div class=\"menu-item\" (click)=\"onInsert(enumType.Handle)\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\uD83D\uDFEA</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>Handler</div>\r\n </div>\r\n </div>\r\n <div class=\"menu-item\" (click)=\"onInsert(enumType.ConditionalBranch)\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\uD83C\uDF3F</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>Conditional Branch</div>\r\n </div>\r\n </div>\r\n <div class=\"menu-item\" (click)=\"onCancelClicked()\">\r\n <div class=\"menu-item-icon-wrapper\">\r\n <div class=\"menu-item-icon\">\u274C</div>\r\n </div>\r\n <div class=\"menu-item-text\">\r\n <div>Cancel</div>\r\n </div>\r\n </div>\r\n</div>", styles: [".wf-insert-menu-container{width:220px;display:block;position:fixed;z-index:99;background:beige;padding:8px;box-shadow:.4rem 0 2rem #0000002e}.wf-insert-menu-container .menu-item{display:flex;align-items:center;justify-content:flex-start;cursor:pointer}.wf-insert-menu-container .menu-item .menu-item-icon-wrapper{width:24px;height:24px;display:flex}.wf-insert-menu-container .menu-item .menu-item-text{display:flex;align-items:center}.wf-insert-menu-container .insert-menu div{padding:6px 12px;cursor:pointer}.wf-insert-menu-container .insert-menu div:hover{background-color:#f3f4f6}.wf-insert-menu-container .cancel{color:red}.wf-insert-menu-overlay{position:absolute;top:0;left:0;z-index:99;pointer-events:none}\n"] }]
63
+ }], ctorParameters: () => [{ type: MultiLanguageService }, { type: i0.Renderer2 }, { type: DomService }], propDecorators: { insert: [{
64
+ type: Output
65
+ }], container: [{
66
+ type: ViewChild,
67
+ args: ['container']
68
+ }] } });
69
+
70
+ class WfBottomVInsertComponent extends BaseComponent {
71
+ constructor() {
72
+ super(...arguments);
73
+ this.insertStep = new EventEmitter();
74
+ this.shouldShowInsert = false;
75
+ this.coreWorkflowService = inject(CoreWorkflowService);
76
+ this.el = inject(ElementRef);
77
+ this.renderer = inject(Renderer2);
78
+ this.observer = null;
79
+ }
80
+ ngOnInit() {
81
+ this.subscriptions.push(this.mls.lang$.subscribe(x => this.lang = x));
82
+ this.subscriptions.push(this.coreWorkflowService.insertContext$
83
+ .subscribe(ctx => {
84
+ this.shouldShowInsert = !!ctx &&
85
+ ctx.branchId === this.currentContext.branchId &&
86
+ ctx.index === this.currentContext.index;
87
+ }));
88
+ }
89
+ onShowInsert(e) {
90
+ const insertContext = {
91
+ branchId: this.currentContext.branchId,
92
+ index: this.currentContext.index
93
+ };
94
+ const triggerEl = e.currentTarget;
95
+ const rect = triggerEl.getBoundingClientRect();
96
+ this.coreWorkflowService.insertContext$.next(insertContext);
97
+ this.coreWorkflowService.insertAnchorPoint$.next(rect);
98
+ }
99
+ ngAfterViewInit() {
100
+ setTimeout(() => {
101
+ });
102
+ }
103
+ ngOnDestroy() {
104
+ this.subscriptions.forEach(x => x?.unsubscribe());
105
+ this.observer?.disconnect();
106
+ }
107
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfBottomVInsertComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
108
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: WfBottomVInsertComponent, isStandalone: true, selector: "wf-bottom-v-insert", inputs: { currentContext: "currentContext", currentStep: "currentStep" }, outputs: { insertStep: "insertStep" }, viewQueries: [{ propertyName: "plusContainer", first: true, predicate: ["plusContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"wf-bottom-v-insert-container\" \r\n [class.shorter]=\"(!!currentStep.isPseudo && !!currentStep.isInFallbackBranch!) || !!currentStep.config\"\r\n [class.insert-context]=\"(coreWorkflowService.insertContext$ | async)?.branchId === currentContext.branchId && (coreWorkflowService.insertContext$ | async)?.index === currentContext.index\"\r\n>\r\n <div class=\"vertical-line\"></div>\r\n\r\n <div class=\"plus-container\" #plusContainer>\r\n <button class=\"plus-btn\" (click)=\"onShowInsert($event)\">\uFF0B</button>\r\n </div>\r\n\r\n <div class=\"arrow-down-container\">\r\n <div class=\"arrow-down\"></div>\r\n </div>\r\n\r\n</div>", styles: [".wf-workflow-canvas-container{--standard-connector-height: 90px;--print-area-scale: 1;padding-top:50px;padding-bottom:50px;background-color:#f2f3f5;position:relative;overflow:auto}.wf-workflow-canvas-container .zoom-tools{display:block;position:absolute;left:15px;z-index:1}.wf-workflow-canvas-container .zoom-tools .tools-wrapper{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;background-color:#f9fafb;box-shadow:0 1px 3px #0000001a}.wf-workflow-canvas-container .zoom-tools .tools-wrapper>*{cursor:pointer}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn{background:none;border:none;padding:6px;cursor:pointer;transition:background-color .2s}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn:hover{background-color:#e5e7eb}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-label{background:none;border:none;padding:6px 8px;cursor:default}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .universe-icon{font-size:16px;display:inline-flex;align-items:center;justify-content:center}.wf-workflow-canvas-container .scroll-container{display:block;width:var(--width);height:var(--height);overflow-x:auto}.wf-workflow-canvas-container .canvas{display:flex;flex-direction:column;align-items:center;position:relative}.wf-workflow-canvas-container .canvas.is-dragging *{-webkit-user-select:none;user-select:none}.wf-workflow-canvas-container .print-area{transform:scale(var(--print-area-scale));transition:.2s linear}.wf-workflow-canvas-container .step{text-align:center;position:relative}.wf-workflow-canvas-container .canvas-top-tool{position:absolute;display:block;top:15px;left:15px;box-shadow:0 0 4px #0000000d}.wf-workflow-canvas-container .canvas-top-tool button{border-radius:0;height:30px;font-size:13px}.workflow-box{width:220px;min-height:85px;max-height:100px;padding:0 4px 4px;box-shadow:0 0 4px #0000000d}.workflow-box.submit,.workflow-box.end{background-color:#a9b4cd}.workflow-box.approval{background-color:#f80}.workflow-box.cc{background-color:#3370ff}.workflow-box.handle{background-color:#935af6}.connector{font-size:24px;color:#888}.plus-btn{font-size:18px;background:#fff;border:1px solid #ccc;border-radius:9999px;width:28px;height:28px;cursor:pointer}.insert-menu{background:#fff;border:1px solid #ddd;border-radius:6px;padding:8px;margin-top:6px;box-shadow:0 2px 8px #0000001a;display:flex;flex-direction:column;gap:6px;z-index:10}.insert-menu div{cursor:pointer;font-size:14px;padding:2px 6px}.insert-menu .cancel{color:red}.branch-column{position:relative}.branch-column .branch-column-inner{width:100%;display:flex;flex-direction:column;align-items:center}.wf-branch-group-container,.wf-branch-group-container .branch-group{position:relative}.wf-branch-group-container .branch-group .branch-column{display:table-cell;min-width:220px;vertical-align:top;padding:0 12px}.wf-branch-group-container .branch-group .branch-column .vertical-bridge-line{position:absolute;width:2px;background-color:#d9d9d9;z-index:2;pointer-events:none}.wf-branch-group-container .branch-group .horizontal-bridge-line{position:absolute;height:2px;background-color:#d9d9d9;pointer-events:none;z-index:1}.wf-branch-group-container:after{content:\"\";display:block;position:absolute;height:2px;width:calc(100% - 244px);left:122px;bottom:102px}.branch-title{font-weight:700;font-size:14px;margin-bottom:8px}.branch-group-header{display:flex;justify-content:center;margin:12px 0}.add-branch-btn{position:absolute;top:0;width:175px;left:calc(50% - 87.5px);z-index:2;background:#fff;color:#0f172a;border:1px solid #ccc;padding:4px 12px;border-radius:9999px;font-weight:500;cursor:pointer;box-shadow:0 2px 4px #0000000f;text-wrap:nowrap}.workflow-box.submit{background-color:#e0f7fa;border-left:4px solid #00bcd4}.workflow-box.end{background-color:#ede7f6;border-left:4px solid #673ab7}.box.special{font-style:italic;opacity:.9}.bottom-v-container{min-height:65px;width:220px}.wf-bottom-v-insert-container{position:relative;display:flex;flex-direction:column;align-items:center;height:var(--standard-connector-height);width:100%;margin:0}.wf-bottom-v-insert-container .vertical-line{position:absolute;top:0;height:100%;width:2px;background-color:#d9d9d9;z-index:0}.wf-bottom-v-insert-container .plus-container{display:block;position:absolute;border-radius:50%;top:calc(var(--standard-connector-height) / 2 - 16px)}.wf-bottom-v-insert-container .plus-btn{width:32px;height:32px;border-radius:50%;border:none;background:#fff;color:#3b82f6;font-size:20px;box-shadow:.4rem 0 2rem #0000002e;cursor:pointer;display:flex;align-items:center;justify-content:center}.wf-bottom-v-insert-container .plus-btn:hover{background:#f0f8ff;box-shadow:0 0 0 4px #3b82f633}.wf-bottom-v-insert-container.shorter{height:calc(var(--standard-connector-height) - 15px)}.wf-bottom-v-insert-container.shorter .plus-container{display:block;position:absolute;top:calc((var(--standard-connector-height) - 18px) / 2 - 16px)}.wf-bottom-v-insert-container.insert-context .plus-container{outline:#2eb795 solid 2px}.add-branch-inline{position:relative;height:35px;margin-bottom:calc(var(--standard-connector-height) - 17.5px)}.arrow-down-container{display:block;position:absolute;z-index:1;bottom:0}.arrow-down-container .arrow-down{margin-top:5px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:8px solid #d9d9d9}.branch-card-wrapper{position:relative}.branch-card-wrapper .arrow-down-container{top:-12px;left:calc(50% - 5px)}.wf-step-container .step-header{position:relative;display:flex;align-items:center;justify-content:space-between;height:43px;font-size:12px;border-bottom:1px solid #f6f6f7}.wf-step-container .step-header .input-wrapper{padding-top:4px}.wf-step-container .step-header .step-name-wrapper{display:flex;align-items:center;justify-content:flex-start;padding-right:8px}.wf-step-container .step-header .step-name-wrapper .step-name{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:140px;padding-left:4px}.wf-step-container .step-header .step-name-wrapper i{margin-left:2px}.wf-step-container .step-header .step-delete{color:gray;display:none}.wf-step-container .step-header .step-delete i{font-size:24px}.wf-step-container .step-header:hover .step-name-wrapper:after{content:\"\\e95a\";font-family:feather}.wf-step-container .step-header:hover .branch-priority{display:none}.wf-step-container .step-header:hover .step-delete,.wf-step-container .step-header.edit-mode{display:block}.wf-step-container .step-set-config{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;padding:7px 4px;font-size:14px;background-color:#fff;color:gray}.wf-step-container .step-set-config .step-subtext{width:100%;text-align:left}.wf-step-container .step-set-config .step-subtext.configurated{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container{background-color:#fff}.wf-step-container.wf-branch-card-container .branch-header{color:#2eb795;border-bottom:1px solid #f6f6f7}.wf-step-container.wf-branch-card-container .branch-header:before{content:\"\";display:block;position:absolute;height:var(--standard-connector-height);width:2px;background-color:#d9d9d9;left:50%;top:calc(var(--standard-connector-height) * -1)}.wf-step-container.wf-branch-card-container .branch-set-condition{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;color:#3e4759;padding:7px 4px;font-size:14px}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext{width:100%;text-align:left}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext.fallback{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header,.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-set-condition{color:gray}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header .branch-priority{padding-right:4px}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-priority{display:block}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-delete{display:none}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-name-wrapper:after{content:\"\"}.steps-preview{position:fixed;width:390px;height:100vh;background-color:#fff;top:0;left:-390px;overflow-y:auto;transition:left .2s ease-out}.steps-preview.shown{left:0}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }] }); }
109
+ }
110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfBottomVInsertComponent, decorators: [{
111
+ type: Component,
112
+ args: [{ selector: 'wf-bottom-v-insert', imports: [
113
+ AsyncPipe,
114
+ WfInsertMenuComponent
115
+ ], template: "<div class=\"wf-bottom-v-insert-container\" \r\n [class.shorter]=\"(!!currentStep.isPseudo && !!currentStep.isInFallbackBranch!) || !!currentStep.config\"\r\n [class.insert-context]=\"(coreWorkflowService.insertContext$ | async)?.branchId === currentContext.branchId && (coreWorkflowService.insertContext$ | async)?.index === currentContext.index\"\r\n>\r\n <div class=\"vertical-line\"></div>\r\n\r\n <div class=\"plus-container\" #plusContainer>\r\n <button class=\"plus-btn\" (click)=\"onShowInsert($event)\">\uFF0B</button>\r\n </div>\r\n\r\n <div class=\"arrow-down-container\">\r\n <div class=\"arrow-down\"></div>\r\n </div>\r\n\r\n</div>", styles: [".wf-workflow-canvas-container{--standard-connector-height: 90px;--print-area-scale: 1;padding-top:50px;padding-bottom:50px;background-color:#f2f3f5;position:relative;overflow:auto}.wf-workflow-canvas-container .zoom-tools{display:block;position:absolute;left:15px;z-index:1}.wf-workflow-canvas-container .zoom-tools .tools-wrapper{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;background-color:#f9fafb;box-shadow:0 1px 3px #0000001a}.wf-workflow-canvas-container .zoom-tools .tools-wrapper>*{cursor:pointer}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn{background:none;border:none;padding:6px;cursor:pointer;transition:background-color .2s}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn:hover{background-color:#e5e7eb}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-label{background:none;border:none;padding:6px 8px;cursor:default}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .universe-icon{font-size:16px;display:inline-flex;align-items:center;justify-content:center}.wf-workflow-canvas-container .scroll-container{display:block;width:var(--width);height:var(--height);overflow-x:auto}.wf-workflow-canvas-container .canvas{display:flex;flex-direction:column;align-items:center;position:relative}.wf-workflow-canvas-container .canvas.is-dragging *{-webkit-user-select:none;user-select:none}.wf-workflow-canvas-container .print-area{transform:scale(var(--print-area-scale));transition:.2s linear}.wf-workflow-canvas-container .step{text-align:center;position:relative}.wf-workflow-canvas-container .canvas-top-tool{position:absolute;display:block;top:15px;left:15px;box-shadow:0 0 4px #0000000d}.wf-workflow-canvas-container .canvas-top-tool button{border-radius:0;height:30px;font-size:13px}.workflow-box{width:220px;min-height:85px;max-height:100px;padding:0 4px 4px;box-shadow:0 0 4px #0000000d}.workflow-box.submit,.workflow-box.end{background-color:#a9b4cd}.workflow-box.approval{background-color:#f80}.workflow-box.cc{background-color:#3370ff}.workflow-box.handle{background-color:#935af6}.connector{font-size:24px;color:#888}.plus-btn{font-size:18px;background:#fff;border:1px solid #ccc;border-radius:9999px;width:28px;height:28px;cursor:pointer}.insert-menu{background:#fff;border:1px solid #ddd;border-radius:6px;padding:8px;margin-top:6px;box-shadow:0 2px 8px #0000001a;display:flex;flex-direction:column;gap:6px;z-index:10}.insert-menu div{cursor:pointer;font-size:14px;padding:2px 6px}.insert-menu .cancel{color:red}.branch-column{position:relative}.branch-column .branch-column-inner{width:100%;display:flex;flex-direction:column;align-items:center}.wf-branch-group-container,.wf-branch-group-container .branch-group{position:relative}.wf-branch-group-container .branch-group .branch-column{display:table-cell;min-width:220px;vertical-align:top;padding:0 12px}.wf-branch-group-container .branch-group .branch-column .vertical-bridge-line{position:absolute;width:2px;background-color:#d9d9d9;z-index:2;pointer-events:none}.wf-branch-group-container .branch-group .horizontal-bridge-line{position:absolute;height:2px;background-color:#d9d9d9;pointer-events:none;z-index:1}.wf-branch-group-container:after{content:\"\";display:block;position:absolute;height:2px;width:calc(100% - 244px);left:122px;bottom:102px}.branch-title{font-weight:700;font-size:14px;margin-bottom:8px}.branch-group-header{display:flex;justify-content:center;margin:12px 0}.add-branch-btn{position:absolute;top:0;width:175px;left:calc(50% - 87.5px);z-index:2;background:#fff;color:#0f172a;border:1px solid #ccc;padding:4px 12px;border-radius:9999px;font-weight:500;cursor:pointer;box-shadow:0 2px 4px #0000000f;text-wrap:nowrap}.workflow-box.submit{background-color:#e0f7fa;border-left:4px solid #00bcd4}.workflow-box.end{background-color:#ede7f6;border-left:4px solid #673ab7}.box.special{font-style:italic;opacity:.9}.bottom-v-container{min-height:65px;width:220px}.wf-bottom-v-insert-container{position:relative;display:flex;flex-direction:column;align-items:center;height:var(--standard-connector-height);width:100%;margin:0}.wf-bottom-v-insert-container .vertical-line{position:absolute;top:0;height:100%;width:2px;background-color:#d9d9d9;z-index:0}.wf-bottom-v-insert-container .plus-container{display:block;position:absolute;border-radius:50%;top:calc(var(--standard-connector-height) / 2 - 16px)}.wf-bottom-v-insert-container .plus-btn{width:32px;height:32px;border-radius:50%;border:none;background:#fff;color:#3b82f6;font-size:20px;box-shadow:.4rem 0 2rem #0000002e;cursor:pointer;display:flex;align-items:center;justify-content:center}.wf-bottom-v-insert-container .plus-btn:hover{background:#f0f8ff;box-shadow:0 0 0 4px #3b82f633}.wf-bottom-v-insert-container.shorter{height:calc(var(--standard-connector-height) - 15px)}.wf-bottom-v-insert-container.shorter .plus-container{display:block;position:absolute;top:calc((var(--standard-connector-height) - 18px) / 2 - 16px)}.wf-bottom-v-insert-container.insert-context .plus-container{outline:#2eb795 solid 2px}.add-branch-inline{position:relative;height:35px;margin-bottom:calc(var(--standard-connector-height) - 17.5px)}.arrow-down-container{display:block;position:absolute;z-index:1;bottom:0}.arrow-down-container .arrow-down{margin-top:5px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:8px solid #d9d9d9}.branch-card-wrapper{position:relative}.branch-card-wrapper .arrow-down-container{top:-12px;left:calc(50% - 5px)}.wf-step-container .step-header{position:relative;display:flex;align-items:center;justify-content:space-between;height:43px;font-size:12px;border-bottom:1px solid #f6f6f7}.wf-step-container .step-header .input-wrapper{padding-top:4px}.wf-step-container .step-header .step-name-wrapper{display:flex;align-items:center;justify-content:flex-start;padding-right:8px}.wf-step-container .step-header .step-name-wrapper .step-name{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:140px;padding-left:4px}.wf-step-container .step-header .step-name-wrapper i{margin-left:2px}.wf-step-container .step-header .step-delete{color:gray;display:none}.wf-step-container .step-header .step-delete i{font-size:24px}.wf-step-container .step-header:hover .step-name-wrapper:after{content:\"\\e95a\";font-family:feather}.wf-step-container .step-header:hover .branch-priority{display:none}.wf-step-container .step-header:hover .step-delete,.wf-step-container .step-header.edit-mode{display:block}.wf-step-container .step-set-config{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;padding:7px 4px;font-size:14px;background-color:#fff;color:gray}.wf-step-container .step-set-config .step-subtext{width:100%;text-align:left}.wf-step-container .step-set-config .step-subtext.configurated{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container{background-color:#fff}.wf-step-container.wf-branch-card-container .branch-header{color:#2eb795;border-bottom:1px solid #f6f6f7}.wf-step-container.wf-branch-card-container .branch-header:before{content:\"\";display:block;position:absolute;height:var(--standard-connector-height);width:2px;background-color:#d9d9d9;left:50%;top:calc(var(--standard-connector-height) * -1)}.wf-step-container.wf-branch-card-container .branch-set-condition{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;color:#3e4759;padding:7px 4px;font-size:14px}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext{width:100%;text-align:left}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext.fallback{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header,.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-set-condition{color:gray}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header .branch-priority{padding-right:4px}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-priority{display:block}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-delete{display:none}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-name-wrapper:after{content:\"\"}.steps-preview{position:fixed;width:390px;height:100vh;background-color:#fff;top:0;left:-390px;overflow-y:auto;transition:left .2s ease-out}.steps-preview.shown{left:0}\n"] }]
116
+ }], propDecorators: { currentContext: [{
117
+ type: Input,
118
+ args: [{ required: true }]
119
+ }], currentStep: [{
120
+ type: Input,
121
+ args: [{ required: true }]
122
+ }], insertStep: [{
123
+ type: Output
124
+ }], plusContainer: [{
125
+ type: ViewChild,
126
+ args: ['plusContainer']
127
+ }] } });
128
+
129
+ class CoreControlValueOnlyComponent {
130
+ constructor() {
131
+ this.$control = input.required();
132
+ this.$form = input.required();
133
+ this.$fieldName = input();
134
+ }
135
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CoreControlValueOnlyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
136
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: CoreControlValueOnlyComponent, isStandalone: true, selector: "core-control-value-only", inputs: { $control: { classPropertyName: "$control", publicName: "$control", isSignal: true, isRequired: true, transformFunction: null }, $form: { classPropertyName: "$form", publicName: "$form", isSignal: true, isRequired: true, transformFunction: null }, $fieldName: { classPropertyName: "$fieldName", publicName: "$fieldName", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"$form()\">\r\n @switch ($control().controlType) {\r\n @case ('TEXTBOX') {\r\n <input class=\"form-control\" [formControlName]=\"$fieldName() || $control().field\" [type]=\"$control().type || 'text'\"\r\n [placeholder]=\"$control().placeholder || ''\" [readonly]=\"$control().readonly\" />\r\n }\r\n @case ('CURRENCY') {\r\n <core-currency-input [formControlName]=\"$fieldName() || $control().field\"\r\n [placeholder]=\"$control().placeholder || ''\">\r\n </core-currency-input>\r\n }\r\n @case ('DROPDOWN') {\r\n @if ($control().dropdownOptions$) {\r\n <core-dropdown [formControlName]=\"$fieldName() || $control().field\" [options$]=\"$control().dropdownOptions$!\">\r\n </core-dropdown>\r\n }\r\n }\r\n @case ('CHECKLIST') {\r\n @if ($control().checklistOptions$) {\r\n <core-checklist [formControlName]=\"$fieldName() || $control().field\" [options$]=\"$control().checklistOptions$!\">\r\n </core-checklist>\r\n }\r\n }\r\n @case ('DATEPICKER') {\r\n <core-date-picker [formControlName]=\"$fieldName() || $control().field\" [rangeLimit]=\"$control().rangeLimit!\"\r\n [popupAlign]=\"$control().popupAlign!\" [placeholder]=\"$control().placeholder || ''\"\r\n [readonly]=\"$control().readonly!\">\r\n </core-date-picker>\r\n }\r\n @case ('SEEKER') {\r\n <core-form-control-seeker [formControlName]=\"$fieldName() || $control().field\"\r\n [seekerSourceType]=\"$control().seekerSourceType!\" [shownFrom]=\"$control().shownFrom!\"\r\n [boundFrom]=\"$control().boundFrom!\" [objectList$]=\"$control().objectList$!\">\r\n </core-form-control-seeker>\r\n }\r\n @default {\r\n <input class=\"form-control\" [formControlName]=\"$fieldName() || $control().field\" type=\"text\"\r\n [placeholder]=\"$control().placeholder || ''\" [readonly]=\"$control().readonly\" />\r\n }\r\n }\r\n</div>", styles: [":host{display:block}input.form-control,core-dropdown,core-checklist,core-date-picker,core-currency-input,core-form-control-seeker{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CoreDropdownComponent, selector: "core-dropdown", inputs: ["getByIdObject$", "paramMode", "shownFrom", "options$", "height", "placeholder", "loading", "warningDisable", "clearDisable", "fitHeightWithItemCount", "itemHeight"] }, { kind: "component", type: CoreChecklistComponent, selector: "core-checklist", inputs: ["paramMode", "getByIdObject$", "shownFrom", "options$", "height", "placeholder", "loading", "readonly", "disabled"] }, { kind: "component", type: CoreDatePickerComponent, selector: "core-date-picker", inputs: ["enableTimeZoneConverter", "showPlaceholder", "popupWidth", "popupXPadding", "popupAlign", "rangeLimit", "placeholder", "readonly", "disabled"] }, { kind: "component", type: CoreFormControlSeekerComponent, selector: "core-form-control-seeker", inputs: ["title", "showPageHeader", "preDefinedOuterParam$", "preDefinedOuterFilter$", "click$", "getByIdObject$", "getByIdApi", "paramMode", "multiMode", "objectList$", "useTheseColumns", "hideOrgTree", "excludedColumns", "excludeExistingList", "placeholder", "sourceSpaceHeight", "indirectBinding", "bindGridIdTo", "multiModeExtendedColumns", "multiModeExtendedSections", "editBufferData$", "multiModeTableHeight", "multiModeRowHeight", "seekerSourceType", "boundFrom", "shownFrom", "alsoBindTo", "seekerVerifyIgnore"], outputs: ["onDoubleClick"] }, { kind: "component", type: CoreCurrencyInputComponent, selector: "core-currency-input", inputs: ["currencySign", "placeholder"], outputs: ["onLeftFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
137
+ }
138
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CoreControlValueOnlyComponent, decorators: [{
139
+ type: Component,
140
+ args: [{ selector: 'core-control-value-only', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
141
+ ReactiveFormsModule,
142
+ CoreDropdownComponent,
143
+ CoreChecklistComponent,
144
+ CoreDatePickerComponent,
145
+ CoreFormControlSeekerComponent,
146
+ CoreCurrencyInputComponent
147
+ ], template: "<div [formGroup]=\"$form()\">\r\n @switch ($control().controlType) {\r\n @case ('TEXTBOX') {\r\n <input class=\"form-control\" [formControlName]=\"$fieldName() || $control().field\" [type]=\"$control().type || 'text'\"\r\n [placeholder]=\"$control().placeholder || ''\" [readonly]=\"$control().readonly\" />\r\n }\r\n @case ('CURRENCY') {\r\n <core-currency-input [formControlName]=\"$fieldName() || $control().field\"\r\n [placeholder]=\"$control().placeholder || ''\">\r\n </core-currency-input>\r\n }\r\n @case ('DROPDOWN') {\r\n @if ($control().dropdownOptions$) {\r\n <core-dropdown [formControlName]=\"$fieldName() || $control().field\" [options$]=\"$control().dropdownOptions$!\">\r\n </core-dropdown>\r\n }\r\n }\r\n @case ('CHECKLIST') {\r\n @if ($control().checklistOptions$) {\r\n <core-checklist [formControlName]=\"$fieldName() || $control().field\" [options$]=\"$control().checklistOptions$!\">\r\n </core-checklist>\r\n }\r\n }\r\n @case ('DATEPICKER') {\r\n <core-date-picker [formControlName]=\"$fieldName() || $control().field\" [rangeLimit]=\"$control().rangeLimit!\"\r\n [popupAlign]=\"$control().popupAlign!\" [placeholder]=\"$control().placeholder || ''\"\r\n [readonly]=\"$control().readonly!\">\r\n </core-date-picker>\r\n }\r\n @case ('SEEKER') {\r\n <core-form-control-seeker [formControlName]=\"$fieldName() || $control().field\"\r\n [seekerSourceType]=\"$control().seekerSourceType!\" [shownFrom]=\"$control().shownFrom!\"\r\n [boundFrom]=\"$control().boundFrom!\" [objectList$]=\"$control().objectList$!\">\r\n </core-form-control-seeker>\r\n }\r\n @default {\r\n <input class=\"form-control\" [formControlName]=\"$fieldName() || $control().field\" type=\"text\"\r\n [placeholder]=\"$control().placeholder || ''\" [readonly]=\"$control().readonly\" />\r\n }\r\n }\r\n</div>", styles: [":host{display:block}input.form-control,core-dropdown,core-checklist,core-date-picker,core-currency-input,core-form-control-seeker{width:100%}\n"] }]
148
+ }] });
149
+
150
+ var EnumCoreRuleTreeOparator;
151
+ (function (EnumCoreRuleTreeOparator) {
152
+ EnumCoreRuleTreeOparator["EQUAL"] = "EQUAL";
153
+ EnumCoreRuleTreeOparator["GREATER_THAN"] = "GREATER_THAN";
154
+ EnumCoreRuleTreeOparator["LESS_THAN"] = "LESS_THAN";
155
+ EnumCoreRuleTreeOparator["GREATER_OR_EQUAL_THAN"] = "GREATER_OR_EQUAL_THAN";
156
+ EnumCoreRuleTreeOparator["LESS_OR_EQUAL_THAN"] = "LESS_OR_EQUAL_THAN";
157
+ EnumCoreRuleTreeOparator["STARTS_WITH"] = "STARTS_WITH";
158
+ EnumCoreRuleTreeOparator["ENDS_WITH"] = "ENDS_WITH";
159
+ EnumCoreRuleTreeOparator["CONTAINS"] = "CONTAINS";
160
+ EnumCoreRuleTreeOparator["IN"] = "IN";
161
+ EnumCoreRuleTreeOparator["NOT_EQUAL"] = "NOT_EQUAL";
162
+ EnumCoreRuleTreeOparator["NOT_STARTS_WITH"] = "NOT_STARTS_WITH";
163
+ EnumCoreRuleTreeOparator["NOT_ENDS_WITH"] = "NOT_ENDS_WITH";
164
+ EnumCoreRuleTreeOparator["NOT_CONTAINS"] = "NOT_CONTAINS";
165
+ EnumCoreRuleTreeOparator["NOT_IN"] = "NOT_IN";
166
+ })(EnumCoreRuleTreeOparator || (EnumCoreRuleTreeOparator = {}));
167
+ class CoreRuleTreeComponent extends BaseComponent {
168
+ toggleCollapse(group) {
169
+ const current = this.collapsedGroups.get(group) || false;
170
+ this.collapsedGroups.set(group, !current);
171
+ }
172
+ isCollapsed(group) {
173
+ return this.collapsedGroups.get(group) || false;
174
+ }
175
+ field() {
176
+ return new FormGroup({
177
+ name: new FormControl(null),
178
+ value: new FormControl(null),
179
+ relationalOperator: new FormControl('EQUAL')
180
+ });
181
+ }
182
+ filter() {
183
+ return new FormGroup({
184
+ logicalOperator: new FormControl('AND'),
185
+ filters: new FormArray([])
186
+ });
187
+ }
188
+ constructor(mls, cdr) {
189
+ super(mls);
190
+ this.mls = mls;
191
+ this.cdr = cdr;
192
+ // Inputs
193
+ this.$totalCols = input([]);
194
+ this.$mainForm = input(new FormGroup({
195
+ logicalOperator: new FormControl('AND')
196
+ }));
197
+ this.$filterStringInput = input();
198
+ this.$expressionInput = input();
199
+ // Outputs
200
+ this.$jsonEmitter = output();
201
+ this.$expressionEmitter = output();
202
+ // Internal signals
203
+ this.$filterString = signal('()');
204
+ this.$filterFormJsonString = signal('{}');
205
+ this.$formValue = signal(null); // Manual form value signal
206
+ this.$rawValue = computed(() => JSON.stringify(this.$mainForm().getRawValue(), null, 2));
207
+ // Track collapsed groups manually
208
+ this.collapsedGroups = new WeakMap();
209
+ this.operatorFriendlyMap = {
210
+ [EnumCoreRuleTreeOparator.EQUAL]: 'Equals (=)',
211
+ [EnumCoreRuleTreeOparator.NOT_EQUAL]: 'Does not equal (≠)',
212
+ [EnumCoreRuleTreeOparator.STARTS_WITH]: 'Starts with (→)',
213
+ [EnumCoreRuleTreeOparator.ENDS_WITH]: 'Ends with (←)',
214
+ [EnumCoreRuleTreeOparator.CONTAINS]: 'Contains (∈)',
215
+ [EnumCoreRuleTreeOparator.NOT_STARTS_WITH]: 'Does NOT start with (↛)',
216
+ [EnumCoreRuleTreeOparator.NOT_ENDS_WITH]: 'Does NOT end with (↚)',
217
+ [EnumCoreRuleTreeOparator.NOT_CONTAINS]: 'Does NOT contain (∉)',
218
+ [EnumCoreRuleTreeOparator.GREATER_THAN]: 'Greater than (>)',
219
+ [EnumCoreRuleTreeOparator.LESS_THAN]: 'Less than (<)',
220
+ [EnumCoreRuleTreeOparator.GREATER_OR_EQUAL_THAN]: 'Greater or equal (≥)',
221
+ [EnumCoreRuleTreeOparator.LESS_OR_EQUAL_THAN]: 'Less or equal (≤)',
222
+ [EnumCoreRuleTreeOparator.IN]: 'In list (∈)',
223
+ [EnumCoreRuleTreeOparator.NOT_IN]: 'Not in list (∉)',
224
+ };
225
+ this.relationalOperator = Object.values(EnumCoreRuleTreeOparator);
226
+ effect((onCleanup) => {
227
+ const form = this.$mainForm();
228
+ if (!!form) {
229
+ const sub = form.valueChanges.subscribe(value => {
230
+ this.$formValue.set(value);
231
+ //this.cdr.markForCheck();
232
+ });
233
+ onCleanup(() => sub.unsubscribe()); // Unsubscribe if form changes
234
+ }
235
+ });
236
+ // ➡️ Separate reaction effect for serialization
237
+ effect(() => {
238
+ const formValue = this.$formValue();
239
+ if (!formValue)
240
+ return;
241
+ const cleaned = this.cleanEmptyFilters(formValue); // 👈 apply cleaning here
242
+ const expr = this.getFilterString(cleaned);
243
+ const json = JSON.stringify(cleaned, null, 2);
244
+ this.$filterString.set(expr);
245
+ this.$filterFormJsonString.set(json.trim());
246
+ this.$expressionEmitter.emit(expr);
247
+ this.$jsonEmitter.emit(json);
248
+ });
249
+ // Initialize immediately based on initial form
250
+ this.$formValue.set(this.$mainForm().getRawValue());
251
+ }
252
+ cleanEmptyFilters(node) {
253
+ if (!node || typeof node !== 'object')
254
+ return node;
255
+ // If it's a group with filters
256
+ if (Array.isArray(node.filters)) {
257
+ node.filters = node.filters
258
+ .map(f => this.cleanEmptyFilters(f))
259
+ .filter(f => f !== null); // optional: skip nulls
260
+ if (node.filters.length === 0) {
261
+ delete node.filters; // ← Clean!
262
+ }
263
+ }
264
+ return node;
265
+ }
266
+ getFilterString(filter) {
267
+ if (!filter || Object.keys(filter).length === 0)
268
+ return '()';
269
+ let str = '(';
270
+ for (let i = 0; i < filter.filters?.length; i++) {
271
+ if (i > 0)
272
+ str += ` ${filter.logicalOperator} `;
273
+ const f = filter.filters[i];
274
+ if (f?.filters?.length) {
275
+ str += this.getFilterString(f);
276
+ }
277
+ else {
278
+ const rawVal = f.value;
279
+ let formattedVal = rawVal;
280
+ if (rawVal instanceof Date) {
281
+ formattedVal = this.formatDateToYMD(rawVal);
282
+ }
283
+ else if (typeof rawVal === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(rawVal)) {
284
+ // parse ISO string if needed
285
+ try {
286
+ formattedVal = this.formatDateToYMD(new Date(rawVal));
287
+ }
288
+ catch { }
289
+ }
290
+ str += `${f.name} ${f.relationalOperator} '${formattedVal}'`;
291
+ }
292
+ }
293
+ return str + ')';
294
+ }
295
+ addGroup(groupForm) {
296
+ const filtersArray = groupForm.get('filters');
297
+ if (filtersArray) {
298
+ const newGroup = this.filter(); // 🛠 use your existing filter() factory method
299
+ filtersArray.push(newGroup);
300
+ }
301
+ }
302
+ removeGroup(groupForm, index) {
303
+ const filtersArray = groupForm.get('filters');
304
+ if (filtersArray && filtersArray.length > index) {
305
+ setTimeout(() => filtersArray.removeAt(index));
306
+ }
307
+ }
308
+ addCondition(groupForm) {
309
+ const filtersArray = groupForm.get('filters');
310
+ if (filtersArray) {
311
+ const newCondition = this.field();
312
+ filtersArray.push(newCondition);
313
+ }
314
+ }
315
+ removeCondition(filterGroup, index) {
316
+ const filtersArray = filterGroup.get('filters');
317
+ if (filtersArray && filtersArray.length > index) {
318
+ setTimeout(() => filtersArray.removeAt(index));
319
+ }
320
+ }
321
+ resolveControl(fieldName) {
322
+ const cols = this.$totalCols();
323
+ if (!cols || !fieldName)
324
+ return undefined;
325
+ const tryfind = cols.find(x => x.field === fieldName);
326
+ if (!!tryfind) {
327
+ }
328
+ return tryfind;
329
+ }
330
+ safeStringify(obj) {
331
+ const seen = new WeakSet();
332
+ return JSON.stringify(obj, (key, value) => {
333
+ if (typeof value === 'object' && value !== null) {
334
+ if (seen.has(value)) {
335
+ return undefined; // ✋ Skip circular reference
336
+ }
337
+ seen.add(value);
338
+ }
339
+ return value;
340
+ });
341
+ }
342
+ formatDateToYMD(date) {
343
+ const yyyy = date.getFullYear();
344
+ const mm = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-based
345
+ const dd = String(date.getDate()).padStart(2, '0');
346
+ return `${yyyy}-${mm}-${dd}`;
347
+ }
348
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CoreRuleTreeComponent, deps: [{ token: MultiLanguageService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
349
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: CoreRuleTreeComponent, isStandalone: true, selector: "core-rule-tree", inputs: { $totalCols: { classPropertyName: "$totalCols", publicName: "$totalCols", isSignal: true, isRequired: false, transformFunction: null }, $mainForm: { classPropertyName: "$mainForm", publicName: "$mainForm", isSignal: true, isRequired: false, transformFunction: null }, $filterStringInput: { classPropertyName: "$filterStringInput", publicName: "$filterStringInput", isSignal: true, isRequired: false, transformFunction: null }, $expressionInput: { classPropertyName: "$expressionInput", publicName: "$expressionInput", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { $jsonEmitter: "$jsonEmitter", $expressionEmitter: "$expressionEmitter" }, usesInheritance: true, ngImport: i0, template: "<div class=\"core-rule-tree-container\">\r\n\r\n <form [formGroup]=\"$mainForm()\" (ngSubmit)=\"null\" class=\"core-rule-tree-form\">\r\n\r\n <!-- Top Controls -->\r\n <div class=\"top-bar\">\r\n <div class=\"expression-box\">\r\n Expression = {{ $filterString() || '()' }}\r\n </div>\r\n \r\n <!-- <div class=\"button-group\">\r\n <button type=\"button\" class=\"btn btn-success btn-sm feather-file-plus\"\r\n (click)=\"addCondition($mainForm())\"\r\n [appTooltip]=\"'Add Condition'\">\r\n </button>\r\n <button type=\"button\" class=\"btn btn-success btn-sm feather-folder-plus\"\r\n (click)=\"addGroup($mainForm())\"\r\n [appTooltip]=\"'Add Group'\">\r\n </button>\r\n </div> -->\r\n </div>\r\n \r\n <!-- Query Builder -->\r\n <div class=\"query-builder\">\r\n <ng-template #queryTemplate let-filter=\"filter\" let-groupToRemove=\"groupToRemove\">\r\n \r\n <div class=\"group-card\">\r\n\r\n <div class=\"group-header\">\r\n\r\n <!-- Logical Operator -->\r\n <div class=\"logical-operator\">\r\n\r\n @if (filter === $mainForm()) {\r\n <div class=\"logical-operator-label\">\r\n AND\r\n </div>\r\n } @else {\r\n <select class=\"form-control pointer\" [formControl]=\"filter.get('logicalOperator')\">\r\n <option value=\"AND\">AND</option>\r\n <option value=\"OR\">OR</option>\r\n </select>\r\n }\r\n\r\n <!-- Collapse/Expand Button -->\r\n @if (!!filter.value.filters?.length) {\r\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\"\r\n (click)=\"toggleCollapse(filter)\"\r\n [appTooltip]=\"isCollapsed(filter) ? 'Expand Group' : 'Collapse Group'\">\r\n <i class=\"feather\" [class.feather-plus]=\"isCollapsed(filter)\" [class.feather-minus]=\"!isCollapsed(filter)\"></i>\r\n </button>\r\n }\r\n <div class=\"local-action-buttons\">\r\n <button type=\"button\" class=\"btn btn-xs btn-success feather-file-plus\"\r\n (click)=\"addCondition(filter)\"\r\n [appTooltip]=\"'Add Condition to this Group'\" [position]=\"'top'\">\r\n </button>\r\n <button type=\"button\" class=\"btn btn-xs btn-success feather-folder-plus\"\r\n (click)=\"addGroup(filter)\"\r\n [appTooltip]=\"'Add Subgroup to this Group'\" [position]=\"'top'\">\r\n </button>\r\n @if (!!groupToRemove) {\r\n <button type=\"button\" class=\"btn btn-xs btn-danger feather-trash\"\r\n (click)=\"removeGroup(groupToRemove.group, groupToRemove.index)\"\r\n [appTooltip]=\"'Remove Group'\" [position]=\"'top'\">\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"group-content\">\r\n \r\n <!-- Filter List (only shown when expanded) -->\r\n\r\n @if (!isCollapsed(filter)) {\r\n\r\n @if (!!filter.value.filters?.length) {\r\n <div class=\"filter-list\" formArrayName=\"filters\">\r\n @for (childFilter of filter.get('filters').controls; track $index; let idx = $index) {\r\n <div class=\"filter-row\" [formGroup]=\"childFilter\">\r\n \r\n @if (!childFilter.value.logicalOperator) {\r\n <div class=\"field-cell\">\r\n <select class=\"form-control\" formControlName=\"name\">\r\n @for (col of $totalCols(); track $index) {\r\n <option [value]=\"col.field\">\r\n {{ col.label || col.field }}\r\n </option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"operator-cell\">\r\n <select class=\"form-control\" formControlName=\"relationalOperator\">\r\n @for (op of relationalOperator; track $index) {\r\n <option [value]=\"op\">\r\n {{ operatorFriendlyMap[op] || op }}\r\n </option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"value-cell\">\r\n <!-- <input class=\"form-control\" formControlName=\"value\" /> -->\r\n <core-control-value-only\r\n [$control]=\"resolveControl(childFilter.value.name)!\"\r\n [$form]=\"childFilter\"\r\n [$fieldName]=\"'value'\"\r\n >\r\n </core-control-value-only>\r\n </div>\r\n <div class=\"action-cell\">\r\n <button type=\"button\" class=\"btn btn-danger btn-sm feather-trash-2\"\r\n (click)=\"removeCondition(filter, idx)\"\r\n [appTooltip]=\"'Remove Condition'\">\r\n </button>\r\n </div>\r\n } @else {\r\n <!-- Recursive nested groups -->\r\n <ng-container *ngTemplateOutlet=\"queryTemplate; context: { filter: childFilter, groupToRemove: { group: filter, index: idx } }\"></ng-container>\r\n }\r\n \r\n </div>\r\n }\r\n </div>\r\n }\r\n \r\n\r\n }\r\n\r\n </div>\r\n\r\n </div>\r\n \r\n </ng-template>\r\n \r\n <ng-container\r\n *ngTemplateOutlet=\"queryTemplate; context: { filter: $mainForm(), groupToRemove: null }\">\r\n </ng-container>\r\n \r\n </div>\r\n \r\n </form>\r\n \r\n <div class=\"dev-json-view\">\r\n <pre class=\"json-preview\">{{ $filterFormJsonString() | tableCell : 'TRIM' : lang }}</pre>\r\n </div>\r\n \r\n </div>\r\n", styles: [".core-rule-tree-container{display:flex;flex-direction:column;height:100vh;width:100%;overflow-y:auto}.core-rule-tree-container button{border-radius:0}.expression-box{background:#e0f2fe;padding:6px 12px;font-weight:500;font-size:14px}.top-controls{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;padding:8px}.expression-display{background-color:#e0f2fe;padding:8px 16px;font-family:monospace;font-size:14px;color:#0369a1}.query-builder{flex-grow:1;overflow-y:visible}.json-preview{background-color:#fff;color:#333;padding:1rem 1.5rem;border-radius:10px;box-shadow:0 2px 6px #00000014;font-family:Fira Code,monospace;font-size:.85rem;word-break:keep-all;overflow-x:auto;line-height:1.5;margin-top:15px}.core-rule-tree-form{display:flex;flex-direction:column;gap:16px}.top-bar{display:flex;justify-content:space-between;align-items:center}.expression-box{background:#e0f2fe;padding:6px 12px;font-weight:500;font-size:14px;margin-right:8px}.query-builder{display:flex;flex-direction:column;gap:16px}.group-card{padding:15px;background:#f9f9f9;display:flex;flex-direction:column;gap:8px;position:relative}.group-card .group-header{display:block;position:relative}.group-card .logical-operator{display:flex;align-items:center;align-self:flex-start;gap:8px}.group-card .logical-operator select{width:57px;background-color:#fff4ce}.group-card .logical-operator .local-action-buttons{margin-left:auto;display:flex;gap:4px}.group-card .logical-operator:hover .local-action-buttons{display:flex}.filter-list{display:flex;flex-direction:column;gap:8px}.filter-row{display:flex;align-items:center;gap:8px}.field-cell,.operator-cell,.value-cell{flex:1}.action-cell{flex-shrink:0}.btn-xs{padding:2px 6px;font-size:10px}.rule-group-container:hover{background-color:#f9f9f9}.group-content{pointer-events:none}.group-content>*{pointer-events:auto}.logical-operator-label{display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;border:1px solid #ced4da;background-color:#fff4ce;color:#495057;font-size:14px;font-weight:500;min-width:100px;width:57px;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: CoreControlValueOnlyComponent, selector: "core-control-value-only", inputs: ["$control", "$form", "$fieldName"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TooltipDirective, selector: "[appTooltip]", inputs: ["color", "backgroundColor", "appTooltip", "showAnyway", "position"] }, { kind: "pipe", type: TableCellPipe, name: "tableCell" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
350
+ }
351
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CoreRuleTreeComponent, decorators: [{
352
+ type: Component,
353
+ args: [{ selector: 'core-rule-tree', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
354
+ FormsModule,
355
+ ReactiveFormsModule,
356
+ CoreControlValueOnlyComponent,
357
+ NgTemplateOutlet,
358
+ CoreDropdownComponent,
359
+ TooltipDirective,
360
+ TableCellPipe,
361
+ TranslatePipe
362
+ ], template: "<div class=\"core-rule-tree-container\">\r\n\r\n <form [formGroup]=\"$mainForm()\" (ngSubmit)=\"null\" class=\"core-rule-tree-form\">\r\n\r\n <!-- Top Controls -->\r\n <div class=\"top-bar\">\r\n <div class=\"expression-box\">\r\n Expression = {{ $filterString() || '()' }}\r\n </div>\r\n \r\n <!-- <div class=\"button-group\">\r\n <button type=\"button\" class=\"btn btn-success btn-sm feather-file-plus\"\r\n (click)=\"addCondition($mainForm())\"\r\n [appTooltip]=\"'Add Condition'\">\r\n </button>\r\n <button type=\"button\" class=\"btn btn-success btn-sm feather-folder-plus\"\r\n (click)=\"addGroup($mainForm())\"\r\n [appTooltip]=\"'Add Group'\">\r\n </button>\r\n </div> -->\r\n </div>\r\n \r\n <!-- Query Builder -->\r\n <div class=\"query-builder\">\r\n <ng-template #queryTemplate let-filter=\"filter\" let-groupToRemove=\"groupToRemove\">\r\n \r\n <div class=\"group-card\">\r\n\r\n <div class=\"group-header\">\r\n\r\n <!-- Logical Operator -->\r\n <div class=\"logical-operator\">\r\n\r\n @if (filter === $mainForm()) {\r\n <div class=\"logical-operator-label\">\r\n AND\r\n </div>\r\n } @else {\r\n <select class=\"form-control pointer\" [formControl]=\"filter.get('logicalOperator')\">\r\n <option value=\"AND\">AND</option>\r\n <option value=\"OR\">OR</option>\r\n </select>\r\n }\r\n\r\n <!-- Collapse/Expand Button -->\r\n @if (!!filter.value.filters?.length) {\r\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\"\r\n (click)=\"toggleCollapse(filter)\"\r\n [appTooltip]=\"isCollapsed(filter) ? 'Expand Group' : 'Collapse Group'\">\r\n <i class=\"feather\" [class.feather-plus]=\"isCollapsed(filter)\" [class.feather-minus]=\"!isCollapsed(filter)\"></i>\r\n </button>\r\n }\r\n <div class=\"local-action-buttons\">\r\n <button type=\"button\" class=\"btn btn-xs btn-success feather-file-plus\"\r\n (click)=\"addCondition(filter)\"\r\n [appTooltip]=\"'Add Condition to this Group'\" [position]=\"'top'\">\r\n </button>\r\n <button type=\"button\" class=\"btn btn-xs btn-success feather-folder-plus\"\r\n (click)=\"addGroup(filter)\"\r\n [appTooltip]=\"'Add Subgroup to this Group'\" [position]=\"'top'\">\r\n </button>\r\n @if (!!groupToRemove) {\r\n <button type=\"button\" class=\"btn btn-xs btn-danger feather-trash\"\r\n (click)=\"removeGroup(groupToRemove.group, groupToRemove.index)\"\r\n [appTooltip]=\"'Remove Group'\" [position]=\"'top'\">\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"group-content\">\r\n \r\n <!-- Filter List (only shown when expanded) -->\r\n\r\n @if (!isCollapsed(filter)) {\r\n\r\n @if (!!filter.value.filters?.length) {\r\n <div class=\"filter-list\" formArrayName=\"filters\">\r\n @for (childFilter of filter.get('filters').controls; track $index; let idx = $index) {\r\n <div class=\"filter-row\" [formGroup]=\"childFilter\">\r\n \r\n @if (!childFilter.value.logicalOperator) {\r\n <div class=\"field-cell\">\r\n <select class=\"form-control\" formControlName=\"name\">\r\n @for (col of $totalCols(); track $index) {\r\n <option [value]=\"col.field\">\r\n {{ col.label || col.field }}\r\n </option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"operator-cell\">\r\n <select class=\"form-control\" formControlName=\"relationalOperator\">\r\n @for (op of relationalOperator; track $index) {\r\n <option [value]=\"op\">\r\n {{ operatorFriendlyMap[op] || op }}\r\n </option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"value-cell\">\r\n <!-- <input class=\"form-control\" formControlName=\"value\" /> -->\r\n <core-control-value-only\r\n [$control]=\"resolveControl(childFilter.value.name)!\"\r\n [$form]=\"childFilter\"\r\n [$fieldName]=\"'value'\"\r\n >\r\n </core-control-value-only>\r\n </div>\r\n <div class=\"action-cell\">\r\n <button type=\"button\" class=\"btn btn-danger btn-sm feather-trash-2\"\r\n (click)=\"removeCondition(filter, idx)\"\r\n [appTooltip]=\"'Remove Condition'\">\r\n </button>\r\n </div>\r\n } @else {\r\n <!-- Recursive nested groups -->\r\n <ng-container *ngTemplateOutlet=\"queryTemplate; context: { filter: childFilter, groupToRemove: { group: filter, index: idx } }\"></ng-container>\r\n }\r\n \r\n </div>\r\n }\r\n </div>\r\n }\r\n \r\n\r\n }\r\n\r\n </div>\r\n\r\n </div>\r\n \r\n </ng-template>\r\n \r\n <ng-container\r\n *ngTemplateOutlet=\"queryTemplate; context: { filter: $mainForm(), groupToRemove: null }\">\r\n </ng-container>\r\n \r\n </div>\r\n \r\n </form>\r\n \r\n <div class=\"dev-json-view\">\r\n <pre class=\"json-preview\">{{ $filterFormJsonString() | tableCell : 'TRIM' : lang }}</pre>\r\n </div>\r\n \r\n </div>\r\n", styles: [".core-rule-tree-container{display:flex;flex-direction:column;height:100vh;width:100%;overflow-y:auto}.core-rule-tree-container button{border-radius:0}.expression-box{background:#e0f2fe;padding:6px 12px;font-weight:500;font-size:14px}.top-controls{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;padding:8px}.expression-display{background-color:#e0f2fe;padding:8px 16px;font-family:monospace;font-size:14px;color:#0369a1}.query-builder{flex-grow:1;overflow-y:visible}.json-preview{background-color:#fff;color:#333;padding:1rem 1.5rem;border-radius:10px;box-shadow:0 2px 6px #00000014;font-family:Fira Code,monospace;font-size:.85rem;word-break:keep-all;overflow-x:auto;line-height:1.5;margin-top:15px}.core-rule-tree-form{display:flex;flex-direction:column;gap:16px}.top-bar{display:flex;justify-content:space-between;align-items:center}.expression-box{background:#e0f2fe;padding:6px 12px;font-weight:500;font-size:14px;margin-right:8px}.query-builder{display:flex;flex-direction:column;gap:16px}.group-card{padding:15px;background:#f9f9f9;display:flex;flex-direction:column;gap:8px;position:relative}.group-card .group-header{display:block;position:relative}.group-card .logical-operator{display:flex;align-items:center;align-self:flex-start;gap:8px}.group-card .logical-operator select{width:57px;background-color:#fff4ce}.group-card .logical-operator .local-action-buttons{margin-left:auto;display:flex;gap:4px}.group-card .logical-operator:hover .local-action-buttons{display:flex}.filter-list{display:flex;flex-direction:column;gap:8px}.filter-row{display:flex;align-items:center;gap:8px}.field-cell,.operator-cell,.value-cell{flex:1}.action-cell{flex-shrink:0}.btn-xs{padding:2px 6px;font-size:10px}.rule-group-container:hover{background-color:#f9f9f9}.group-content{pointer-events:none}.group-content>*{pointer-events:auto}.logical-operator-label{display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;border:1px solid #ced4da;background-color:#fff4ce;color:#495057;font-size:14px;font-weight:500;min-width:100px;width:57px;-webkit-user-select:none;user-select:none}\n"] }]
363
+ }], ctorParameters: () => [{ type: MultiLanguageService }, { type: i0.ChangeDetectorRef }] });
364
+
365
+ var EnumActorSourceType;
366
+ (function (EnumActorSourceType) {
367
+ EnumActorSourceType["Employee"] = "Employee";
368
+ EnumActorSourceType["Manager"] = "Manager";
369
+ EnumActorSourceType["DepartmentSupervisor"] = "DepartmentSupervisor";
370
+ EnumActorSourceType["Position"] = "Position";
371
+ EnumActorSourceType["Requester"] = "Requester";
372
+ EnumActorSourceType["StepRecipient"] = "StepRecipient";
373
+ EnumActorSourceType["UserGroup"] = "UserGroup";
374
+ EnumActorSourceType["SelfSelection"] = "SelfSelection"; // Manually chosen at runtime
375
+ })(EnumActorSourceType || (EnumActorSourceType = {}));
376
+
377
+ class WfActorSelectorComponent extends BaseComponent {
378
+ constructor() {
379
+ super(...arguments);
380
+ this.wfs = inject(CoreWorkflowService);
381
+ this.$value = this.wfs.$selectedActorAssignment;
382
+ this.$valueChange = output();
383
+ this.levelSpecificOptions$ = new BehaviorSubject([]);
384
+ this.employeeObjectList$ = new BehaviorSubject([]);
385
+ this.positionObjectList$ = new BehaviorSubject([]);
386
+ this.onNgModelChange = (ngModel, value) => {
387
+ switch (ngModel) {
388
+ case 'level':
389
+ this.onLevelChanged(value);
390
+ break;
391
+ case 'employeeIds':
392
+ case 'positionIds':
393
+ this.onStaticValueSelected(value);
394
+ break;
395
+ }
396
+ };
397
+ this.levelSpecificControl = {
398
+ controlType: EnumFormBaseContolType.DROPDOWN,
399
+ name: 'level',
400
+ dropdownOptions$: this.levelSpecificOptions$,
401
+ ngModel: this.$value()?.level,
402
+ flexSize: 12,
403
+ label: '',
404
+ ngModelChange: this.onNgModelChange,
405
+ getByIdApi: '/api/HuEmployee/GetById'
406
+ };
407
+ this.employeeIdsControl = {
408
+ controlType: EnumFormBaseContolType.SEEKER,
409
+ seekerSourceType: EnumCoreFormControlSeekerSourceType.EMPLOYEE_SEEK,
410
+ multiMode: true,
411
+ objectList$: this.employeeObjectList$,
412
+ name: 'employeeIds',
413
+ ngModel: this.$value()?.staticValueIds,
414
+ flexSize: 12,
415
+ label: '',
416
+ ngModelChange: this.onNgModelChange,
417
+ shownFrom: 'fullname',
418
+ getByIdApi: '/api/HuEmployee/GetById'
419
+ };
420
+ this.positionIdsControl = {
421
+ controlType: EnumFormBaseContolType.SEEKER,
422
+ seekerSourceType: EnumCoreFormControlSeekerSourceType.POSITION_SEEK,
423
+ multiMode: true,
424
+ objectList$: this.positionObjectList$,
425
+ name: 'positionIds',
426
+ ngModel: this.$value()?.staticValueIds,
427
+ flexSize: 12,
428
+ label: '',
429
+ ngModelChange: this.onNgModelChange,
430
+ shownFrom: 'name',
431
+ getByIdApi: '/api/HuPosition/GetById'
432
+ };
433
+ this.cdr = inject(ChangeDetectorRef);
434
+ this.AVAILABLE_SOURCES = Object.values(EnumActorSourceType);
435
+ this.actorSourceOptions$ = new BehaviorSubject(Object.values(EnumActorSourceType)
436
+ .filter(val => ['Employee', 'Manager', 'DepartmentSupervisor', 'Position'].includes(val))
437
+ .map(val => ({
438
+ value: val,
439
+ text: val
440
+ })));
441
+ this.unsupportedYetactorSourceOptions$ = new BehaviorSubject(Object.values(EnumActorSourceType)
442
+ .filter(val => !['Employee', 'Manager', 'DepartmentSupervisor', 'Position'].includes(val))
443
+ .map(val => ({
444
+ value: val,
445
+ text: val
446
+ })));
447
+ this.$showEmployeeSeeker = computed(() => this.$value()?.source === EnumActorSourceType.Employee);
448
+ this.$showPositionSeeker = computed(() => this.$value()?.source === EnumActorSourceType.Position);
449
+ this.$showLevel = computed(() => [EnumActorSourceType.Manager, EnumActorSourceType.DepartmentSupervisor].includes(this.$value().source));
450
+ this.$showStepKey = computed(() => this.$value()?.source === EnumActorSourceType.StepRecipient);
451
+ }
452
+ ngOnInit() {
453
+ this.subscriptions.push(this.mls.lang$.subscribe(x => this.lang = x));
454
+ const current = this.$value()?.source;
455
+ if (current === EnumActorSourceType.Manager ||
456
+ current === EnumActorSourceType.DepartmentSupervisor) {
457
+ this.updateLevelOptions(current);
458
+ }
459
+ }
460
+ updateLevelOptions(source) {
461
+ const prefix = source === EnumActorSourceType.Manager ? 'Direct manager' : 'Direct supervisor';
462
+ const options = Array.from({ length: 10 }, (_, i) => ({
463
+ value: i,
464
+ text: i === 0 ? `${prefix}` : `${prefix} + ${i}`
465
+ }));
466
+ this.levelSpecificOptions$.next(options);
467
+ }
468
+ onSourceChanged(newSource) {
469
+ let newValue = this.$value();
470
+ if (!newValue)
471
+ return;
472
+ // Optionally reset level
473
+ if (newSource === EnumActorSourceType.Manager ||
474
+ newSource === EnumActorSourceType.DepartmentSupervisor) {
475
+ newValue.level = undefined;
476
+ delete newValue.staticValueIds;
477
+ delete newValue.stepKey;
478
+ }
479
+ else {
480
+ delete newValue.level;
481
+ }
482
+ this.$value.set({ ...newValue });
483
+ this.updateLevelOptions(newSource);
484
+ this.$valueChange.emit({ source: newSource });
485
+ this.updateCurrentStepConfigPatch({
486
+ approvers: [{ source: newSource }],
487
+ });
488
+ this.cdr.markForCheck();
489
+ }
490
+ onStaticValueSelected(value) {
491
+ if (!this.$value())
492
+ return;
493
+ const next = { ...this.$value(), staticValueIds: value };
494
+ this.$valueChange.emit(next);
495
+ const prev = this.$value();
496
+ this.updateCurrentStepConfigPatch({
497
+ approvers: [{ ...prev, staticValueIds: value }]
498
+ });
499
+ }
500
+ onLevelChanged(level) {
501
+ if (!this.$value())
502
+ return;
503
+ const next = { ...this.$value(), level };
504
+ this.$valueChange.emit(next);
505
+ const prev = this.$value();
506
+ this.updateCurrentStepConfigPatch({
507
+ approvers: [{ ...prev, level }]
508
+ });
509
+ }
510
+ onStepKeyChanged(key) {
511
+ if (!this.$value())
512
+ return;
513
+ const next = { ...this.$value(), stepKey: key };
514
+ this.$valueChange.emit(next);
515
+ }
516
+ updateCurrentStepConfigPatch(patch) {
517
+ const step = this.wfs.$currentStep();
518
+ if (!step)
519
+ return;
520
+ const cloned = structuredClone(this.wfs.$currentSteps());
521
+ const target = cloned.find(s => s.id === step.id);
522
+ if (!target)
523
+ return;
524
+ target.config = {
525
+ ...(target.config ?? {}),
526
+ ...patch
527
+ };
528
+ this.wfs.$currentSteps.set(cloned);
529
+ }
530
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfActorSelectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
531
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: WfActorSelectorComponent, isStandalone: true, selector: "wf-actor-selector", outputs: { $valueChange: "$valueChange" }, usesInheritance: true, ngImport: i0, template: "<div class=\"wf-actor-selector-container\">\r\n <div class=\"soure-options\"\r\n [appTooltip]=\"'This version currently supports: Manager | Supervisor | Employee | Position'\"\r\n [showAnyway]=\"true\"\r\n [position]=\"'above'\" \r\n >\r\n <core-radio-group\r\n [options$]=\"actorSourceOptions$\"\r\n [vertical]=\"true\"\r\n [columnCount]=\"2\"\r\n [gapY]=\"8\"\r\n [(ngModel)]=\"$value()!.source\"\r\n (ngModelChange)=\"onSourceChanged($event)\">\r\n </core-radio-group>\r\n </div>\r\n\r\n <div class=\"soure-options form-control-disabled\"\r\n [appTooltip]=\"'Not supported yet in this version'\"\r\n [showAnyway]=\"true\"\r\n >\r\n <core-radio-group\r\n [options$]=\"unsupportedYetactorSourceOptions$\"\r\n [vertical]=\"true\"\r\n [columnCount]=\"2\"\r\n [gapY]=\"8\"\r\n [disabled]=\"true\"\r\n [(ngModel)]=\"$value()!.source\"\r\n (ngModelChange)=\"onSourceChanged($event)\">\r\n </core-radio-group>\r\n </div>\r\n \r\n <!-- Manager / DepartmentSupervisor -->\r\n @if (!!$value() && $showLevel()) {\r\n <div class=\"manager-level\">\r\n <label>\r\n {{ $value()!.source === 'Manager' ? 'Manager level' : 'Supervisor level' }}\r\n </label>\r\n <core-param-control\r\n [control]=\"levelSpecificControl\"\r\n ></core-param-control>\r\n </div>\r\n }\r\n \r\n <!-- Employee / Position / UserGroup (choose static entities) -->\r\n @if (!!$value() && $value()!.source === 'Employee' || $value()!.source === 'Position' || $value()!.source === 'UserGroup') {\r\n <div class=\"static-selector\">\r\n <label>Select {{ $value()!.source }}</label>\r\n <!-- Choose component based on source -->\r\n @switch ($value()!.source) {\r\n @case('Employee') {\r\n <core-param-control\r\n [control]=\"employeeIdsControl\"\r\n ></core-param-control>\r\n }\r\n @case('Position') {\r\n <core-param-control\r\n [control]=\"positionIdsControl\"\r\n ></core-param-control>\r\n }\r\n @case('UserGroup') {\r\n <div>Not supported yet in this version</div>\r\n }\r\n }\r\n </div>\r\n }\r\n \r\n @if (!!$value() && $value()!.source === 'StepRecipient') {\r\n <div>Not supported yet in this version</div>\r\n }\r\n \r\n</div>\r\n ", styles: [".wf-actor-selector-container{height:100%;font-size:13px}.wf-actor-selector-container>*{margin-bottom:15px}.wf-actor-selector-container .soure-options{border:1px gray solid;padding:15px 15px 15px 30px}.wf-actor-selector-container .soure-options.form-control-disabled{pointer-events:none}.wf-actor-selector-container .manager-level{position:relative;overflow-y:visible}.wf-actor-selector-container .manager-level label{color:#464646}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: CoreParamControlComponent, selector: "core-param-control", inputs: ["control", "enableTimeZoneConverterForDateTimePeriodParameters"] }, { kind: "component", type: CoreRadioGroupComponent, selector: "core-radio-group", inputs: ["options$", "vertical", "columnCount", "gapY"] }, { kind: "directive", type: TooltipDirective, selector: "[appTooltip]", inputs: ["color", "backgroundColor", "appTooltip", "showAnyway", "position"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
532
+ }
533
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfActorSelectorComponent, decorators: [{
534
+ type: Component,
535
+ args: [{ selector: 'wf-actor-selector', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
536
+ FormsModule,
537
+ CoreParamControlComponent,
538
+ CoreRadioGroupComponent,
539
+ TranslatePipe,
540
+ TooltipDirective,
541
+ ], template: "<div class=\"wf-actor-selector-container\">\r\n <div class=\"soure-options\"\r\n [appTooltip]=\"'This version currently supports: Manager | Supervisor | Employee | Position'\"\r\n [showAnyway]=\"true\"\r\n [position]=\"'above'\" \r\n >\r\n <core-radio-group\r\n [options$]=\"actorSourceOptions$\"\r\n [vertical]=\"true\"\r\n [columnCount]=\"2\"\r\n [gapY]=\"8\"\r\n [(ngModel)]=\"$value()!.source\"\r\n (ngModelChange)=\"onSourceChanged($event)\">\r\n </core-radio-group>\r\n </div>\r\n\r\n <div class=\"soure-options form-control-disabled\"\r\n [appTooltip]=\"'Not supported yet in this version'\"\r\n [showAnyway]=\"true\"\r\n >\r\n <core-radio-group\r\n [options$]=\"unsupportedYetactorSourceOptions$\"\r\n [vertical]=\"true\"\r\n [columnCount]=\"2\"\r\n [gapY]=\"8\"\r\n [disabled]=\"true\"\r\n [(ngModel)]=\"$value()!.source\"\r\n (ngModelChange)=\"onSourceChanged($event)\">\r\n </core-radio-group>\r\n </div>\r\n \r\n <!-- Manager / DepartmentSupervisor -->\r\n @if (!!$value() && $showLevel()) {\r\n <div class=\"manager-level\">\r\n <label>\r\n {{ $value()!.source === 'Manager' ? 'Manager level' : 'Supervisor level' }}\r\n </label>\r\n <core-param-control\r\n [control]=\"levelSpecificControl\"\r\n ></core-param-control>\r\n </div>\r\n }\r\n \r\n <!-- Employee / Position / UserGroup (choose static entities) -->\r\n @if (!!$value() && $value()!.source === 'Employee' || $value()!.source === 'Position' || $value()!.source === 'UserGroup') {\r\n <div class=\"static-selector\">\r\n <label>Select {{ $value()!.source }}</label>\r\n <!-- Choose component based on source -->\r\n @switch ($value()!.source) {\r\n @case('Employee') {\r\n <core-param-control\r\n [control]=\"employeeIdsControl\"\r\n ></core-param-control>\r\n }\r\n @case('Position') {\r\n <core-param-control\r\n [control]=\"positionIdsControl\"\r\n ></core-param-control>\r\n }\r\n @case('UserGroup') {\r\n <div>Not supported yet in this version</div>\r\n }\r\n }\r\n </div>\r\n }\r\n \r\n @if (!!$value() && $value()!.source === 'StepRecipient') {\r\n <div>Not supported yet in this version</div>\r\n }\r\n \r\n</div>\r\n ", styles: [".wf-actor-selector-container{height:100%;font-size:13px}.wf-actor-selector-container>*{margin-bottom:15px}.wf-actor-selector-container .soure-options{border:1px gray solid;padding:15px 15px 15px 30px}.wf-actor-selector-container .soure-options.form-control-disabled{pointer-events:none}.wf-actor-selector-container .manager-level{position:relative;overflow-y:visible}.wf-actor-selector-container .manager-level label{color:#464646}\n"] }]
542
+ }] });
543
+
544
+ class WfApproverConfigComponent {
545
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfApproverConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
546
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: WfApproverConfigComponent, isStandalone: true, selector: "wf-approver-config", ngImport: i0, template: "<wf-actor-selector></wf-actor-selector>", styles: [""], dependencies: [{ kind: "component", type: WfActorSelectorComponent, selector: "wf-actor-selector", outputs: ["$valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
547
+ }
548
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfApproverConfigComponent, decorators: [{
549
+ type: Component,
550
+ args: [{ selector: 'wf-approver-config', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
551
+ WfActorSelectorComponent
552
+ ], template: "<wf-actor-selector></wf-actor-selector>" }]
553
+ }] });
554
+
555
+ class WfCcConfigComponent {
556
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfCcConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
557
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: WfCcConfigComponent, isStandalone: true, selector: "wf-cc-config", ngImport: i0, template: "<wf-actor-selector></wf-actor-selector>", styles: [""], dependencies: [{ kind: "component", type: WfActorSelectorComponent, selector: "wf-actor-selector", outputs: ["$valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
558
+ }
559
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfCcConfigComponent, decorators: [{
560
+ type: Component,
561
+ args: [{ selector: 'wf-cc-config', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
562
+ WfActorSelectorComponent
563
+ ], template: "<wf-actor-selector></wf-actor-selector>" }]
564
+ }] });
565
+
566
+ class WfEndConfigComponent {
567
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfEndConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
568
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: WfEndConfigComponent, isStandalone: true, selector: "wf-end-config", ngImport: i0, template: "<div class=\"wf-submit-config-container\">\r\n <div class=\"submit-config-box\">\r\n <span class=\"icon\"><i class=\"feather-mail\"></i></span>\r\n <span class=\"message\">\r\n In this version, an email will be sent the <strong>requester</strong> by default.\r\n </span>\r\n </div>\r\n <div class=\"submit-config-box\">Press ESC to hide</div>\r\n</div>", styles: [".submit-config-box{display:flex;align-items:center;gap:8px;padding:15px;background-color:#ede7f6;border-left:4px solid #673ab7;margin-bottom:15px}.submit-config-box .icon{font-size:18px}.submit-config-box .message strong{font-weight:600}\n"] }); }
569
+ }
570
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfEndConfigComponent, decorators: [{
571
+ type: Component,
572
+ args: [{ selector: 'wf-end-config', imports: [], template: "<div class=\"wf-submit-config-container\">\r\n <div class=\"submit-config-box\">\r\n <span class=\"icon\"><i class=\"feather-mail\"></i></span>\r\n <span class=\"message\">\r\n In this version, an email will be sent the <strong>requester</strong> by default.\r\n </span>\r\n </div>\r\n <div class=\"submit-config-box\">Press ESC to hide</div>\r\n</div>", styles: [".submit-config-box{display:flex;align-items:center;gap:8px;padding:15px;background-color:#ede7f6;border-left:4px solid #673ab7;margin-bottom:15px}.submit-config-box .icon{font-size:18px}.submit-config-box .message strong{font-weight:600}\n"] }]
573
+ }] });
574
+
575
+ class WfHandlerConfigComponent {
576
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfHandlerConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
577
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: WfHandlerConfigComponent, isStandalone: true, selector: "wf-handler-config", ngImport: i0, template: "<wf-actor-selector></wf-actor-selector>", styles: [""], dependencies: [{ kind: "component", type: WfActorSelectorComponent, selector: "wf-actor-selector", outputs: ["$valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
578
+ }
579
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfHandlerConfigComponent, decorators: [{
580
+ type: Component,
581
+ args: [{ selector: 'wf-handler-config', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
582
+ WfActorSelectorComponent
583
+ ], template: "<wf-actor-selector></wf-actor-selector>" }]
584
+ }] });
585
+
586
+ class WfSubmitConfigComponent {
587
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfSubmitConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
588
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: WfSubmitConfigComponent, isStandalone: true, selector: "wf-submit-config", ngImport: i0, template: "<div class=\"wf-submit-config-container\">\r\n <div class=\"submit-config-box\">\r\n <span class=\"icon\"><i class=\"feather-check-square\"></i></span>\r\n <span class=\"message\">\r\n In this version, <strong>all members</strong> are allowed to submit.\r\n </span>\r\n </div>\r\n <div class=\"submit-config-box\">Press ESC to hide</div>\r\n</div>", styles: [".submit-config-box{display:flex;align-items:center;gap:8px;padding:15px;background-color:#e0f7fa;border-left:4px solid #00bcd4;margin-bottom:15px}.submit-config-box .icon{font-size:18px}.submit-config-box .message strong{font-weight:600}\n"] }); }
589
+ }
590
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfSubmitConfigComponent, decorators: [{
591
+ type: Component,
592
+ args: [{ selector: 'wf-submit-config', imports: [], template: "<div class=\"wf-submit-config-container\">\r\n <div class=\"submit-config-box\">\r\n <span class=\"icon\"><i class=\"feather-check-square\"></i></span>\r\n <span class=\"message\">\r\n In this version, <strong>all members</strong> are allowed to submit.\r\n </span>\r\n </div>\r\n <div class=\"submit-config-box\">Press ESC to hide</div>\r\n</div>", styles: [".submit-config-box{display:flex;align-items:center;gap:8px;padding:15px;background-color:#e0f7fa;border-left:4px solid #00bcd4;margin-bottom:15px}.submit-config-box .icon{font-size:18px}.submit-config-box .message strong{font-weight:600}\n"] }]
593
+ }] });
594
+
595
+ class WfStepConfigShellComponent {
596
+ constructor(coreWorkflowService, domService) {
597
+ this.coreWorkflowService = coreWorkflowService;
598
+ this.domService = domService;
599
+ this.$container = viewChild('container');
600
+ // listenerFn!: () => void;
601
+ this.renderer = inject(Renderer2);
602
+ this.cdr = inject(ChangeDetectorRef);
603
+ this.enumType = EnumWorkflowStepType;
604
+ this.$stepFormGroup = computed(() => {
605
+ const step = this.coreWorkflowService.$currentStep();
606
+ if (!step) {
607
+ return new FormGroup({
608
+ logicalOperator: new FormControl('AND'),
609
+ filters: new FormArray([])
610
+ });
611
+ }
612
+ return this.buildFormGroupFromStep(step.config);
613
+ });
614
+ this.$isBranchCard = computed(() => {
615
+ const step = this.coreWorkflowService.$currentStep();
616
+ console.log(step?.type);
617
+ console.log(step?.type === EnumWorkflowStepType.BranchCard);
618
+ return !!step && step.type === EnumWorkflowStepType.BranchCard;
619
+ });
620
+ this.$canRenderRuleTree = computed(() => {
621
+ const form = this.$stepFormGroup();
622
+ const cols = this.coreWorkflowService.$availableCols();
623
+ const isBranchCard = this.$isBranchCard();
624
+ if (!form || !cols || !isBranchCard)
625
+ return false;
626
+ if (cols.length === 0)
627
+ return false;
628
+ return form.valid;
629
+ });
630
+ effect(() => {
631
+ const containerRef = this.$container();
632
+ if (containerRef) {
633
+ containerRef.nativeElement.style.zIndex = this.domService.getMaxZIndex() + 1;
634
+ }
635
+ });
636
+ }
637
+ buildFormGroupFromStep(config) {
638
+ if (!config) {
639
+ return new FormGroup({
640
+ logicalOperator: new FormControl('AND'),
641
+ filters: new FormArray([])
642
+ });
643
+ }
644
+ return new FormGroup({
645
+ logicalOperator: new FormControl(config.logicalOperator ?? 'AND'),
646
+ filters: new FormArray([]) // You could map config.filters to prefilled controls
647
+ });
648
+ }
649
+ close() {
650
+ this.coreWorkflowService.$showStepConfig.set(false); // example method
651
+ }
652
+ save() {
653
+ // handle save logic
654
+ }
655
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfStepConfigShellComponent, deps: [{ token: CoreWorkflowService }, { token: DomService }], target: i0.ɵɵFactoryTarget.Component }); }
656
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: WfStepConfigShellComponent, isStandalone: true, selector: "wf-step-config-shell", viewQueries: [{ propertyName: "$container", first: true, predicate: ["container"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"wf-step-config-shell-container\" #container [class.shown]=\"coreWorkflowService.$showStepConfig()\">\r\n \r\n <div class=\"wf-step-config-header\">\r\n <div class=\"panel-title\">\r\n {{ coreWorkflowService.$currentStep()?.type || 'Step' }} Configuration\r\n </div>\r\n <div class=\"close-wrapper\" (click)=\"close()\">\r\n <i class=\"feather-x\"></i>\r\n </div>\r\n </div>\r\n \r\n <div class=\"wf-step-config-content\">\r\n\r\n\r\n @switch (coreWorkflowService.$currentStep()?.type) {\r\n \r\n @case (enumType.BranchCard) {\r\n <core-rule-tree\r\n [$totalCols]=\"coreWorkflowService.$availableCols()\"\r\n [$mainForm]=\"$stepFormGroup()\" />\r\n }\r\n \r\n @case (enumType.Approval) {\r\n <wf-approver-config/>\r\n }\r\n \r\n @case (enumType.Handle) {\r\n <wf-handler-config/>\r\n }\r\n \r\n @case (enumType.CC) {\r\n <wf-cc-config/>\r\n }\r\n \r\n @case (enumType.Submit) {\r\n <wf-submit-config/>\r\n }\r\n \r\n @case (enumType.End) {\r\n <wf-end-config/>\r\n }\r\n \r\n @default {\r\n <div class=\"loading-placeholder\">\r\n Unsupported step type.\r\n </div>\r\n }\r\n \r\n }\r\n \r\n \r\n </div>\r\n \r\n</div>", styles: [".wf-step-config-shell-container{display:block;position:fixed;top:0;right:-532px;width:532px;height:100vh;background-color:#fff;transition:right .2s ease-out;box-shadow:var(--decoration-box-shadow);overflow-y:auto}.wf-step-config-header{display:flex;align-items:center;justify-content:space-between;padding:15px;height:60px;background-color:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1f2937}.panel-title{flex-grow:1}.close-wrapper{display:flex;align-items:center;justify-content:center;background-color:#f1f5f9;width:32px;height:32px;border-radius:50%;cursor:pointer;transition:background-color .2s}.close-wrapper:hover{background-color:#e2e8f0}.wf-step-config-content{flex-grow:1;padding:15px;overflow-y:visible;font-size:13px}.wf-step-config-content .core-radio-group-container label{font-size:13px!important}.loading-placeholder{display:flex;align-items:center;justify-content:center;height:100%;color:#94a3b8;font-size:14px}.wf-step-config-shell-container.shown{right:0}\n"], dependencies: [{ kind: "component", type: CoreRuleTreeComponent, selector: "core-rule-tree", inputs: ["$totalCols", "$mainForm", "$filterStringInput", "$expressionInput"], outputs: ["$jsonEmitter", "$expressionEmitter"] }, { kind: "component", type: WfApproverConfigComponent, selector: "wf-approver-config" }, { kind: "component", type: WfCcConfigComponent, selector: "wf-cc-config" }, { kind: "component", type: WfEndConfigComponent, selector: "wf-end-config" }, { kind: "component", type: WfHandlerConfigComponent, selector: "wf-handler-config" }, { kind: "component", type: WfSubmitConfigComponent, selector: "wf-submit-config" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
657
+ }
658
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfStepConfigShellComponent, decorators: [{
659
+ type: Component,
660
+ args: [{ selector: 'wf-step-config-shell', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
661
+ CoreRuleTreeComponent,
662
+ WfApproverConfigComponent,
663
+ WfCcConfigComponent,
664
+ WfEndConfigComponent,
665
+ WfHandlerConfigComponent,
666
+ WfSubmitConfigComponent
667
+ ], template: "<div class=\"wf-step-config-shell-container\" #container [class.shown]=\"coreWorkflowService.$showStepConfig()\">\r\n \r\n <div class=\"wf-step-config-header\">\r\n <div class=\"panel-title\">\r\n {{ coreWorkflowService.$currentStep()?.type || 'Step' }} Configuration\r\n </div>\r\n <div class=\"close-wrapper\" (click)=\"close()\">\r\n <i class=\"feather-x\"></i>\r\n </div>\r\n </div>\r\n \r\n <div class=\"wf-step-config-content\">\r\n\r\n\r\n @switch (coreWorkflowService.$currentStep()?.type) {\r\n \r\n @case (enumType.BranchCard) {\r\n <core-rule-tree\r\n [$totalCols]=\"coreWorkflowService.$availableCols()\"\r\n [$mainForm]=\"$stepFormGroup()\" />\r\n }\r\n \r\n @case (enumType.Approval) {\r\n <wf-approver-config/>\r\n }\r\n \r\n @case (enumType.Handle) {\r\n <wf-handler-config/>\r\n }\r\n \r\n @case (enumType.CC) {\r\n <wf-cc-config/>\r\n }\r\n \r\n @case (enumType.Submit) {\r\n <wf-submit-config/>\r\n }\r\n \r\n @case (enumType.End) {\r\n <wf-end-config/>\r\n }\r\n \r\n @default {\r\n <div class=\"loading-placeholder\">\r\n Unsupported step type.\r\n </div>\r\n }\r\n \r\n }\r\n \r\n \r\n </div>\r\n \r\n</div>", styles: [".wf-step-config-shell-container{display:block;position:fixed;top:0;right:-532px;width:532px;height:100vh;background-color:#fff;transition:right .2s ease-out;box-shadow:var(--decoration-box-shadow);overflow-y:auto}.wf-step-config-header{display:flex;align-items:center;justify-content:space-between;padding:15px;height:60px;background-color:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1f2937}.panel-title{flex-grow:1}.close-wrapper{display:flex;align-items:center;justify-content:center;background-color:#f1f5f9;width:32px;height:32px;border-radius:50%;cursor:pointer;transition:background-color .2s}.close-wrapper:hover{background-color:#e2e8f0}.wf-step-config-content{flex-grow:1;padding:15px;overflow-y:visible;font-size:13px}.wf-step-config-content .core-radio-group-container label{font-size:13px!important}.loading-placeholder{display:flex;align-items:center;justify-content:center;height:100%;color:#94a3b8;font-size:14px}.wf-step-config-shell-container.shown{right:0}\n"] }]
668
+ }], ctorParameters: () => [{ type: CoreWorkflowService }, { type: DomService }] });
669
+
670
+ const ROOT_BRANCH_ID = 'root';
671
+
672
+ class BridgeLineService {
673
+ constructor() {
674
+ this.coreWorkflowService = inject(CoreWorkflowService);
675
+ this.colorRadius = 10;
676
+ }
677
+ adjustBridgeLines(branchGroupEl, topBridgeLineEl, bottomBridgeLineEl, branchColumnEls) {
678
+ const columns = Array.from(branchGroupEl.querySelectorAll(':scope > .branch-column'));
679
+ if (columns.length < 2)
680
+ return;
681
+ // Helper: get the last .arrow-down inside a column
682
+ // ':scope > .arrow-down' only works if .arrow-down is a direct child of col.
683
+ // Safely queries only arrows inside wf-bottom-v-insert
684
+ // Uses .pop() to grab the last one, if any (safe fallback if there's more than one).
685
+ // Ensures type safety with instanceof HTMLElement.
686
+ const getLastArrow = (col) => {
687
+ const arrow = Array.from(col.querySelectorAll('wf-bottom-v-insert .arrow-down')).pop();
688
+ return arrow instanceof HTMLElement ? arrow : null;
689
+ };
690
+ const allArrows = columns
691
+ .map(getLastArrow)
692
+ .filter((el) => !!el);
693
+ if (allArrows.length < 2)
694
+ return;
695
+ const r1 = allArrows[0].getBoundingClientRect();
696
+ const r2 = allArrows[allArrows.length - 1].getBoundingClientRect();
697
+ const containerRect = branchGroupEl.getBoundingClientRect();
698
+ const left = r1.left + r1.width / 2 - containerRect.left;
699
+ const right = r2.left + r2.width / 2 - containerRect.left;
700
+ const maxArrowBottom = allArrows.reduce((max, el) => {
701
+ const bottom = el.getBoundingClientRect().bottom;
702
+ return Math.max(max, bottom);
703
+ }, 0);
704
+ const top = maxArrowBottom - containerRect.top - 1;
705
+ // TOP bridge line
706
+ topBridgeLineEl.style.top = `17.5px`;
707
+ topBridgeLineEl.style.left = `${left}px`;
708
+ topBridgeLineEl.style.width = `${right - left}px`;
709
+ // BOTTOM bridge line
710
+ bottomBridgeLineEl.style.top = `${top}px`;
711
+ bottomBridgeLineEl.style.left = `${left}px`;
712
+ bottomBridgeLineEl.style.width = `${right - left}px`;
713
+ // Vertical lines
714
+ branchColumnEls.forEach(col => {
715
+ const lastArrow = getLastArrow(col);
716
+ const vertical = col.querySelector(':scope > .vertical-bridge-line');
717
+ if (!lastArrow || !vertical)
718
+ return;
719
+ const arrowRect = lastArrow.getBoundingClientRect();
720
+ const colRect = col.getBoundingClientRect();
721
+ const startY = arrowRect.bottom - colRect.top;
722
+ const height = top - startY - this.coreWorkflowService.standardConnectorHeight - 17.5;
723
+ vertical.style.top = `${startY}px`;
724
+ vertical.style.left = `calc(50% - 1px)`;
725
+ vertical.style.height = `${height}px`;
726
+ vertical.style.display = height > 0 ? 'block' : 'none';
727
+ //vertical.style.backgroundColor = `hsl(${this.colorRadius}, 100%, 50%)`;
728
+ this.colorRadius += 10;
729
+ });
730
+ }
731
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BridgeLineService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
732
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BridgeLineService, providedIn: 'root' }); }
733
+ }
734
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BridgeLineService, decorators: [{
735
+ type: Injectable,
736
+ args: [{
737
+ providedIn: 'root'
738
+ }]
739
+ }] });
740
+
741
+ class BridgeLineDirective {
742
+ constructor(elRef, bridgeLineService, zone) {
743
+ this.elRef = elRef;
744
+ this.bridgeLineService = bridgeLineService;
745
+ this.zone = zone;
746
+ this.bridgeLinesAdjusted = new EventEmitter();
747
+ }
748
+ ngOnInit() {
749
+ this.zone.runOutsideAngular(() => {
750
+ this.resizeObserver = new ResizeObserver(() => {
751
+ requestAnimationFrame(() => this.adjustBridgeLines());
752
+ });
753
+ this.resizeObserver.observe(this.elRef.nativeElement);
754
+ this.mutationObserver = new MutationObserver(() => {
755
+ this.adjustBridgeLines();
756
+ });
757
+ this.mutationObserver.observe(this.elRef.nativeElement, {
758
+ childList: true,
759
+ subtree: true
760
+ });
761
+ });
762
+ // First adjustment
763
+ requestAnimationFrame(() => this.adjustBridgeLines());
764
+ }
765
+ ngOnDestroy() {
766
+ this.resizeObserver?.disconnect();
767
+ this.mutationObserver?.disconnect();
768
+ }
769
+ adjustBridgeLines() {
770
+ const branchGroupEl = this.elRef.nativeElement;
771
+ const bridgeLines = branchGroupEl.querySelectorAll('.horizontal-bridge-line');
772
+ const topBridgeLineEl = bridgeLines[0];
773
+ const bottomBridgeLineEl = bridgeLines[1];
774
+ const branchColumnEls = Array.from(branchGroupEl.querySelectorAll(':scope > .branch-column'));
775
+ if (!topBridgeLineEl || !bottomBridgeLineEl || !branchColumnEls)
776
+ return;
777
+ this.bridgeLineService.adjustBridgeLines(this.elRef.nativeElement, topBridgeLineEl, bottomBridgeLineEl, branchColumnEls);
778
+ this.bridgeLinesAdjusted.emit();
779
+ }
780
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BridgeLineDirective, deps: [{ token: i0.ElementRef }, { token: BridgeLineService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
781
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.5", type: BridgeLineDirective, isStandalone: true, selector: "[bridgeLine]", outputs: { bridgeLinesAdjusted: "bridgeLinesAdjusted" }, ngImport: i0 }); }
782
+ }
783
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BridgeLineDirective, decorators: [{
784
+ type: Directive,
785
+ args: [{
786
+ selector: '[bridgeLine]'
787
+ }]
788
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: BridgeLineService }, { type: i0.NgZone }], propDecorators: { bridgeLinesAdjusted: [{
789
+ type: Output
790
+ }] } });
791
+
792
+ class WfNodeComponent extends BaseComponent {
793
+ constructor() {
794
+ super(...arguments);
795
+ this.stepGroup = []; // array that holds 'step'
796
+ this.isRootLevelStepGroup = false;
797
+ this.grandParentSteps = null; // The step array that owns the parent step of type ConditionalBranch
798
+ this.isInFallbackBranch = false;
799
+ //private observer!: MutationObserver;
800
+ this.enumType = EnumWorkflowStepType;
801
+ this.coreWorkflowService = inject(CoreWorkflowService);
802
+ this.renderer = inject(Renderer2);
803
+ this.bridgeLineService = inject(BridgeLineService);
804
+ this.stepNameEditMode = false;
805
+ }
806
+ onInputBlur() {
807
+ this.stepNameEditMode = false;
808
+ }
809
+ onStepNameChanged(newName) {
810
+ if (this.isRootLevelStepGroup) {
811
+ const cloned = structuredClone(this.coreWorkflowService.$currentSteps());
812
+ const stepInCloned = cloned.find(s => s.id === this.step.id);
813
+ if (stepInCloned) {
814
+ stepInCloned.name = newName;
815
+ this.coreWorkflowService.$currentSteps.set(cloned);
816
+ }
817
+ }
818
+ }
819
+ getBranchColumnElements() {
820
+ return this.branchColumnRefs?.map(ref => ref?.nativeElement);
821
+ }
822
+ setupClickOutsideListener() {
823
+ // Clean up any existing listener
824
+ if (this.listenerFn) {
825
+ this.listenerFn();
826
+ this.listenerFn = null;
827
+ }
828
+ // Delay to ensure DOM has rendered
829
+ setTimeout(() => {
830
+ this.listenerFn = this.renderer.listen('document', 'click', (event) => {
831
+ const clickedInside = this.branchHeader?.nativeElement.contains(event.target);
832
+ if (!clickedInside) {
833
+ this.stepNameEditMode = false;
834
+ this.removeClickOutsideListener(); // optional: remove after 1 toggle
835
+ }
836
+ });
837
+ });
838
+ }
839
+ removeClickOutsideListener() {
840
+ if (this.listenerFn) {
841
+ this.listenerFn();
842
+ this.listenerFn = null;
843
+ }
844
+ }
845
+ onLabelClicked() {
846
+ this.coreWorkflowService.$showStepConfig.set(true);
847
+ }
848
+ switchToNameEditMode() {
849
+ if (!!this.step.isPseudo && !!this.isInFallbackBranch)
850
+ return;
851
+ this.stepNameEditMode = true;
852
+ setTimeout(() => this.input?.nativeElement.focus());
853
+ this.setupClickOutsideListener();
854
+ }
855
+ adjustBridgeLines() {
856
+ setTimeout(() => {
857
+ if (!this.branchGroupRef || !this.topBridgeLineRef || !this.bottomBridgeLineRef) {
858
+ console.warn('[DEBUG] Some ref was null');
859
+ return;
860
+ }
861
+ console.log('[DEBUG] Triggering BridgeLineService');
862
+ this.bridgeLineService.adjustBridgeLines(this.branchGroupRef.nativeElement, this.topBridgeLineRef.nativeElement, this.bottomBridgeLineRef.nativeElement, this.branchColumnRefs.map(ref => ref.nativeElement));
863
+ }, 50);
864
+ }
865
+ /*
866
+ onDeleteBranch(branchId: string): void {
867
+
868
+ if (!this.conditionalBranches) return;
869
+
870
+ const index = this.conditionalBranches.findIndex(b => b.id === branchId);
871
+ if (index === -1) return;
872
+
873
+ // ❌ Remove the selected branch
874
+ this.conditionalBranches.splice(index, 1);
875
+
876
+ // ✅ Check if only fallback branch remains → delete the group step
877
+ if (this.conditionalBranches.length === 1 && this.conditionalBranches[0].isFallback) {
878
+
879
+ if (!this.grandParentSteps) return;
880
+
881
+ const indexInGrandParentSteps = this.grandParentSteps.findIndex(x => x.branches?.some(y => y.id === this.conditionalBranches[0].id));
882
+ if (indexInGrandParentSteps === -1) return;
883
+
884
+ // 🧹 Remove the ConditionalBranch step (parent step)
885
+ this.grandParentSteps.splice(indexInGrandParentSteps, 1);
886
+
887
+ } else {
888
+
889
+ this.coreWorkflowService.autoReassignPriorities(this.conditionalBranches);
890
+
891
+ }
892
+ }
893
+ */
894
+ /*
895
+ If the fallback deletion triggers parent step removal → check isRootLevelStepGroup to update signal.
896
+ Otherwise, it's safe to mutate grandParentSteps directly.
897
+ autoReassignPriorities() keeps branch execution order consistent.
898
+ */
899
+ /*
900
+ onDeleteBranch(branchId: string): void {
901
+ if (!this.conditionalBranches) return;
902
+
903
+ const index = this.conditionalBranches.findIndex(b => b.id === branchId);
904
+ if (index === -1) return;
905
+
906
+ // 🧹 Remove selected branch
907
+ this.conditionalBranches.splice(index, 1);
908
+
909
+ // ✅ Case: only fallback remains → delete the entire ConditionalBranch step
910
+ const onlyFallbackLeft = this.conditionalBranches.length === 1 && this.conditionalBranches[0].isFallback;
911
+ if (onlyFallbackLeft) {
912
+ if (!this.grandParentSteps) return;
913
+
914
+ const fallbackBranchId = this.conditionalBranches[0].id;
915
+ const stepIndex = this.grandParentSteps.findIndex(step =>
916
+ step.branches?.some(branch => branch.id === fallbackBranchId)
917
+ );
918
+ if (stepIndex === -1) return;
919
+
920
+ if (this.isRootLevelStepGroup) {
921
+ // ✅ Must clone and reassign signal
922
+ const updated = [...this.grandParentSteps];
923
+ updated.splice(stepIndex, 1);
924
+ this.coreWorkflowService.$currentSteps.set(updated);
925
+ } else {
926
+ // ✅ In-place mutation is safe for non-root
927
+ this.grandParentSteps.splice(stepIndex, 1);
928
+ }
929
+
930
+ return;
931
+ }
932
+
933
+ // 🔁 Otherwise: re-prioritize branches
934
+ this.coreWorkflowService.autoReassignPriorities(this.conditionalBranches);
935
+ }
936
+ */
937
+ onDeleteBranch(branchId) {
938
+ if (!this.conditionalBranches)
939
+ return;
940
+ const index = this.conditionalBranches.findIndex(b => b.id === branchId);
941
+ if (index === -1)
942
+ return;
943
+ // ⚠️ Remove selected branch (in-place is okay, but needs re-signal)
944
+ this.conditionalBranches.splice(index, 1);
945
+ const onlyFallbackLeft = this.conditionalBranches.length === 1 && this.conditionalBranches[0].isFallback;
946
+ if (onlyFallbackLeft) {
947
+ if (!this.grandParentSteps)
948
+ return;
949
+ const fallbackBranchId = this.conditionalBranches[0].id;
950
+ const stepIndex = this.grandParentSteps.findIndex(step => step.branches?.some(branch => branch.id === fallbackBranchId));
951
+ if (stepIndex === -1)
952
+ return;
953
+ if (this.isRootLevelStepGroup) {
954
+ // ✅ Deep clone and reassign to trigger reactivity
955
+ const updated = structuredClone(this.grandParentSteps);
956
+ updated.splice(stepIndex, 1);
957
+ this.coreWorkflowService.$currentSteps.set(updated);
958
+ }
959
+ else {
960
+ // ✅ In-place mutation is fine for nested groups
961
+ this.grandParentSteps.splice(stepIndex, 1);
962
+ this.coreWorkflowService.$currentSteps.set(structuredClone(this.coreWorkflowService.$currentSteps()));
963
+ }
964
+ return;
965
+ }
966
+ // 🧠 Still re-trigger signal to reflect nested change in UI
967
+ this.coreWorkflowService.autoReassignPriorities(this.conditionalBranches);
968
+ this.coreWorkflowService.$currentSteps.set(structuredClone(this.coreWorkflowService.$currentSteps()));
969
+ }
970
+ /*onDeleteStep(): void {
971
+
972
+ if (!this.stepGroup) return;
973
+
974
+ const index = this.stepGroup.findIndex(s => s.id === this.step.id);
975
+ if (index === -1) return;
976
+
977
+ // ❌ Remove the selected step
978
+ this.stepGroup.splice(index, 1);
979
+
980
+ }*/
981
+ /*
982
+ For root-level steps, we must reassign the signal so Angular reacts to it.
983
+ For nested branch steps, direct mutation is acceptable because the signal still tracks the root array (which contains branches).
984
+ */
985
+ /*
986
+ onDeleteStep(): void {
987
+ if (!this.stepGroup) return;
988
+
989
+ const index = this.stepGroup.findIndex(s => s.id === this.step.id);
990
+ if (index === -1) return;
991
+
992
+ if (this.isRootLevelStepGroup) {
993
+ // ✅ Immutable update to signal
994
+ const updated = [...this.stepGroup];
995
+ updated.splice(index, 1);
996
+ this.coreWorkflowService.$currentSteps.set(updated);
997
+ } else {
998
+ // ✅ Safe mutation inside branch
999
+ this.stepGroup.splice(index, 1);
1000
+ }
1001
+ }
1002
+ */
1003
+ onDeleteStep() {
1004
+ if (!this.stepGroup)
1005
+ return;
1006
+ const index = this.stepGroup.findIndex(s => s.id === this.step.id);
1007
+ if (index === -1)
1008
+ return;
1009
+ if (this.isRootLevelStepGroup) {
1010
+ this.coreWorkflowService.updateStepsSignalAfterNestedChange(this.coreWorkflowService.$currentSteps, draft => {
1011
+ draft.splice(index, 1);
1012
+ });
1013
+ }
1014
+ else {
1015
+ this.stepGroup.splice(index, 1); // nested mutation still allowed (e.g., in branch)
1016
+ this.coreWorkflowService.updateStepsSignalAfterNestedChange(this.coreWorkflowService.$currentSteps, _ => { }); // triggers reactivity
1017
+ }
1018
+ }
1019
+ ngAfterViewInit() {
1020
+ setTimeout(() => {
1021
+ });
1022
+ }
1023
+ ngOnDestroy() {
1024
+ this.subscriptions.forEach(x => x?.unsubscribe());
1025
+ }
1026
+ openConditionEditor() {
1027
+ this.coreWorkflowService.$currentStep.set(this.step);
1028
+ this.coreWorkflowService.$showStepConfig.set(true);
1029
+ }
1030
+ openNoneBranchRelatedEditor() {
1031
+ this.coreWorkflowService.$currentStep.set(this.step);
1032
+ this.coreWorkflowService.$showStepConfig.set(true);
1033
+ }
1034
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfNodeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1035
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: WfNodeComponent, isStandalone: true, selector: "wf-node", inputs: { branchId: "branchId", step: "step", index: "index", branchPriority: "branchPriority", stepGroup: "stepGroup", conditionalBranches: "conditionalBranches", isRootLevelStepGroup: "isRootLevelStepGroup", grandParentSteps: "grandParentSteps", isInFallbackBranch: "isInFallbackBranch" }, viewQueries: [{ propertyName: "branchHeader", first: true, predicate: ["branchHeader"], descendants: true }, { propertyName: "branchName", first: true, predicate: ["branchName"], descendants: true }, { propertyName: "input", first: true, predicate: ["input"], descendants: true }, { propertyName: "branchGroupRef", first: true, predicate: ["branchGroup"], descendants: true }, { propertyName: "topBridgeLineRef", first: true, predicate: ["topBridgeLine"], descendants: true }, { propertyName: "bottomBridgeLineRef", first: true, predicate: ["bottomBridgeLine"], descendants: true }, { propertyName: "branchColumnRefs", predicate: ["branchColumn"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@switch (step.type) {\r\n\r\n @case (enumType.ConditionalBranch) {\r\n <div class=\"wf-branch-group-container\">\r\n <div \r\n class=\"branch-group\" \r\n #branchGroup \r\n bridgeLine\r\n (bridgeLinesAdjusted)=\"adjustBridgeLines()\"\r\n >\r\n <!-- \uD83D\uDD39 Top Bridge Line -->\r\n <div class=\"horizontal-bridge-line\" #topBridgeLine></div>\r\n\r\n <div class=\"add-branch-inline\">\r\n <button class=\"add-branch-btn\" (click)=\"coreWorkflowService.addBranchToStep(step.id)\">\r\n \uFF0B Add New Branch\r\n </button>\r\n </div>\r\n\r\n \r\n @for (branch of step.branches; track $index; let j = $index) {\r\n <div class=\"branch-column\" #branchColumn>\r\n <div class=\"branch-column-inner\">\r\n \r\n @for (bstep of branch.steps; track $index; let k = $index) {\r\n <wf-node\r\n [branchId]=\"branch.id\"\r\n [branchPriority]=\"branch.priority\"\r\n [step]=\"bstep\"\r\n [conditionalBranches]=\"step.branches || []\"\r\n [stepGroup]=\"branch.steps\"\r\n [grandParentSteps]=\"stepGroup\"\r\n [index]=\"k\"\r\n [isInFallbackBranch]=\"!!branch.isFallback\"\r\n ></wf-node>\r\n }\r\n \r\n </div>\r\n \r\n <div class=\"vertical-bridge-line\"></div>\r\n </div>\r\n }\r\n \r\n <!-- \uD83D\uDD39 Bottom Bridge Line -->\r\n <div class=\"horizontal-bridge-line\" #bottomBridgeLine></div>\r\n </div>\r\n </div>\r\n }\r\n \r\n @case (enumType.BranchCard) {\r\n <div class=\"wf-step-container wf-branch-card-container workflow-box\">\r\n <div class=\"step-wrapper branch-card-wrapper\" [class.fallback]=\"!!isInFallbackBranch\">\r\n <div class=\"arrow-down-container\">\r\n <div class=\"arrow-down\"></div>\r\n </div>\r\n \r\n <div class=\"step-header branch-header\" [class.edit-mode]=\"stepNameEditMode\" #branchHeader>\r\n @if (stepNameEditMode) {\r\n <div class=\"input-wrapper\">\r\n <input class=\"form-control\" \r\n (blur)=\"onInputBlur()\" \r\n [(ngModel)]=\"step.name\"\r\n (ngModelChange)=\"onStepNameChanged($event)\" \r\n #input>\r\n </div>\r\n } @else {\r\n <div class=\"step-name-wrapper branch-name-wrapper\">\r\n <div\r\n class=\"step-name branch-name\"\r\n [class.pointer]=\"!isInFallbackBranch\"\r\n (click)=\"switchToNameEditMode()\"\r\n #branchName>\r\n {{ step.name }}\r\n </div>\r\n \r\n @if (!!isInFallbackBranch) {\r\n <i class=\"ti-info-alt\"\r\n [appTooltip]=\"'This branch is created by default and will only be activated if none of the other branches can be executed.'\"\r\n [showAnyway]=\"true\" [position]=\"'above'\"></i>\r\n }\r\n </div>\r\n \r\n <div class=\"branch-priority\">Priority {{ branchPriority }}</div>\r\n <div class=\"step-delete branch-delete pointer\" (click)=\"onDeleteBranch(branchId)\">\r\n <i class=\"feather-x\"></i>\r\n </div>\r\n }\r\n </div>\r\n \r\n <div class=\"step-set-config branch-set-condition\" [class.pointer]=\"!isInFallbackBranch\">\r\n @if (!!isInFallbackBranch) {\r\n <div class=\"branch-subtext fallback\"\r\n [appTooltip]=\"'If other branches are not met, the alternative branch will be executed'\"\r\n [showAnyway]=\"true\" [position]=\"'above'\">\r\n If other branches are not met, the alternative branch will be executed\r\n </div>\r\n } @else {\r\n <div class=\"step-subtext branch-subtext\" (click)=\"openConditionEditor()\">Set conditions</div>\r\n <div><i class=\"feather-chevron-right\"></i></div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n \r\n @default() {\r\n <div class=\"wf-step-container workflow-box {{ step.type.toLowerCase() }}\">\r\n\r\n <div class=\"step-wrapper\">\r\n \r\n <div class=\"step-header\" [class.edit-mode]=\"stepNameEditMode\">\r\n @if (stepNameEditMode) {\r\n <div class=\"input-wrapper\">\r\n <input class=\"form-control\" \r\n (blur)=\"onInputBlur()\" \r\n [(ngModel)]=\"step.name\" \r\n (ngModelChange)=\"onStepNameChanged($event)\" \r\n #input>\r\n </div>\r\n } @else {\r\n <div class=\"step-name-wrapper\">\r\n <div\r\n class=\"step-name pointer\"\r\n (click)=\"switchToNameEditMode()\"\r\n #stepName>\r\n {{ step.name }}\r\n </div>\r\n </div>\r\n \r\n <div class=\"step-delete pointer\" (click)=\"onDeleteStep()\">\r\n <i class=\"feather-x\"></i>\r\n </div>\r\n }\r\n </div>\r\n \r\n <div class=\"step-set-config pointer\" (click)=\"openNoneBranchRelatedEditor()\">\r\n <div class=\"step-subtext pointer\" [class.configurated]=\"!!step.config\">{{ step.label }}</div>\r\n <div><i class=\"feather-chevron-right\"></i></div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n}\r\n \r\n@if (step.type !== enumType.End) {\r\n <wf-bottom-v-insert\r\n [currentContext]=\"{ branchId: step.branchId, index: index + 1 }\"\r\n [currentStep]=\"step\"\r\n ></wf-bottom-v-insert>\r\n}\r\n ", styles: [".wf-workflow-canvas-container{--standard-connector-height: 90px;--print-area-scale: 1;padding-top:50px;padding-bottom:50px;background-color:#f2f3f5;position:relative;overflow:auto}.wf-workflow-canvas-container .zoom-tools{display:block;position:absolute;left:15px;z-index:1}.wf-workflow-canvas-container .zoom-tools .tools-wrapper{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;background-color:#f9fafb;box-shadow:0 1px 3px #0000001a}.wf-workflow-canvas-container .zoom-tools .tools-wrapper>*{cursor:pointer}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn{background:none;border:none;padding:6px;cursor:pointer;transition:background-color .2s}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn:hover{background-color:#e5e7eb}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-label{background:none;border:none;padding:6px 8px;cursor:default}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .universe-icon{font-size:16px;display:inline-flex;align-items:center;justify-content:center}.wf-workflow-canvas-container .scroll-container{display:block;width:var(--width);height:var(--height);overflow-x:auto}.wf-workflow-canvas-container .canvas{display:flex;flex-direction:column;align-items:center;position:relative}.wf-workflow-canvas-container .canvas.is-dragging *{-webkit-user-select:none;user-select:none}.wf-workflow-canvas-container .print-area{transform:scale(var(--print-area-scale));transition:.2s linear}.wf-workflow-canvas-container .step{text-align:center;position:relative}.wf-workflow-canvas-container .canvas-top-tool{position:absolute;display:block;top:15px;left:15px;box-shadow:0 0 4px #0000000d}.wf-workflow-canvas-container .canvas-top-tool button{border-radius:0;height:30px;font-size:13px}.workflow-box{width:220px;min-height:85px;max-height:100px;padding:0 4px 4px;box-shadow:0 0 4px #0000000d}.workflow-box.submit,.workflow-box.end{background-color:#a9b4cd}.workflow-box.approval{background-color:#f80}.workflow-box.cc{background-color:#3370ff}.workflow-box.handle{background-color:#935af6}.connector{font-size:24px;color:#888}.plus-btn{font-size:18px;background:#fff;border:1px solid #ccc;border-radius:9999px;width:28px;height:28px;cursor:pointer}.insert-menu{background:#fff;border:1px solid #ddd;border-radius:6px;padding:8px;margin-top:6px;box-shadow:0 2px 8px #0000001a;display:flex;flex-direction:column;gap:6px;z-index:10}.insert-menu div{cursor:pointer;font-size:14px;padding:2px 6px}.insert-menu .cancel{color:red}.branch-column{position:relative}.branch-column .branch-column-inner{width:100%;display:flex;flex-direction:column;align-items:center}.wf-branch-group-container,.wf-branch-group-container .branch-group{position:relative}.wf-branch-group-container .branch-group .branch-column{display:table-cell;min-width:220px;vertical-align:top;padding:0 12px}.wf-branch-group-container .branch-group .branch-column .vertical-bridge-line{position:absolute;width:2px;background-color:#d9d9d9;z-index:2;pointer-events:none}.wf-branch-group-container .branch-group .horizontal-bridge-line{position:absolute;height:2px;background-color:#d9d9d9;pointer-events:none;z-index:1}.wf-branch-group-container:after{content:\"\";display:block;position:absolute;height:2px;width:calc(100% - 244px);left:122px;bottom:102px}.branch-title{font-weight:700;font-size:14px;margin-bottom:8px}.branch-group-header{display:flex;justify-content:center;margin:12px 0}.add-branch-btn{position:absolute;top:0;width:175px;left:calc(50% - 87.5px);z-index:2;background:#fff;color:#0f172a;border:1px solid #ccc;padding:4px 12px;border-radius:9999px;font-weight:500;cursor:pointer;box-shadow:0 2px 4px #0000000f;text-wrap:nowrap}.workflow-box.submit{background-color:#e0f7fa;border-left:4px solid #00bcd4}.workflow-box.end{background-color:#ede7f6;border-left:4px solid #673ab7}.box.special{font-style:italic;opacity:.9}.bottom-v-container{min-height:65px;width:220px}.wf-bottom-v-insert-container{position:relative;display:flex;flex-direction:column;align-items:center;height:var(--standard-connector-height);width:100%;margin:0}.wf-bottom-v-insert-container .vertical-line{position:absolute;top:0;height:100%;width:2px;background-color:#d9d9d9;z-index:0}.wf-bottom-v-insert-container .plus-container{display:block;position:absolute;border-radius:50%;top:calc(var(--standard-connector-height) / 2 - 16px)}.wf-bottom-v-insert-container .plus-btn{width:32px;height:32px;border-radius:50%;border:none;background:#fff;color:#3b82f6;font-size:20px;box-shadow:.4rem 0 2rem #0000002e;cursor:pointer;display:flex;align-items:center;justify-content:center}.wf-bottom-v-insert-container .plus-btn:hover{background:#f0f8ff;box-shadow:0 0 0 4px #3b82f633}.wf-bottom-v-insert-container.shorter{height:calc(var(--standard-connector-height) - 15px)}.wf-bottom-v-insert-container.shorter .plus-container{display:block;position:absolute;top:calc((var(--standard-connector-height) - 18px) / 2 - 16px)}.wf-bottom-v-insert-container.insert-context .plus-container{outline:#2eb795 solid 2px}.add-branch-inline{position:relative;height:35px;margin-bottom:calc(var(--standard-connector-height) - 17.5px)}.arrow-down-container{display:block;position:absolute;z-index:1;bottom:0}.arrow-down-container .arrow-down{margin-top:5px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:8px solid #d9d9d9}.branch-card-wrapper{position:relative}.branch-card-wrapper .arrow-down-container{top:-12px;left:calc(50% - 5px)}.wf-step-container .step-header{position:relative;display:flex;align-items:center;justify-content:space-between;height:43px;font-size:12px;border-bottom:1px solid #f6f6f7}.wf-step-container .step-header .input-wrapper{padding-top:4px}.wf-step-container .step-header .step-name-wrapper{display:flex;align-items:center;justify-content:flex-start;padding-right:8px}.wf-step-container .step-header .step-name-wrapper .step-name{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:140px;padding-left:4px}.wf-step-container .step-header .step-name-wrapper i{margin-left:2px}.wf-step-container .step-header .step-delete{color:gray;display:none}.wf-step-container .step-header .step-delete i{font-size:24px}.wf-step-container .step-header:hover .step-name-wrapper:after{content:\"\\e95a\";font-family:feather}.wf-step-container .step-header:hover .branch-priority{display:none}.wf-step-container .step-header:hover .step-delete,.wf-step-container .step-header.edit-mode{display:block}.wf-step-container .step-set-config{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;padding:7px 4px;font-size:14px;background-color:#fff;color:gray}.wf-step-container .step-set-config .step-subtext{width:100%;text-align:left}.wf-step-container .step-set-config .step-subtext.configurated{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container{background-color:#fff}.wf-step-container.wf-branch-card-container .branch-header{color:#2eb795;border-bottom:1px solid #f6f6f7}.wf-step-container.wf-branch-card-container .branch-header:before{content:\"\";display:block;position:absolute;height:var(--standard-connector-height);width:2px;background-color:#d9d9d9;left:50%;top:calc(var(--standard-connector-height) * -1)}.wf-step-container.wf-branch-card-container .branch-set-condition{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;color:#3e4759;padding:7px 4px;font-size:14px}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext{width:100%;text-align:left}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext.fallback{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header,.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-set-condition{color:gray}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header .branch-priority{padding-right:4px}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-priority{display:block}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-delete{display:none}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-name-wrapper:after{content:\"\"}.steps-preview{position:fixed;width:390px;height:100vh;background-color:#fff;top:0;left:-390px;overflow-y:auto;transition:left .2s ease-out}.steps-preview.shown{left:0}\n", ""], dependencies: [{ kind: "component", type: WfNodeComponent, selector: "wf-node", inputs: ["branchId", "step", "index", "branchPriority", "stepGroup", "conditionalBranches", "isRootLevelStepGroup", "grandParentSteps", "isInFallbackBranch"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: BridgeLineDirective, selector: "[bridgeLine]", outputs: ["bridgeLinesAdjusted"] }, { kind: "component", type: WfBottomVInsertComponent, selector: "wf-bottom-v-insert", inputs: ["currentContext", "currentStep"], outputs: ["insertStep"] }, { kind: "directive", type: TooltipDirective, selector: "[appTooltip]", inputs: ["color", "backgroundColor", "appTooltip", "showAnyway", "position"] }] }); }
1036
+ }
1037
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfNodeComponent, decorators: [{
1038
+ type: Component,
1039
+ args: [{ selector: 'wf-node', imports: [
1040
+ FormsModule,
1041
+ BridgeLineDirective,
1042
+ LowerCasePipe,
1043
+ WfBottomVInsertComponent,
1044
+ TooltipDirective,
1045
+ ], template: "@switch (step.type) {\r\n\r\n @case (enumType.ConditionalBranch) {\r\n <div class=\"wf-branch-group-container\">\r\n <div \r\n class=\"branch-group\" \r\n #branchGroup \r\n bridgeLine\r\n (bridgeLinesAdjusted)=\"adjustBridgeLines()\"\r\n >\r\n <!-- \uD83D\uDD39 Top Bridge Line -->\r\n <div class=\"horizontal-bridge-line\" #topBridgeLine></div>\r\n\r\n <div class=\"add-branch-inline\">\r\n <button class=\"add-branch-btn\" (click)=\"coreWorkflowService.addBranchToStep(step.id)\">\r\n \uFF0B Add New Branch\r\n </button>\r\n </div>\r\n\r\n \r\n @for (branch of step.branches; track $index; let j = $index) {\r\n <div class=\"branch-column\" #branchColumn>\r\n <div class=\"branch-column-inner\">\r\n \r\n @for (bstep of branch.steps; track $index; let k = $index) {\r\n <wf-node\r\n [branchId]=\"branch.id\"\r\n [branchPriority]=\"branch.priority\"\r\n [step]=\"bstep\"\r\n [conditionalBranches]=\"step.branches || []\"\r\n [stepGroup]=\"branch.steps\"\r\n [grandParentSteps]=\"stepGroup\"\r\n [index]=\"k\"\r\n [isInFallbackBranch]=\"!!branch.isFallback\"\r\n ></wf-node>\r\n }\r\n \r\n </div>\r\n \r\n <div class=\"vertical-bridge-line\"></div>\r\n </div>\r\n }\r\n \r\n <!-- \uD83D\uDD39 Bottom Bridge Line -->\r\n <div class=\"horizontal-bridge-line\" #bottomBridgeLine></div>\r\n </div>\r\n </div>\r\n }\r\n \r\n @case (enumType.BranchCard) {\r\n <div class=\"wf-step-container wf-branch-card-container workflow-box\">\r\n <div class=\"step-wrapper branch-card-wrapper\" [class.fallback]=\"!!isInFallbackBranch\">\r\n <div class=\"arrow-down-container\">\r\n <div class=\"arrow-down\"></div>\r\n </div>\r\n \r\n <div class=\"step-header branch-header\" [class.edit-mode]=\"stepNameEditMode\" #branchHeader>\r\n @if (stepNameEditMode) {\r\n <div class=\"input-wrapper\">\r\n <input class=\"form-control\" \r\n (blur)=\"onInputBlur()\" \r\n [(ngModel)]=\"step.name\"\r\n (ngModelChange)=\"onStepNameChanged($event)\" \r\n #input>\r\n </div>\r\n } @else {\r\n <div class=\"step-name-wrapper branch-name-wrapper\">\r\n <div\r\n class=\"step-name branch-name\"\r\n [class.pointer]=\"!isInFallbackBranch\"\r\n (click)=\"switchToNameEditMode()\"\r\n #branchName>\r\n {{ step.name }}\r\n </div>\r\n \r\n @if (!!isInFallbackBranch) {\r\n <i class=\"ti-info-alt\"\r\n [appTooltip]=\"'This branch is created by default and will only be activated if none of the other branches can be executed.'\"\r\n [showAnyway]=\"true\" [position]=\"'above'\"></i>\r\n }\r\n </div>\r\n \r\n <div class=\"branch-priority\">Priority {{ branchPriority }}</div>\r\n <div class=\"step-delete branch-delete pointer\" (click)=\"onDeleteBranch(branchId)\">\r\n <i class=\"feather-x\"></i>\r\n </div>\r\n }\r\n </div>\r\n \r\n <div class=\"step-set-config branch-set-condition\" [class.pointer]=\"!isInFallbackBranch\">\r\n @if (!!isInFallbackBranch) {\r\n <div class=\"branch-subtext fallback\"\r\n [appTooltip]=\"'If other branches are not met, the alternative branch will be executed'\"\r\n [showAnyway]=\"true\" [position]=\"'above'\">\r\n If other branches are not met, the alternative branch will be executed\r\n </div>\r\n } @else {\r\n <div class=\"step-subtext branch-subtext\" (click)=\"openConditionEditor()\">Set conditions</div>\r\n <div><i class=\"feather-chevron-right\"></i></div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n \r\n @default() {\r\n <div class=\"wf-step-container workflow-box {{ step.type.toLowerCase() }}\">\r\n\r\n <div class=\"step-wrapper\">\r\n \r\n <div class=\"step-header\" [class.edit-mode]=\"stepNameEditMode\">\r\n @if (stepNameEditMode) {\r\n <div class=\"input-wrapper\">\r\n <input class=\"form-control\" \r\n (blur)=\"onInputBlur()\" \r\n [(ngModel)]=\"step.name\" \r\n (ngModelChange)=\"onStepNameChanged($event)\" \r\n #input>\r\n </div>\r\n } @else {\r\n <div class=\"step-name-wrapper\">\r\n <div\r\n class=\"step-name pointer\"\r\n (click)=\"switchToNameEditMode()\"\r\n #stepName>\r\n {{ step.name }}\r\n </div>\r\n </div>\r\n \r\n <div class=\"step-delete pointer\" (click)=\"onDeleteStep()\">\r\n <i class=\"feather-x\"></i>\r\n </div>\r\n }\r\n </div>\r\n \r\n <div class=\"step-set-config pointer\" (click)=\"openNoneBranchRelatedEditor()\">\r\n <div class=\"step-subtext pointer\" [class.configurated]=\"!!step.config\">{{ step.label }}</div>\r\n <div><i class=\"feather-chevron-right\"></i></div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n}\r\n \r\n@if (step.type !== enumType.End) {\r\n <wf-bottom-v-insert\r\n [currentContext]=\"{ branchId: step.branchId, index: index + 1 }\"\r\n [currentStep]=\"step\"\r\n ></wf-bottom-v-insert>\r\n}\r\n ", styles: [".wf-workflow-canvas-container{--standard-connector-height: 90px;--print-area-scale: 1;padding-top:50px;padding-bottom:50px;background-color:#f2f3f5;position:relative;overflow:auto}.wf-workflow-canvas-container .zoom-tools{display:block;position:absolute;left:15px;z-index:1}.wf-workflow-canvas-container .zoom-tools .tools-wrapper{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;background-color:#f9fafb;box-shadow:0 1px 3px #0000001a}.wf-workflow-canvas-container .zoom-tools .tools-wrapper>*{cursor:pointer}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn{background:none;border:none;padding:6px;cursor:pointer;transition:background-color .2s}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn:hover{background-color:#e5e7eb}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-label{background:none;border:none;padding:6px 8px;cursor:default}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .universe-icon{font-size:16px;display:inline-flex;align-items:center;justify-content:center}.wf-workflow-canvas-container .scroll-container{display:block;width:var(--width);height:var(--height);overflow-x:auto}.wf-workflow-canvas-container .canvas{display:flex;flex-direction:column;align-items:center;position:relative}.wf-workflow-canvas-container .canvas.is-dragging *{-webkit-user-select:none;user-select:none}.wf-workflow-canvas-container .print-area{transform:scale(var(--print-area-scale));transition:.2s linear}.wf-workflow-canvas-container .step{text-align:center;position:relative}.wf-workflow-canvas-container .canvas-top-tool{position:absolute;display:block;top:15px;left:15px;box-shadow:0 0 4px #0000000d}.wf-workflow-canvas-container .canvas-top-tool button{border-radius:0;height:30px;font-size:13px}.workflow-box{width:220px;min-height:85px;max-height:100px;padding:0 4px 4px;box-shadow:0 0 4px #0000000d}.workflow-box.submit,.workflow-box.end{background-color:#a9b4cd}.workflow-box.approval{background-color:#f80}.workflow-box.cc{background-color:#3370ff}.workflow-box.handle{background-color:#935af6}.connector{font-size:24px;color:#888}.plus-btn{font-size:18px;background:#fff;border:1px solid #ccc;border-radius:9999px;width:28px;height:28px;cursor:pointer}.insert-menu{background:#fff;border:1px solid #ddd;border-radius:6px;padding:8px;margin-top:6px;box-shadow:0 2px 8px #0000001a;display:flex;flex-direction:column;gap:6px;z-index:10}.insert-menu div{cursor:pointer;font-size:14px;padding:2px 6px}.insert-menu .cancel{color:red}.branch-column{position:relative}.branch-column .branch-column-inner{width:100%;display:flex;flex-direction:column;align-items:center}.wf-branch-group-container,.wf-branch-group-container .branch-group{position:relative}.wf-branch-group-container .branch-group .branch-column{display:table-cell;min-width:220px;vertical-align:top;padding:0 12px}.wf-branch-group-container .branch-group .branch-column .vertical-bridge-line{position:absolute;width:2px;background-color:#d9d9d9;z-index:2;pointer-events:none}.wf-branch-group-container .branch-group .horizontal-bridge-line{position:absolute;height:2px;background-color:#d9d9d9;pointer-events:none;z-index:1}.wf-branch-group-container:after{content:\"\";display:block;position:absolute;height:2px;width:calc(100% - 244px);left:122px;bottom:102px}.branch-title{font-weight:700;font-size:14px;margin-bottom:8px}.branch-group-header{display:flex;justify-content:center;margin:12px 0}.add-branch-btn{position:absolute;top:0;width:175px;left:calc(50% - 87.5px);z-index:2;background:#fff;color:#0f172a;border:1px solid #ccc;padding:4px 12px;border-radius:9999px;font-weight:500;cursor:pointer;box-shadow:0 2px 4px #0000000f;text-wrap:nowrap}.workflow-box.submit{background-color:#e0f7fa;border-left:4px solid #00bcd4}.workflow-box.end{background-color:#ede7f6;border-left:4px solid #673ab7}.box.special{font-style:italic;opacity:.9}.bottom-v-container{min-height:65px;width:220px}.wf-bottom-v-insert-container{position:relative;display:flex;flex-direction:column;align-items:center;height:var(--standard-connector-height);width:100%;margin:0}.wf-bottom-v-insert-container .vertical-line{position:absolute;top:0;height:100%;width:2px;background-color:#d9d9d9;z-index:0}.wf-bottom-v-insert-container .plus-container{display:block;position:absolute;border-radius:50%;top:calc(var(--standard-connector-height) / 2 - 16px)}.wf-bottom-v-insert-container .plus-btn{width:32px;height:32px;border-radius:50%;border:none;background:#fff;color:#3b82f6;font-size:20px;box-shadow:.4rem 0 2rem #0000002e;cursor:pointer;display:flex;align-items:center;justify-content:center}.wf-bottom-v-insert-container .plus-btn:hover{background:#f0f8ff;box-shadow:0 0 0 4px #3b82f633}.wf-bottom-v-insert-container.shorter{height:calc(var(--standard-connector-height) - 15px)}.wf-bottom-v-insert-container.shorter .plus-container{display:block;position:absolute;top:calc((var(--standard-connector-height) - 18px) / 2 - 16px)}.wf-bottom-v-insert-container.insert-context .plus-container{outline:#2eb795 solid 2px}.add-branch-inline{position:relative;height:35px;margin-bottom:calc(var(--standard-connector-height) - 17.5px)}.arrow-down-container{display:block;position:absolute;z-index:1;bottom:0}.arrow-down-container .arrow-down{margin-top:5px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:8px solid #d9d9d9}.branch-card-wrapper{position:relative}.branch-card-wrapper .arrow-down-container{top:-12px;left:calc(50% - 5px)}.wf-step-container .step-header{position:relative;display:flex;align-items:center;justify-content:space-between;height:43px;font-size:12px;border-bottom:1px solid #f6f6f7}.wf-step-container .step-header .input-wrapper{padding-top:4px}.wf-step-container .step-header .step-name-wrapper{display:flex;align-items:center;justify-content:flex-start;padding-right:8px}.wf-step-container .step-header .step-name-wrapper .step-name{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:140px;padding-left:4px}.wf-step-container .step-header .step-name-wrapper i{margin-left:2px}.wf-step-container .step-header .step-delete{color:gray;display:none}.wf-step-container .step-header .step-delete i{font-size:24px}.wf-step-container .step-header:hover .step-name-wrapper:after{content:\"\\e95a\";font-family:feather}.wf-step-container .step-header:hover .branch-priority{display:none}.wf-step-container .step-header:hover .step-delete,.wf-step-container .step-header.edit-mode{display:block}.wf-step-container .step-set-config{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;padding:7px 4px;font-size:14px;background-color:#fff;color:gray}.wf-step-container .step-set-config .step-subtext{width:100%;text-align:left}.wf-step-container .step-set-config .step-subtext.configurated{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container{background-color:#fff}.wf-step-container.wf-branch-card-container .branch-header{color:#2eb795;border-bottom:1px solid #f6f6f7}.wf-step-container.wf-branch-card-container .branch-header:before{content:\"\";display:block;position:absolute;height:var(--standard-connector-height);width:2px;background-color:#d9d9d9;left:50%;top:calc(var(--standard-connector-height) * -1)}.wf-step-container.wf-branch-card-container .branch-set-condition{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;color:#3e4759;padding:7px 4px;font-size:14px}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext{width:100%;text-align:left}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext.fallback{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header,.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-set-condition{color:gray}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header .branch-priority{padding-right:4px}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-priority{display:block}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-delete{display:none}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-name-wrapper:after{content:\"\"}.steps-preview{position:fixed;width:390px;height:100vh;background-color:#fff;top:0;left:-390px;overflow-y:auto;transition:left .2s ease-out}.steps-preview.shown{left:0}\n"] }]
1046
+ }], propDecorators: { branchId: [{
1047
+ type: Input,
1048
+ args: [{ required: true }]
1049
+ }], step: [{
1050
+ type: Input,
1051
+ args: [{ required: true }]
1052
+ }], index: [{
1053
+ type: Input,
1054
+ args: [{ required: true }]
1055
+ }], branchPriority: [{
1056
+ type: Input,
1057
+ args: [{ required: true }]
1058
+ }], stepGroup: [{
1059
+ type: Input,
1060
+ args: [{ required: true }]
1061
+ }], conditionalBranches: [{
1062
+ type: Input
1063
+ }], isRootLevelStepGroup: [{
1064
+ type: Input
1065
+ }], grandParentSteps: [{
1066
+ type: Input
1067
+ }], isInFallbackBranch: [{
1068
+ type: Input
1069
+ }], branchHeader: [{
1070
+ type: ViewChild,
1071
+ args: ['branchHeader']
1072
+ }], branchName: [{
1073
+ type: ViewChild,
1074
+ args: ['branchName']
1075
+ }], input: [{
1076
+ type: ViewChild,
1077
+ args: ['input']
1078
+ }], branchGroupRef: [{
1079
+ type: ViewChild,
1080
+ args: ['branchGroup']
1081
+ }], topBridgeLineRef: [{
1082
+ type: ViewChild,
1083
+ args: ['topBridgeLine']
1084
+ }], bottomBridgeLineRef: [{
1085
+ type: ViewChild,
1086
+ args: ['bottomBridgeLine']
1087
+ }], branchColumnRefs: [{
1088
+ type: ViewChildren,
1089
+ args: ['branchColumn']
1090
+ }] } });
1091
+
1092
+ class WfStepsPreviewComponent extends BaseComponent {
1093
+ constructor() {
1094
+ super(...arguments);
1095
+ this.wfs = inject(CoreWorkflowService);
1096
+ }
1097
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfStepsPreviewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1098
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: WfStepsPreviewComponent, isStandalone: true, selector: "wf-steps-preview", usesInheritance: true, ngImport: i0, template: "<div class=\"wf-steps-preview-container\">\r\n\r\n @if (wfs.$stepsJsonPreview()) {\r\n <div class=\"steps-tool\">\r\n <button type=\"button\" class=\"btn-save-steps btn btn-secondary\" (click)=\"wfs.saveCurrentSteps()\">Save</button>\r\n </div>\r\n <pre class=\"json-preview\">{{ wfs.$stepsJsonPreview() }}</pre>\r\n } @else {\r\n <div class=\"empty-preview\">No steps to preview</div>\r\n }\r\n\r\n</div>", styles: [".wf-steps-preview-container{padding:15px;box-shadow:var(--decoration-box-shadow)}.wf-steps-preview-container .steps-tool{margin-bottom:15px}.wf-steps-preview-container .steps-tool .btn-save-steps{border-radius:0;background-color:#000;color:#fff}.wf-steps-preview-container .json-preview{background-color:#fff;color:#333;padding:1rem 1.5rem;font-family:Fira Code,monospace;font-size:.85rem;overflow-x:auto;line-height:1.5;width:100%;margin:0;white-space:pre-wrap;word-break:break-word}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1099
+ }
1100
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfStepsPreviewComponent, decorators: [{
1101
+ type: Component,
1102
+ args: [{ selector: 'wf-steps-preview', changeDetection: ChangeDetectionStrategy.OnPush, imports: [], template: "<div class=\"wf-steps-preview-container\">\r\n\r\n @if (wfs.$stepsJsonPreview()) {\r\n <div class=\"steps-tool\">\r\n <button type=\"button\" class=\"btn-save-steps btn btn-secondary\" (click)=\"wfs.saveCurrentSteps()\">Save</button>\r\n </div>\r\n <pre class=\"json-preview\">{{ wfs.$stepsJsonPreview() }}</pre>\r\n } @else {\r\n <div class=\"empty-preview\">No steps to preview</div>\r\n }\r\n\r\n</div>", styles: [".wf-steps-preview-container{padding:15px;box-shadow:var(--decoration-box-shadow)}.wf-steps-preview-container .steps-tool{margin-bottom:15px}.wf-steps-preview-container .steps-tool .btn-save-steps{border-radius:0;background-color:#000;color:#fff}.wf-steps-preview-container .json-preview{background-color:#fff;color:#333;padding:1rem 1.5rem;font-family:Fira Code,monospace;font-size:.85rem;overflow-x:auto;line-height:1.5;width:100%;margin:0;white-space:pre-wrap;word-break:break-word}\n"] }]
1103
+ }] });
1104
+
1105
+ class WfWorkflowCanvasComponent extends BaseComponent {
1106
+ constructor(mls) {
1107
+ super(mls);
1108
+ this.mls = mls;
1109
+ this.$width = signal(0);
1110
+ this.$height = signal(0);
1111
+ this.$container = viewChild('container');
1112
+ this.$printArea = viewChild('printArea');
1113
+ this.$zoomTools = viewChild('zoomTools');
1114
+ this.$parent = viewChild('parent');
1115
+ this.hotKeys = ['F3', 'Escape'];
1116
+ this.enumType = EnumWorkflowStepType;
1117
+ this.ROOT_BRANCH_ID = ROOT_BRANCH_ID;
1118
+ this.wfs = inject(CoreWorkflowService);
1119
+ this.$steps = this.wfs.$currentSteps;
1120
+ this.applicationHelpService = inject(ApplicationHelpService);
1121
+ this.domService = inject(DomService);
1122
+ this.insertIndex = null;
1123
+ this.$previewZIndex = signal(this.domService.getMaxZIndex() + 1);
1124
+ this.$scale = signal(1);
1125
+ this.$scalePercent = computed(() => `${Math.round(this.$scale() * 100)}%`);
1126
+ this.cdr = inject(ChangeDetectorRef);
1127
+ this.$mouseDown = signal(false);
1128
+ this.$isDragging = computed(() => this.$mouseDown());
1129
+ this.$startX = signal(undefined);
1130
+ this.$scrollLeft = signal(undefined);
1131
+ this.$startY = signal(undefined);
1132
+ this.$scrollTop = signal(undefined);
1133
+ effect(() => {
1134
+ this.$container()?.nativeElement.style.setProperty('--standard-connector-height', this.wfs.standardConnectorHeight + 'px');
1135
+ });
1136
+ this.subscriptions.push(this.applicationHelpService.activeKey$
1137
+ .pipe(distinctUntilChanged())
1138
+ .subscribe(x => {
1139
+ console.log("x", x);
1140
+ switch (x) {
1141
+ case 'F3':
1142
+ this.wfs.$showCurrentStepsPreview.set(true);
1143
+ break;
1144
+ case 'Escape':
1145
+ this.wfs.$currentStep.set(null);
1146
+ this.wfs.$showCurrentStepsPreview.set(false);
1147
+ this.wfs.$showStepConfig.set(false);
1148
+ break;
1149
+ }
1150
+ }));
1151
+ }
1152
+ startDragging(e, flag) {
1153
+ this.$mouseDown.set(true);
1154
+ this.$startX.set(e.pageX - this.$parent()?.nativeElement.offsetLeft);
1155
+ this.$scrollLeft.set(this.$parent()?.nativeElement.scrollLeft);
1156
+ this.$startY.set(e.pageY - this.$parent()?.nativeElement.offsetTop);
1157
+ this.$scrollTop.set(this.$parent()?.nativeElement.scrollTop);
1158
+ }
1159
+ stopDragging(e, flag) {
1160
+ this.$mouseDown.set(false);
1161
+ }
1162
+ moveEvent(e) {
1163
+ e.preventDefault();
1164
+ if (!this.$mouseDown()) {
1165
+ return;
1166
+ }
1167
+ const x = e.pageX - this.$parent()?.nativeElement.offsetLeft;
1168
+ const scrollX = x - this.$startX();
1169
+ this.$parent().nativeElement.scrollLeft = this.$scrollLeft() - scrollX;
1170
+ const y = e.pageY - this.$parent()?.nativeElement.offsetTop;
1171
+ const scrollY = y - this.$startY();
1172
+ this.$parent().nativeElement.scrollTop = this.$scrollTop() - scrollY;
1173
+ }
1174
+ ngAfterViewInit() {
1175
+ }
1176
+ findBranchById(branchId, steps = this.wfs.$currentSteps()) {
1177
+ for (const step of steps) {
1178
+ if (step.type === EnumWorkflowStepType.ConditionalBranch && step.branches) {
1179
+ // ✅ step.branches is now just an array
1180
+ const found = step.branches.find(b => b.id === branchId);
1181
+ if (found)
1182
+ return found;
1183
+ // 🔁 Recurse into steps of each branch
1184
+ for (const branch of step.branches) {
1185
+ const deep = this.findBranchById(branchId, branch.steps);
1186
+ if (deep)
1187
+ return deep;
1188
+ }
1189
+ }
1190
+ }
1191
+ return undefined;
1192
+ }
1193
+ safeInsertStep(branchId, index, newStep) {
1194
+ if (branchId === null || branchId === ROOT_BRANCH_ID) {
1195
+ this.$steps.update(steps => {
1196
+ const copy = [...steps];
1197
+ copy.splice(index, 0, newStep);
1198
+ return copy;
1199
+ });
1200
+ return;
1201
+ }
1202
+ const branch = this.findBranchById(branchId);
1203
+ if (!branch) {
1204
+ console.warn(`❗ Cannot insert: Branch with ID "${branchId}" not found.`);
1205
+ return;
1206
+ }
1207
+ branch.steps.splice(index, 0, newStep);
1208
+ }
1209
+ insertStep(event) {
1210
+ const { type, index, branchId } = event;
1211
+ if (!branchId) {
1212
+ console.error(`insertStep error: without branchId`);
1213
+ return;
1214
+ }
1215
+ ;
1216
+ let newStep;
1217
+ switch (type) {
1218
+ case EnumWorkflowStepType.Approval:
1219
+ newStep = this.wfs.createStep(type, branchId, 'Set approver');
1220
+ break;
1221
+ case EnumWorkflowStepType.CC:
1222
+ newStep = this.wfs.createStep(type, branchId, 'Set cc recipients');
1223
+ break;
1224
+ case EnumWorkflowStepType.Handle:
1225
+ newStep = this.wfs.createStep(type, branchId, 'Set handler');
1226
+ break;
1227
+ case EnumWorkflowStepType.ConditionalBranch:
1228
+ newStep = this.wfs.createConditionalBranchStep(branchId);
1229
+ break;
1230
+ default:
1231
+ return;
1232
+ }
1233
+ this.safeInsertStep(branchId, index, newStep);
1234
+ this.wfs.insertContext$.next(null);
1235
+ }
1236
+ showInsertInBranch(context) {
1237
+ this.wfs.insertContext$.next(context);
1238
+ }
1239
+ insertIntoBranch(event) {
1240
+ const { branchId, type, index } = event;
1241
+ if (!branchId) {
1242
+ console.error(`insertStep error: missing branchId`);
1243
+ return;
1244
+ }
1245
+ // 🔍 Find the branch that matches the given ID
1246
+ const branch = this.findBranchById(branchId);
1247
+ if (!branch) {
1248
+ console.warn(`Branch not found: ${branchId}`);
1249
+ return;
1250
+ }
1251
+ let newStep;
1252
+ switch (type) {
1253
+ case EnumWorkflowStepType.Approval:
1254
+ newStep = this.wfs.createStep(type, branchId, 'Set approver');
1255
+ break;
1256
+ case EnumWorkflowStepType.CC:
1257
+ newStep = this.wfs.createStep(type, branchId, 'Set cc recipients');
1258
+ break;
1259
+ case EnumWorkflowStepType.Handle:
1260
+ newStep = this.wfs.createStep(type, branchId, 'Set handler');
1261
+ break;
1262
+ case EnumWorkflowStepType.ConditionalBranch:
1263
+ newStep = this.wfs.createConditionalBranchStep(branchId);
1264
+ break;
1265
+ default:
1266
+ console.warn(`Unsupported step type: ${type}`);
1267
+ return;
1268
+ }
1269
+ // ✅ Insert into the correct step list
1270
+ branch.steps.splice(index, 0, newStep);
1271
+ // 🧹 Clear insert state
1272
+ this.wfs.insertContext$.next(null);
1273
+ }
1274
+ findStepRecursive(steps, targetId) {
1275
+ for (const step of steps) {
1276
+ if (step.id === targetId)
1277
+ return step;
1278
+ // ✅ New model: step.branches is directly an array
1279
+ if (step.type === EnumWorkflowStepType.ConditionalBranch && step.branches) {
1280
+ for (const branch of step.branches) {
1281
+ const found = this.findStepRecursive(branch.steps, targetId);
1282
+ if (found)
1283
+ return found;
1284
+ }
1285
+ }
1286
+ }
1287
+ return null;
1288
+ }
1289
+ addBranchToConditional(conditionalStepId) {
1290
+ const conditional = this.findStepRecursive(this.wfs.$currentSteps(), conditionalStepId);
1291
+ if (!conditional || conditional.type !== EnumWorkflowStepType.ConditionalBranch || !conditional.branches)
1292
+ return;
1293
+ const branches = conditional.branches;
1294
+ const newBranchId = crypto.randomUUID();
1295
+ const name = `Condition ${branches.length}`;
1296
+ const newBranch = {
1297
+ id: newBranchId,
1298
+ name,
1299
+ priority: branches.length + 1,
1300
+ steps: [
1301
+ {
1302
+ id: `pseudo-${newBranchId}`,
1303
+ name: `pseudo-${newBranchId}`,
1304
+ branchId: newBranchId,
1305
+ type: EnumWorkflowStepType.BranchCard,
1306
+ label: name,
1307
+ isPseudo: true
1308
+ },
1309
+ {
1310
+ id: crypto.randomUUID(),
1311
+ name: `default-approval-${branches.length + 1}`,
1312
+ branchId: newBranchId,
1313
+ type: EnumWorkflowStepType.Approval,
1314
+ label: `Approve ${branches.length + 1}`
1315
+ }
1316
+ ]
1317
+ };
1318
+ const fallbackIndex = branches.findIndex(b => b.isFallback);
1319
+ if (fallbackIndex !== -1) {
1320
+ branches.splice(fallbackIndex, 0, newBranch);
1321
+ }
1322
+ else {
1323
+ branches.push(newBranch);
1324
+ }
1325
+ this.wfs.autoReassignPriorities(branches);
1326
+ }
1327
+ deleteBranchGroup(stepId) {
1328
+ const step = this.wfs.$currentSteps().find(s => s.id === stepId);
1329
+ if (step?.type === EnumWorkflowStepType.ConditionalBranch) {
1330
+ const index = this.wfs.$currentSteps().indexOf(step);
1331
+ if (index !== -1) {
1332
+ this.$steps.update(steps => {
1333
+ const copy = [...steps];
1334
+ copy.splice(index, 1);
1335
+ return copy;
1336
+ });
1337
+ }
1338
+ }
1339
+ }
1340
+ tempOnLabelClicked() {
1341
+ this.wfs.$showStepConfig.set(true);
1342
+ }
1343
+ onInsert(event) {
1344
+ // Delegate to CoreWorkflowService or your working tree logic
1345
+ this.insertStep(event);
1346
+ this.clearInsertContext(); // clean up
1347
+ }
1348
+ clearInsertContext() {
1349
+ this.wfs.insertContext$.next(null);
1350
+ }
1351
+ showStepsJSON() {
1352
+ this.wfs.$showCurrentStepsPreview.set(true);
1353
+ }
1354
+ zoonIn() {
1355
+ this.$scale.set(this.$scale() * 1.1);
1356
+ this.$container().nativeElement.style.setProperty('--print-area-scale', this.$scale());
1357
+ }
1358
+ zoonOut() {
1359
+ this.$scale.set(this.$scale() / 1.1);
1360
+ this.$container().nativeElement.style.setProperty('--print-area-scale', this.$scale());
1361
+ }
1362
+ zoonFeat() {
1363
+ this.$scale.set(1);
1364
+ this.$container().nativeElement.style.setProperty('--print-area-scale', this.$scale());
1365
+ }
1366
+ ngOnDestroy() {
1367
+ this.subscriptions.forEach(x => x?.unsubscribe());
1368
+ }
1369
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfWorkflowCanvasComponent, deps: [{ token: MultiLanguageService }], target: i0.ɵɵFactoryTarget.Component }); }
1370
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: WfWorkflowCanvasComponent, isStandalone: true, selector: "wf-workflow-canvas", viewQueries: [{ propertyName: "$container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "$printArea", first: true, predicate: ["printArea"], descendants: true, isSignal: true }, { propertyName: "$zoomTools", first: true, predicate: ["zoomTools"], descendants: true, isSignal: true }, { propertyName: "$parent", first: true, predicate: ["parent"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"wf-workflow-canvas-container\" #container [hotKeys]=\"hotKeys\"\r\n (mousedown)=\"startDragging($event, false)\"\r\n (mouseup)=\"stopDragging($event, false)\" \r\n (mouseleave)=\"stopDragging($event, false)\" \r\n (mousemove)=\"moveEvent($event)\"\r\n>\r\n\r\n <div class=\"canvas-top-tool\">\r\n <button type=\"button\" class=\"btn btn-secondary\"\r\n [appTooltip]=\"'Press F3 to show, Escape to hide'\"\r\n [showAnyway]=\"true\"\r\n (click)=\"showStepsJSON()\"\r\n >Show JSON</button>\r\n </div> \r\n\r\n <div class=\"zoom-tools\" #zoomTools>\r\n <div class=\"tools-wrapper\">\r\n <button type=\"button\" class=\"zoom-btn\" (click)=\"zoonOut()\">\r\n <span class=\"universe-icon\"><i class=\"feather-zoom-out\"></i></span>\r\n </button>\r\n <button type=\"button\" class=\"zoom-label\">\r\n {{ $scalePercent() }}\r\n </button>\r\n <button type=\"button\" class=\"zoom-btn\" (click)=\"zoonIn()\">\r\n <span class=\"universe-icon\"><i class=\"feather-zoom-in\"></i></span>\r\n </button>\r\n <button type=\"button\" class=\"zoom-btn\" (click)=\"zoonFeat()\">\r\n <span class=\"universe-icon\"><i class=\"feather-zap\"></i></span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"scroll-container\" #parent [ngStyle]=\"{ cursor: $mouseDown() ? 'all-scroll' : 'unset', width: $width() ? $width() + 'px' : '100%', height: $height() ? $height() + 'px' : 'unset'}\">\r\n\r\n <div class=\"canvas print-area\" #printArea [class.is-dragging]=\"$isDragging()\">\r\n\r\n @for (step of wfs.$currentSteps(); track $index; let i = $index) {\r\n <div class=\"step\">\r\n <wf-node\r\n [branchId]=\"'root'\"\r\n [branchPriority]=\"1\"\r\n [step]=\"step\"\r\n [stepGroup]=\"wfs.$currentSteps()\"\r\n [index]=\"i\"\r\n [isRootLevelStepGroup]=\"true\"\r\n ></wf-node>\r\n </div>\r\n }\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n @if (!!(wfs.insertContext$ | async)) {\r\n <wf-insert-menu (insert)=\"insertStep($event)\"></wf-insert-menu>\r\n }\r\n\r\n <wf-step-config-shell></wf-step-config-shell>\r\n\r\n <div class=\"steps-preview\" [class.shown]=\"wfs.$showCurrentStepsPreview()\"\r\n [ngStyle]=\"{\r\n zIndex: $previewZIndex()\r\n }\"\r\n >\r\n <wf-steps-preview></wf-steps-preview>\r\n </div>\r\n \r\n\r\n</div>", styles: [".wf-workflow-canvas-container{--standard-connector-height: 90px;--print-area-scale: 1;padding-top:50px;padding-bottom:50px;background-color:#f2f3f5;position:relative;overflow:auto}.wf-workflow-canvas-container .zoom-tools{display:block;position:absolute;left:15px;z-index:1}.wf-workflow-canvas-container .zoom-tools .tools-wrapper{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;background-color:#f9fafb;box-shadow:0 1px 3px #0000001a}.wf-workflow-canvas-container .zoom-tools .tools-wrapper>*{cursor:pointer}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn{background:none;border:none;padding:6px;cursor:pointer;transition:background-color .2s}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn:hover{background-color:#e5e7eb}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-label{background:none;border:none;padding:6px 8px;cursor:default}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .universe-icon{font-size:16px;display:inline-flex;align-items:center;justify-content:center}.wf-workflow-canvas-container .scroll-container{display:block;width:var(--width);height:var(--height);overflow-x:auto}.wf-workflow-canvas-container .canvas{display:flex;flex-direction:column;align-items:center;position:relative}.wf-workflow-canvas-container .canvas.is-dragging *{-webkit-user-select:none;user-select:none}.wf-workflow-canvas-container .print-area{transform:scale(var(--print-area-scale));transition:.2s linear}.wf-workflow-canvas-container .step{text-align:center;position:relative}.wf-workflow-canvas-container .canvas-top-tool{position:absolute;display:block;top:15px;left:15px;box-shadow:0 0 4px #0000000d}.wf-workflow-canvas-container .canvas-top-tool button{border-radius:0;height:30px;font-size:13px}.workflow-box{width:220px;min-height:85px;max-height:100px;padding:0 4px 4px;box-shadow:0 0 4px #0000000d}.workflow-box.submit,.workflow-box.end{background-color:#a9b4cd}.workflow-box.approval{background-color:#f80}.workflow-box.cc{background-color:#3370ff}.workflow-box.handle{background-color:#935af6}.connector{font-size:24px;color:#888}.plus-btn{font-size:18px;background:#fff;border:1px solid #ccc;border-radius:9999px;width:28px;height:28px;cursor:pointer}.insert-menu{background:#fff;border:1px solid #ddd;border-radius:6px;padding:8px;margin-top:6px;box-shadow:0 2px 8px #0000001a;display:flex;flex-direction:column;gap:6px;z-index:10}.insert-menu div{cursor:pointer;font-size:14px;padding:2px 6px}.insert-menu .cancel{color:red}.branch-column{position:relative}.branch-column .branch-column-inner{width:100%;display:flex;flex-direction:column;align-items:center}.wf-branch-group-container,.wf-branch-group-container .branch-group{position:relative}.wf-branch-group-container .branch-group .branch-column{display:table-cell;min-width:220px;vertical-align:top;padding:0 12px}.wf-branch-group-container .branch-group .branch-column .vertical-bridge-line{position:absolute;width:2px;background-color:#d9d9d9;z-index:2;pointer-events:none}.wf-branch-group-container .branch-group .horizontal-bridge-line{position:absolute;height:2px;background-color:#d9d9d9;pointer-events:none;z-index:1}.wf-branch-group-container:after{content:\"\";display:block;position:absolute;height:2px;width:calc(100% - 244px);left:122px;bottom:102px}.branch-title{font-weight:700;font-size:14px;margin-bottom:8px}.branch-group-header{display:flex;justify-content:center;margin:12px 0}.add-branch-btn{position:absolute;top:0;width:175px;left:calc(50% - 87.5px);z-index:2;background:#fff;color:#0f172a;border:1px solid #ccc;padding:4px 12px;border-radius:9999px;font-weight:500;cursor:pointer;box-shadow:0 2px 4px #0000000f;text-wrap:nowrap}.workflow-box.submit{background-color:#e0f7fa;border-left:4px solid #00bcd4}.workflow-box.end{background-color:#ede7f6;border-left:4px solid #673ab7}.box.special{font-style:italic;opacity:.9}.bottom-v-container{min-height:65px;width:220px}.wf-bottom-v-insert-container{position:relative;display:flex;flex-direction:column;align-items:center;height:var(--standard-connector-height);width:100%;margin:0}.wf-bottom-v-insert-container .vertical-line{position:absolute;top:0;height:100%;width:2px;background-color:#d9d9d9;z-index:0}.wf-bottom-v-insert-container .plus-container{display:block;position:absolute;border-radius:50%;top:calc(var(--standard-connector-height) / 2 - 16px)}.wf-bottom-v-insert-container .plus-btn{width:32px;height:32px;border-radius:50%;border:none;background:#fff;color:#3b82f6;font-size:20px;box-shadow:.4rem 0 2rem #0000002e;cursor:pointer;display:flex;align-items:center;justify-content:center}.wf-bottom-v-insert-container .plus-btn:hover{background:#f0f8ff;box-shadow:0 0 0 4px #3b82f633}.wf-bottom-v-insert-container.shorter{height:calc(var(--standard-connector-height) - 15px)}.wf-bottom-v-insert-container.shorter .plus-container{display:block;position:absolute;top:calc((var(--standard-connector-height) - 18px) / 2 - 16px)}.wf-bottom-v-insert-container.insert-context .plus-container{outline:#2eb795 solid 2px}.add-branch-inline{position:relative;height:35px;margin-bottom:calc(var(--standard-connector-height) - 17.5px)}.arrow-down-container{display:block;position:absolute;z-index:1;bottom:0}.arrow-down-container .arrow-down{margin-top:5px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:8px solid #d9d9d9}.branch-card-wrapper{position:relative}.branch-card-wrapper .arrow-down-container{top:-12px;left:calc(50% - 5px)}.wf-step-container .step-header{position:relative;display:flex;align-items:center;justify-content:space-between;height:43px;font-size:12px;border-bottom:1px solid #f6f6f7}.wf-step-container .step-header .input-wrapper{padding-top:4px}.wf-step-container .step-header .step-name-wrapper{display:flex;align-items:center;justify-content:flex-start;padding-right:8px}.wf-step-container .step-header .step-name-wrapper .step-name{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:140px;padding-left:4px}.wf-step-container .step-header .step-name-wrapper i{margin-left:2px}.wf-step-container .step-header .step-delete{color:gray;display:none}.wf-step-container .step-header .step-delete i{font-size:24px}.wf-step-container .step-header:hover .step-name-wrapper:after{content:\"\\e95a\";font-family:feather}.wf-step-container .step-header:hover .branch-priority{display:none}.wf-step-container .step-header:hover .step-delete,.wf-step-container .step-header.edit-mode{display:block}.wf-step-container .step-set-config{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;padding:7px 4px;font-size:14px;background-color:#fff;color:gray}.wf-step-container .step-set-config .step-subtext{width:100%;text-align:left}.wf-step-container .step-set-config .step-subtext.configurated{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container{background-color:#fff}.wf-step-container.wf-branch-card-container .branch-header{color:#2eb795;border-bottom:1px solid #f6f6f7}.wf-step-container.wf-branch-card-container .branch-header:before{content:\"\";display:block;position:absolute;height:var(--standard-connector-height);width:2px;background-color:#d9d9d9;left:50%;top:calc(var(--standard-connector-height) * -1)}.wf-step-container.wf-branch-card-container .branch-set-condition{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;color:#3e4759;padding:7px 4px;font-size:14px}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext{width:100%;text-align:left}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext.fallback{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header,.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-set-condition{color:gray}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header .branch-priority{padding-right:4px}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-priority{display:block}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-delete{display:none}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-name-wrapper:after{content:\"\"}.steps-preview{position:fixed;width:390px;height:100vh;background-color:#fff;top:0;left:-390px;overflow-y:auto;transition:left .2s ease-out}.steps-preview.shown{left:0}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: HotKeysDirective, selector: "[hotKeys]", inputs: ["hotKeys"] }, { kind: "directive", type: TooltipDirective, selector: "[appTooltip]", inputs: ["color", "backgroundColor", "appTooltip", "showAnyway", "position"] }, { kind: "component", type: WfInsertMenuComponent, selector: "wf-insert-menu", outputs: ["insert"] }, { kind: "component", type: WfStepConfigShellComponent, selector: "wf-step-config-shell" }, { kind: "component", type: WfNodeComponent, selector: "wf-node", inputs: ["branchId", "step", "index", "branchPriority", "stepGroup", "conditionalBranches", "isRootLevelStepGroup", "grandParentSteps", "isInFallbackBranch"] }, { kind: "component", type: WfStepsPreviewComponent, selector: "wf-steps-preview" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1371
+ }
1372
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfWorkflowCanvasComponent, decorators: [{
1373
+ type: Component,
1374
+ args: [{ selector: 'wf-workflow-canvas', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1375
+ AsyncPipe,
1376
+ NgStyle,
1377
+ HotKeysDirective,
1378
+ TooltipDirective,
1379
+ NgTemplateOutlet,
1380
+ LowerCasePipe,
1381
+ WfInsertMenuComponent,
1382
+ WfBottomVInsertComponent,
1383
+ WfInsertMenuComponent,
1384
+ WfStepConfigShellComponent,
1385
+ WfNodeComponent,
1386
+ WfStepsPreviewComponent
1387
+ ], template: "<div class=\"wf-workflow-canvas-container\" #container [hotKeys]=\"hotKeys\"\r\n (mousedown)=\"startDragging($event, false)\"\r\n (mouseup)=\"stopDragging($event, false)\" \r\n (mouseleave)=\"stopDragging($event, false)\" \r\n (mousemove)=\"moveEvent($event)\"\r\n>\r\n\r\n <div class=\"canvas-top-tool\">\r\n <button type=\"button\" class=\"btn btn-secondary\"\r\n [appTooltip]=\"'Press F3 to show, Escape to hide'\"\r\n [showAnyway]=\"true\"\r\n (click)=\"showStepsJSON()\"\r\n >Show JSON</button>\r\n </div> \r\n\r\n <div class=\"zoom-tools\" #zoomTools>\r\n <div class=\"tools-wrapper\">\r\n <button type=\"button\" class=\"zoom-btn\" (click)=\"zoonOut()\">\r\n <span class=\"universe-icon\"><i class=\"feather-zoom-out\"></i></span>\r\n </button>\r\n <button type=\"button\" class=\"zoom-label\">\r\n {{ $scalePercent() }}\r\n </button>\r\n <button type=\"button\" class=\"zoom-btn\" (click)=\"zoonIn()\">\r\n <span class=\"universe-icon\"><i class=\"feather-zoom-in\"></i></span>\r\n </button>\r\n <button type=\"button\" class=\"zoom-btn\" (click)=\"zoonFeat()\">\r\n <span class=\"universe-icon\"><i class=\"feather-zap\"></i></span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"scroll-container\" #parent [ngStyle]=\"{ cursor: $mouseDown() ? 'all-scroll' : 'unset', width: $width() ? $width() + 'px' : '100%', height: $height() ? $height() + 'px' : 'unset'}\">\r\n\r\n <div class=\"canvas print-area\" #printArea [class.is-dragging]=\"$isDragging()\">\r\n\r\n @for (step of wfs.$currentSteps(); track $index; let i = $index) {\r\n <div class=\"step\">\r\n <wf-node\r\n [branchId]=\"'root'\"\r\n [branchPriority]=\"1\"\r\n [step]=\"step\"\r\n [stepGroup]=\"wfs.$currentSteps()\"\r\n [index]=\"i\"\r\n [isRootLevelStepGroup]=\"true\"\r\n ></wf-node>\r\n </div>\r\n }\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n @if (!!(wfs.insertContext$ | async)) {\r\n <wf-insert-menu (insert)=\"insertStep($event)\"></wf-insert-menu>\r\n }\r\n\r\n <wf-step-config-shell></wf-step-config-shell>\r\n\r\n <div class=\"steps-preview\" [class.shown]=\"wfs.$showCurrentStepsPreview()\"\r\n [ngStyle]=\"{\r\n zIndex: $previewZIndex()\r\n }\"\r\n >\r\n <wf-steps-preview></wf-steps-preview>\r\n </div>\r\n \r\n\r\n</div>", styles: [".wf-workflow-canvas-container{--standard-connector-height: 90px;--print-area-scale: 1;padding-top:50px;padding-bottom:50px;background-color:#f2f3f5;position:relative;overflow:auto}.wf-workflow-canvas-container .zoom-tools{display:block;position:absolute;left:15px;z-index:1}.wf-workflow-canvas-container .zoom-tools .tools-wrapper{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;background-color:#f9fafb;box-shadow:0 1px 3px #0000001a}.wf-workflow-canvas-container .zoom-tools .tools-wrapper>*{cursor:pointer}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn{background:none;border:none;padding:6px;cursor:pointer;transition:background-color .2s}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-btn:hover{background-color:#e5e7eb}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .zoom-label{background:none;border:none;padding:6px 8px;cursor:default}.wf-workflow-canvas-container .zoom-tools .tools-wrapper .universe-icon{font-size:16px;display:inline-flex;align-items:center;justify-content:center}.wf-workflow-canvas-container .scroll-container{display:block;width:var(--width);height:var(--height);overflow-x:auto}.wf-workflow-canvas-container .canvas{display:flex;flex-direction:column;align-items:center;position:relative}.wf-workflow-canvas-container .canvas.is-dragging *{-webkit-user-select:none;user-select:none}.wf-workflow-canvas-container .print-area{transform:scale(var(--print-area-scale));transition:.2s linear}.wf-workflow-canvas-container .step{text-align:center;position:relative}.wf-workflow-canvas-container .canvas-top-tool{position:absolute;display:block;top:15px;left:15px;box-shadow:0 0 4px #0000000d}.wf-workflow-canvas-container .canvas-top-tool button{border-radius:0;height:30px;font-size:13px}.workflow-box{width:220px;min-height:85px;max-height:100px;padding:0 4px 4px;box-shadow:0 0 4px #0000000d}.workflow-box.submit,.workflow-box.end{background-color:#a9b4cd}.workflow-box.approval{background-color:#f80}.workflow-box.cc{background-color:#3370ff}.workflow-box.handle{background-color:#935af6}.connector{font-size:24px;color:#888}.plus-btn{font-size:18px;background:#fff;border:1px solid #ccc;border-radius:9999px;width:28px;height:28px;cursor:pointer}.insert-menu{background:#fff;border:1px solid #ddd;border-radius:6px;padding:8px;margin-top:6px;box-shadow:0 2px 8px #0000001a;display:flex;flex-direction:column;gap:6px;z-index:10}.insert-menu div{cursor:pointer;font-size:14px;padding:2px 6px}.insert-menu .cancel{color:red}.branch-column{position:relative}.branch-column .branch-column-inner{width:100%;display:flex;flex-direction:column;align-items:center}.wf-branch-group-container,.wf-branch-group-container .branch-group{position:relative}.wf-branch-group-container .branch-group .branch-column{display:table-cell;min-width:220px;vertical-align:top;padding:0 12px}.wf-branch-group-container .branch-group .branch-column .vertical-bridge-line{position:absolute;width:2px;background-color:#d9d9d9;z-index:2;pointer-events:none}.wf-branch-group-container .branch-group .horizontal-bridge-line{position:absolute;height:2px;background-color:#d9d9d9;pointer-events:none;z-index:1}.wf-branch-group-container:after{content:\"\";display:block;position:absolute;height:2px;width:calc(100% - 244px);left:122px;bottom:102px}.branch-title{font-weight:700;font-size:14px;margin-bottom:8px}.branch-group-header{display:flex;justify-content:center;margin:12px 0}.add-branch-btn{position:absolute;top:0;width:175px;left:calc(50% - 87.5px);z-index:2;background:#fff;color:#0f172a;border:1px solid #ccc;padding:4px 12px;border-radius:9999px;font-weight:500;cursor:pointer;box-shadow:0 2px 4px #0000000f;text-wrap:nowrap}.workflow-box.submit{background-color:#e0f7fa;border-left:4px solid #00bcd4}.workflow-box.end{background-color:#ede7f6;border-left:4px solid #673ab7}.box.special{font-style:italic;opacity:.9}.bottom-v-container{min-height:65px;width:220px}.wf-bottom-v-insert-container{position:relative;display:flex;flex-direction:column;align-items:center;height:var(--standard-connector-height);width:100%;margin:0}.wf-bottom-v-insert-container .vertical-line{position:absolute;top:0;height:100%;width:2px;background-color:#d9d9d9;z-index:0}.wf-bottom-v-insert-container .plus-container{display:block;position:absolute;border-radius:50%;top:calc(var(--standard-connector-height) / 2 - 16px)}.wf-bottom-v-insert-container .plus-btn{width:32px;height:32px;border-radius:50%;border:none;background:#fff;color:#3b82f6;font-size:20px;box-shadow:.4rem 0 2rem #0000002e;cursor:pointer;display:flex;align-items:center;justify-content:center}.wf-bottom-v-insert-container .plus-btn:hover{background:#f0f8ff;box-shadow:0 0 0 4px #3b82f633}.wf-bottom-v-insert-container.shorter{height:calc(var(--standard-connector-height) - 15px)}.wf-bottom-v-insert-container.shorter .plus-container{display:block;position:absolute;top:calc((var(--standard-connector-height) - 18px) / 2 - 16px)}.wf-bottom-v-insert-container.insert-context .plus-container{outline:#2eb795 solid 2px}.add-branch-inline{position:relative;height:35px;margin-bottom:calc(var(--standard-connector-height) - 17.5px)}.arrow-down-container{display:block;position:absolute;z-index:1;bottom:0}.arrow-down-container .arrow-down{margin-top:5px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:8px solid #d9d9d9}.branch-card-wrapper{position:relative}.branch-card-wrapper .arrow-down-container{top:-12px;left:calc(50% - 5px)}.wf-step-container .step-header{position:relative;display:flex;align-items:center;justify-content:space-between;height:43px;font-size:12px;border-bottom:1px solid #f6f6f7}.wf-step-container .step-header .input-wrapper{padding-top:4px}.wf-step-container .step-header .step-name-wrapper{display:flex;align-items:center;justify-content:flex-start;padding-right:8px}.wf-step-container .step-header .step-name-wrapper .step-name{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:140px;padding-left:4px}.wf-step-container .step-header .step-name-wrapper i{margin-left:2px}.wf-step-container .step-header .step-delete{color:gray;display:none}.wf-step-container .step-header .step-delete i{font-size:24px}.wf-step-container .step-header:hover .step-name-wrapper:after{content:\"\\e95a\";font-family:feather}.wf-step-container .step-header:hover .branch-priority{display:none}.wf-step-container .step-header:hover .step-delete,.wf-step-container .step-header.edit-mode{display:block}.wf-step-container .step-set-config{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;padding:7px 4px;font-size:14px;background-color:#fff;color:gray}.wf-step-container .step-set-config .step-subtext{width:100%;text-align:left}.wf-step-container .step-set-config .step-subtext.configurated{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container{background-color:#fff}.wf-step-container.wf-branch-card-container .branch-header{color:#2eb795;border-bottom:1px solid #f6f6f7}.wf-step-container.wf-branch-card-container .branch-header:before{content:\"\";display:block;position:absolute;height:var(--standard-connector-height);width:2px;background-color:#d9d9d9;left:50%;top:calc(var(--standard-connector-height) * -1)}.wf-step-container.wf-branch-card-container .branch-set-condition{display:flex;align-items:center;justify-content:space-between;min-height:38px;max-height:56px;color:#3e4759;padding:7px 4px;font-size:14px}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext{width:100%;text-align:left}.wf-step-container.wf-branch-card-container .branch-set-condition .branch-subtext.fallback{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;white-space:pre-line;word-break:break-word;line-height:1.5em;max-height:3em;overflow:hidden;cursor:default}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header,.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-set-condition{color:gray}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header .branch-priority{padding-right:4px}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-priority{display:block}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-delete{display:none}.wf-step-container.wf-branch-card-container .branch-card-wrapper.fallback .branch-header:hover .branch-name-wrapper:after{content:\"\"}.steps-preview{position:fixed;width:390px;height:100vh;background-color:#fff;top:0;left:-390px;overflow-y:auto;transition:left .2s ease-out}.steps-preview.shown{left:0}\n"] }]
1388
+ }], ctorParameters: () => [{ type: MultiLanguageService }] });
1389
+
1390
+ class WfProcessDesignComponent extends BaseComponent {
1391
+ constructor(mls, route) {
1392
+ super(mls);
1393
+ this.mls = mls;
1394
+ this.route = route;
1395
+ this.wfs = inject(CoreWorkflowService);
1396
+ this.$loading = this.wfs.$loading;
1397
+ const idDecrypted = this.route.snapshot.paramMap.get('id');
1398
+ if (!!idDecrypted) {
1399
+ this.id = atob(idDecrypted);
1400
+ }
1401
+ else {
1402
+ this.id = null;
1403
+ }
1404
+ }
1405
+ onCorePageHeaderButtonClicked(e) {
1406
+ switch (e.code) {
1407
+ case EnumCoreButtonVNSCode.HEADER_RESET:
1408
+ this.wfs.$currentSteps.set(INITIAL_PROCESS_DEFINITION);
1409
+ break;
1410
+ case EnumCoreButtonVNSCode.HEADER_SAVE:
1411
+ const currentFlow = this.wfs.$currentFlow();
1412
+ if (!!currentFlow) {
1413
+ this.wfs.saveCurrentSteps();
1414
+ }
1415
+ break;
1416
+ }
1417
+ }
1418
+ ngAfterViewInit() {
1419
+ if (!!this.id) {
1420
+ setTimeout(() => {
1421
+ this.wfs.getById(this.id);
1422
+ });
1423
+ }
1424
+ }
1425
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfProcessDesignComponent, deps: [{ token: MultiLanguageService }, { token: i1$1.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); }
1426
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: WfProcessDesignComponent, isStandalone: true, selector: "wf-process-design", usesInheritance: true, ngImport: i0, template: "<div class=\"wf-process-design-container\">\r\n <core-page-header title=\"UI.COMPONENT_TITLE.WORKFLOW_LIST\" (buttonClick)=\"onCorePageHeaderButtonClicked($event)\"></core-page-header>\r\n @if (!!wfs.$currentFlow()) {\r\n <p>{{ wfs.$currentFlow()!.name + ' > Process Design' }}</p>\r\n <wf-workflow-canvas></wf-workflow-canvas>\r\n }\r\n\r\n @if ($loading()) {\r\n <app-fullscreen-modal-loader></app-fullscreen-modal-loader>\r\n }\r\n</div>", styles: [""], dependencies: [{ kind: "component", type: CorePageHeaderComponent, selector: "core-page-header", inputs: ["instanceNumber", "shownItems", "title", "hideButtonGroup"], outputs: ["buttonClick"] }, { kind: "component", type: WfWorkflowCanvasComponent, selector: "wf-workflow-canvas" }, { kind: "component", type: FullscreenModalLoaderComponent, selector: "app-fullscreen-modal-loader", inputs: ["content"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1427
+ }
1428
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: WfProcessDesignComponent, decorators: [{
1429
+ type: Component,
1430
+ args: [{ selector: 'wf-process-design', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1431
+ AsyncPipe,
1432
+ CorePageHeaderComponent,
1433
+ WfWorkflowCanvasComponent,
1434
+ FullscreenModalLoaderComponent
1435
+ ], template: "<div class=\"wf-process-design-container\">\r\n <core-page-header title=\"UI.COMPONENT_TITLE.WORKFLOW_LIST\" (buttonClick)=\"onCorePageHeaderButtonClicked($event)\"></core-page-header>\r\n @if (!!wfs.$currentFlow()) {\r\n <p>{{ wfs.$currentFlow()!.name + ' > Process Design' }}</p>\r\n <wf-workflow-canvas></wf-workflow-canvas>\r\n }\r\n\r\n @if ($loading()) {\r\n <app-fullscreen-modal-loader></app-fullscreen-modal-loader>\r\n }\r\n</div>" }]
1436
+ }], ctorParameters: () => [{ type: MultiLanguageService }, { type: i1$1.ActivatedRoute }] });
1437
+
1438
+ export { WfProcessDesignComponent };
1439
+ //# sourceMappingURL=ngx-histaff-alpha-wf-process-design.component-CQxxRCqC.mjs.map