verben-workflow-ui 0.5.72 → 0.5.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/lib/components/flowable-status/flowable-status.component.mjs +10 -3
- package/esm2022/src/lib/components/workflow-designer/designer-canvas/designer-canvas.component.mjs +26 -2
- package/esm2022/src/lib/components/workflow-designer/swimlane-dialog/swimlane-dialog.component.mjs +14 -4
- package/esm2022/src/lib/components/workflow-designer/workflow-data.service.mjs +41 -19
- package/esm2022/src/lib/components/workflow-designer/workflow-designer.component.mjs +45 -3
- package/esm2022/src/lib/components/workflow-designer/workflow-designer.state.mjs +38 -1
- package/fesm2022/verben-workflow-ui-src-lib-components-flowable-status.mjs +9 -2
- package/fesm2022/verben-workflow-ui-src-lib-components-flowable-status.mjs.map +1 -1
- package/fesm2022/verben-workflow-ui-src-lib-components-workflow-designer.mjs +157 -23
- package/fesm2022/verben-workflow-ui-src-lib-components-workflow-designer.mjs.map +1 -1
- package/package.json +60 -60
- package/src/lib/components/workflow-designer/swimlane-dialog/swimlane-dialog.component.d.ts +4 -1
- package/src/lib/components/workflow-designer/workflow-data.service.d.ts +12 -3
- package/src/lib/components/workflow-designer/workflow-designer.component.d.ts +2 -0
- package/src/lib/components/workflow-designer/workflow-designer.state.d.ts +16 -0
|
@@ -365,6 +365,43 @@ class WorkflowDesignerState {
|
|
|
365
365
|
const sourceNodeType = sourceNodeInfo.node.type;
|
|
366
366
|
return this.connectionRules[sourceNodeType] || [];
|
|
367
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Deletes a swimlane. Only succeeds when the lane has no nodes — stages must
|
|
370
|
+
* be moved to another lane first. Returns false when the lane still has nodes
|
|
371
|
+
* or the index is out of range.
|
|
372
|
+
*
|
|
373
|
+
* Keeps everything aligned after removal:
|
|
374
|
+
* - Re-sequences `order` on the remaining lanes (immutable reassignment so
|
|
375
|
+
* Angular's @for blocks re-render).
|
|
376
|
+
* - Decrements the swimlane indices stored on connections whose endpoints
|
|
377
|
+
* live below the removed lane, since those lanes shift up by one.
|
|
378
|
+
*
|
|
379
|
+
* The lane's original record is left in `swimlaneRecord`, so a previously
|
|
380
|
+
* loaded lane is emitted with `ObjectState.Removed` by
|
|
381
|
+
* `transformToWorkflowModel`; a never-saved lane simply disappears.
|
|
382
|
+
*/
|
|
383
|
+
deleteSwimlane(index) {
|
|
384
|
+
if (index < 0 || index >= this.swimlanes.length) {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
if (this.swimlanes[index].nodes?.length) {
|
|
388
|
+
console.warn('Cannot delete a swimlane that still has stages; move them out first.');
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
this.swimlanes = this.swimlanes
|
|
392
|
+
.filter((_, i) => i !== index)
|
|
393
|
+
.map((lane, i) => ({ ...lane, order: i }));
|
|
394
|
+
this.connections = this.connections.map((conn) => ({
|
|
395
|
+
...conn,
|
|
396
|
+
sourceSwimlaneIndex: conn.sourceSwimlaneIndex > index
|
|
397
|
+
? conn.sourceSwimlaneIndex - 1
|
|
398
|
+
: conn.sourceSwimlaneIndex,
|
|
399
|
+
targetSwimlaneIndex: conn.targetSwimlaneIndex > index
|
|
400
|
+
? conn.targetSwimlaneIndex - 1
|
|
401
|
+
: conn.targetSwimlaneIndex,
|
|
402
|
+
}));
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
368
405
|
updateSwimlane(index, name, tags) {
|
|
369
406
|
console.log('State: Updating swimlane at index', index, 'with name', name, 'and tags', tags);
|
|
370
407
|
if (index >= 0 && index < this.swimlanes.length) {
|
|
@@ -736,49 +773,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
736
773
|
class WorkflowDataService {
|
|
737
774
|
httpService;
|
|
738
775
|
envSvc;
|
|
739
|
-
|
|
776
|
+
utilService;
|
|
777
|
+
pendingRequests = 0;
|
|
778
|
+
constructor(httpService, envSvc, utilService) {
|
|
740
779
|
this.httpService = httpService;
|
|
741
780
|
this.envSvc = envSvc;
|
|
781
|
+
this.utilService = utilService;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Wraps an API call so a busy indicator is shown while it is in flight.
|
|
785
|
+
* A ref-count keeps the loader visible until the last concurrent request
|
|
786
|
+
* settles, mirroring how the workflows facade toggles `sendBI`.
|
|
787
|
+
*/
|
|
788
|
+
withLoader(request) {
|
|
789
|
+
if (this.pendingRequests++ === 0) {
|
|
790
|
+
this.utilService.sendBI(true);
|
|
791
|
+
}
|
|
792
|
+
return request().finally(() => {
|
|
793
|
+
if (--this.pendingRequests === 0) {
|
|
794
|
+
this.utilService.sendBI(false);
|
|
795
|
+
}
|
|
796
|
+
});
|
|
742
797
|
}
|
|
743
798
|
getWorkflowWithParam(param, skip = 0, limit = 1, sortParam = 'CreatedAt', sortOrder = 'Asc') {
|
|
744
799
|
const url = `GetWorkflowsWithParam/${param}/${skip}/${limit}/${sortParam}/${sortOrder}`;
|
|
745
|
-
return this.httpService.get(url);
|
|
800
|
+
return this.withLoader(() => this.httpService.get(url));
|
|
746
801
|
}
|
|
747
802
|
getWorkflows(skip = 0, limit = 0) {
|
|
748
803
|
const url = `GetWorkflows/${skip}/${limit}`;
|
|
749
|
-
return this.httpService.get(url, this.envSvc.environment.WorkFlowAPI);
|
|
804
|
+
return this.withLoader(() => this.httpService.get(url, this.envSvc.environment.WorkFlowAPI));
|
|
750
805
|
}
|
|
751
806
|
getForms(skip = 0, limit = 0) {
|
|
752
807
|
const url = `GetForms/${skip}/${limit}`;
|
|
753
|
-
return this.httpService.get(url, this.envSvc.environment.WorkFlowAPI);
|
|
808
|
+
return this.withLoader(() => this.httpService.get(url, this.envSvc.environment.WorkFlowAPI));
|
|
754
809
|
}
|
|
755
810
|
getTags(skip = 0, limit = 0) {
|
|
756
811
|
const url = `GetTags/${skip}/${limit}`;
|
|
757
|
-
return this.httpService.get(url, this.envSvc.environment.AuthAPI);
|
|
812
|
+
return this.withLoader(() => this.httpService.get(url, this.envSvc.environment.AuthAPI));
|
|
758
813
|
}
|
|
759
814
|
saveWorkflows(requests) {
|
|
760
815
|
const url = `SaveWorkflows`;
|
|
761
816
|
// console.log('Saving workflows', requests);
|
|
762
|
-
return this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI);
|
|
817
|
+
return this.withLoader(() => this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI));
|
|
763
818
|
}
|
|
764
819
|
deleteWorkflowStages(requests) {
|
|
765
820
|
const url = `DeleteWorkflowStage`;
|
|
766
821
|
// console.log('Saving workflows', requests);
|
|
767
|
-
return this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI);
|
|
822
|
+
return this.withLoader(() => this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI));
|
|
768
823
|
}
|
|
769
824
|
deleteWorkflowActions(requests) {
|
|
770
825
|
const url = `DeleteWorkflowAction`;
|
|
771
|
-
return this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI);
|
|
826
|
+
return this.withLoader(() => this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI));
|
|
827
|
+
}
|
|
828
|
+
deleteSwimLanes(requests) {
|
|
829
|
+
const url = `DeleteSwimLane`;
|
|
830
|
+
return this.withLoader(() => this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI));
|
|
772
831
|
}
|
|
773
832
|
saveEscalations(requests) {
|
|
774
833
|
const url = `SaveEscalations`;
|
|
775
834
|
// console.log('Saving workflows', requests);
|
|
776
|
-
return this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI);
|
|
835
|
+
return this.withLoader(() => this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI));
|
|
777
836
|
}
|
|
778
837
|
deleteEscalations(requests) {
|
|
779
838
|
const url = `DeleteEscalation`;
|
|
780
839
|
// console.log('Saving workflows', requests);
|
|
781
|
-
return this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI);
|
|
840
|
+
return this.withLoader(() => this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI));
|
|
782
841
|
}
|
|
783
842
|
searchEscalationWithParam(params, skip = 0, limit = 1, sortOrder = 'Asc') {
|
|
784
843
|
const url = `SearchEscalations/${skip}/${limit}`;
|
|
@@ -793,27 +852,27 @@ class WorkflowDataService {
|
|
|
793
852
|
Sort: sortOrder,
|
|
794
853
|
// Fields: ['string'],
|
|
795
854
|
}));
|
|
796
|
-
return this.httpService.post(url, payload);
|
|
855
|
+
return this.withLoader(() => this.httpService.post(url, payload));
|
|
797
856
|
}
|
|
798
857
|
getEscalationWithParam(param, skip = 0, limit = 1, sortParam = 'CreatedAt', sortOrder = 'Asc') {
|
|
799
858
|
const url = `GetEscalationsWithParam/${param}/${skip}/${limit}/${sortParam}/${sortOrder}`;
|
|
800
|
-
return this.httpService.get(url);
|
|
859
|
+
return this.withLoader(() => this.httpService.get(url));
|
|
801
860
|
}
|
|
802
861
|
getReportSchedules(skip = 0, limit = 0) {
|
|
803
862
|
const url = `GetReportSchedules/${skip}/${limit}`;
|
|
804
|
-
return this.httpService.get(url, this.envSvc.environment.ReportingAPI);
|
|
863
|
+
return this.withLoader(() => this.httpService.get(url, this.envSvc.environment.ReportingAPI));
|
|
805
864
|
}
|
|
806
865
|
getOperationActions(skip = 0, limit = 0) {
|
|
807
866
|
const url = `GetOperationAction`;
|
|
808
|
-
return this.httpService.get(url);
|
|
867
|
+
return this.withLoader(() => this.httpService.get(url));
|
|
809
868
|
}
|
|
810
869
|
saveActorTags(requests) {
|
|
811
870
|
const url = `SaveActorTags`;
|
|
812
|
-
return this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI);
|
|
871
|
+
return this.withLoader(() => this.httpService.post(url, requests, this.envSvc.environment.WorkFlowAPI));
|
|
813
872
|
}
|
|
814
873
|
getFlowableStatuses(skip = 0, limit = 0) {
|
|
815
874
|
const url = `GetFlowableStatus/${skip}/${limit}/CreatedAt/Desc`;
|
|
816
|
-
return this.httpService.get(url);
|
|
875
|
+
return this.withLoader(() => this.httpService.get(url));
|
|
817
876
|
}
|
|
818
877
|
// Helper to create a mock workflow (just for demo)
|
|
819
878
|
createMockWorkflow(code) {
|
|
@@ -883,7 +942,7 @@ class WorkflowDataService {
|
|
|
883
942
|
};
|
|
884
943
|
return workflow;
|
|
885
944
|
}
|
|
886
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WorkflowDataService, deps: [{ token: i1.HttpWebRequestService }, { token: i1.EnvironmentService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
945
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WorkflowDataService, deps: [{ token: i1.HttpWebRequestService }, { token: i1.EnvironmentService }, { token: i1.UtilService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
887
946
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WorkflowDataService, providedIn: 'root' });
|
|
888
947
|
}
|
|
889
948
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WorkflowDataService, decorators: [{
|
|
@@ -891,7 +950,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
891
950
|
args: [{
|
|
892
951
|
providedIn: 'root',
|
|
893
952
|
}]
|
|
894
|
-
}], ctorParameters: () => [{ type: i1.HttpWebRequestService }, { type: i1.EnvironmentService }] });
|
|
953
|
+
}], ctorParameters: () => [{ type: i1.HttpWebRequestService }, { type: i1.EnvironmentService }, { type: i1.UtilService }] });
|
|
895
954
|
|
|
896
955
|
class NodeManagementService {
|
|
897
956
|
state;
|
|
@@ -2531,7 +2590,14 @@ class DesignerCanvasComponent {
|
|
|
2531
2590
|
const nodeInfo = this.state.findNodeById(stageId);
|
|
2532
2591
|
if (nodeInfo) {
|
|
2533
2592
|
this.activeStageId = stageId;
|
|
2534
|
-
|
|
2593
|
+
// Seed the entry-point toggle from the node's actual start state, which is
|
|
2594
|
+
// the source of truth for the start circle and API serialization. The
|
|
2595
|
+
// auto-assigned entry node has isStartNode=true without stageData.IsEntryPoint.
|
|
2596
|
+
this.activeStageData = {
|
|
2597
|
+
...nodeInfo.node.stageData,
|
|
2598
|
+
IsEntryPoint: nodeInfo.node.isStartNode,
|
|
2599
|
+
id: stageId,
|
|
2600
|
+
};
|
|
2535
2601
|
console.log(this.activeStageData, "ACTIVE STAGE DATA");
|
|
2536
2602
|
this.showStageDialogLocal = true;
|
|
2537
2603
|
}
|
|
@@ -2599,6 +2665,23 @@ class DesignerCanvasComponent {
|
|
|
2599
2665
|
...stageData,
|
|
2600
2666
|
};
|
|
2601
2667
|
console.log('Updated stage data:', nodeInfo.node.stageData);
|
|
2668
|
+
// Sync the entry-point flag onto node.isStartNode, which drives both the
|
|
2669
|
+
// start circle and the IsEntryPoint value serialized to the API.
|
|
2670
|
+
if (stageData.IsEntryPoint) {
|
|
2671
|
+
// Enforce a single entry point: this node becomes the sole start node.
|
|
2672
|
+
this.state.swimlanes.forEach((swimlane) => {
|
|
2673
|
+
swimlane.nodes?.forEach((node) => {
|
|
2674
|
+
node.isStartNode = node.id === this.activeStageId;
|
|
2675
|
+
});
|
|
2676
|
+
});
|
|
2677
|
+
this.state.startNodeId = this.activeStageId;
|
|
2678
|
+
}
|
|
2679
|
+
else {
|
|
2680
|
+
nodeInfo.node.isStartNode = false;
|
|
2681
|
+
if (this.state.startNodeId === this.activeStageId) {
|
|
2682
|
+
this.state.startNodeId = null;
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2602
2685
|
// Emit event for parent component to know about the update
|
|
2603
2686
|
this.stagePropertiesUpdated.emit({
|
|
2604
2687
|
nodeId: this.activeStageId,
|
|
@@ -3622,9 +3705,11 @@ class SwimlaneDialogComponent {
|
|
|
3622
3705
|
dataService;
|
|
3623
3706
|
swimlaneService;
|
|
3624
3707
|
visible = false;
|
|
3708
|
+
isEditing = false;
|
|
3625
3709
|
swimlaneData = input(null);
|
|
3626
3710
|
closed = new EventEmitter();
|
|
3627
3711
|
created = new EventEmitter();
|
|
3712
|
+
deleted = new EventEmitter();
|
|
3628
3713
|
searchQuery = '';
|
|
3629
3714
|
workflowName = '';
|
|
3630
3715
|
// Track selected tags in a separate array
|
|
@@ -3692,6 +3777,9 @@ class SwimlaneDialogComponent {
|
|
|
3692
3777
|
this.selectedTagNames.push(tagName);
|
|
3693
3778
|
}
|
|
3694
3779
|
}
|
|
3780
|
+
onDeleteSwimlane() {
|
|
3781
|
+
this.deleted.emit();
|
|
3782
|
+
}
|
|
3695
3783
|
onDialogClose(eventData) {
|
|
3696
3784
|
console.log('Dialog closed, received data:', eventData);
|
|
3697
3785
|
this.searchQuery = '';
|
|
@@ -3719,17 +3807,21 @@ class SwimlaneDialogComponent {
|
|
|
3719
3807
|
this.searchQuery = '';
|
|
3720
3808
|
}
|
|
3721
3809
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SwimlaneDialogComponent, deps: [{ token: i1$1.FormBuilder }, { token: WorkflowDataService }, { token: SwimlaneService }], target: i0.ɵɵFactoryTarget.Component });
|
|
3722
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: SwimlaneDialogComponent, selector: "lib-swimlane-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: false, isRequired: false, transformFunction: null }, swimlaneData: { classPropertyName: "swimlaneData", publicName: "swimlaneData", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", created: "created" }, ngImport: i0, template: "<verben-dialogue\n [showCloseIcon]=\"true\"\n [dismissOutsideClick]=\"true\"\n [closeOnEscape]=\"true\"\n [size]=\"'medium'\"\n [mode]=\"'drawer'\"\n [disableFooter]=\"false\"\n [isVisible]=\"visible\"\n [headerTemplate]=\"headerTemplate\"\n [bodyTemplate]=\"bodyTemplate\"\n [footerTemplate]=\"footerTemplate\"\n (openModal)=\"onDialogOpen($event)\"\n (closeModal)=\"onDialogClose($event)\"\n>\n</verben-dialogue>\n\n<ng-template #headerTemplate>\n <div\n class=\"flex items-center justify-between p-3 text-xs border-b-4 border-[#FFE681]\"\n >\n <button class=\"mr-4\" type=\"button\" (click)=\"onDialogClose($event)\">\n <span\n class=\"block w-2.5 h-2.5 border-t border-l border-[#3E3E3E]/70 transform -rotate-45\"\n ></span>\n </button>\n <div class=\"text-center\">\n <h2 class=\"text-sm font-medium\">Select Tags</h2>\n <span class=\"text-xs text-[#3E3E3E]/70\"\n >{{ this.selectedTags.length }}/{{ tags.length }}</span\n >\n </div>\n <span\n class=\"font-medium cursor-pointer text-[#3E3E3E]/70\"\n (click)=\"applySelection()\"\n >Create</span\n >\n </div>\n</ng-template>\n\n<ng-template #bodyTemplate>\n <div class=\"p-3\">\n <div class=\"mb-4 grid gap-4\">\n <!-- <input\n type=\"text\"\n placeholder=\"Enter Name\"\n class=\"w-full px-4 py-2 rounded-lg border border-[#E7C10B] outline-none\"\n [(ngModel)]=\"workflowName\"\n />\n\n <input\n type=\"search\"\n placeholder=\"Filter Tags\"\n class=\"w-full px-4 py-2 rounded-lg border border-[#E7C10B] outline-none\"\n [(ngModel)]=\"searchQuery\"\n />\n </div>\n\n <div class=\"\">\n <div class=\"py-3\">\n <label class=\"flex items-center\">\n <input type=\"checkbox\" class=\"mr-3\" [(ngModel)]=\"allSelected\" />\n <span class=\"text-sm\">Select All</span>\n </label>\n </div>\n\n <div *ngFor=\"let tag of filteredTags\" class=\"py-3\">\n <label class=\"flex items-center\">\n <input\n type=\"checkbox\"\n class=\"mr-3\"\n [checked]=\"isTagSelected(tag.Name)\"\n (change)=\"toggleTagSelection(tag.Name)\"\n />\n <span class=\"text-sm\">{{ tag.Name }}</span>\n <span *ngIf=\"!tag.IsOptional\" class=\"ml-2 text-xs text-red-500\"\n >(Required)</span\n >\n </label>\n </div> -->\n\n <verbena-input\n [(ngModel)]=\"workflowName\"\n [border]=\"'1px solid #9A9FBF66'\"\n placeHolder=\"Enter Swimlane Label\"\n [bgColor]=\"'white'\"\n ></verbena-input>\n\n <verben-drop-down\n selectKey=\"Code\"\n label=\"Tags\"\n styleClass=\"w-full\"\n width=\"100%\"\n [multiselect]=\"true\"\n placeholder=\"Select\"\n [options]=\"tags\"\n optionLabel=\"Name\"\n id=\"tags\"\n [(ngModel)]=\"selectedTags\"\n class=\"form-control\"\n [filter]=\"true\"\n [filterBy]=\"'Name'\"\n [showClear]=\"true\"\n >\n </verben-drop-down>\n </div>\n </div>\n</ng-template>\n\n<ng-template #footerTemplate>\n <div\n class=\"flex justify-between w-full items-center p-4 border-t border-gray-200\"\n >\n <!-- <button\n class=\"px-4 py-2 mr-2 bg-white border border-gray-200 rounded text-sm font-medium\"\n (click)=\"onDialogClose($event)\"\n >\n Cancel\n </button> -->\n\n <verbena-button\n (click)=\"onDialogClose($event)\"\n text=\"Cancel\"\n styleType=\"ylw-outline\"\n ></verbena-button>\n\n <verbena-button\n type=\"submit\"\n text=\"Save\"\n bgColor=\"#FFE681\"\n textColor=\"#404040\"\n borderRadius=\"10px\"\n pd=\"10px 20px\"\n width=\"114px\"\n height=\"39px\"\n [disable]=\"selectedTags.length < 1\"\n (click)=\"applySelection()\"\n ></verbena-button>\n\n
|
|
3810
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.13", type: SwimlaneDialogComponent, selector: "lib-swimlane-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: false, isRequired: false, transformFunction: null }, isEditing: { classPropertyName: "isEditing", publicName: "isEditing", isSignal: false, isRequired: false, transformFunction: null }, swimlaneData: { classPropertyName: "swimlaneData", publicName: "swimlaneData", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", created: "created", deleted: "deleted" }, ngImport: i0, template: "<verben-dialogue\n [showCloseIcon]=\"true\"\n [dismissOutsideClick]=\"true\"\n [closeOnEscape]=\"true\"\n [size]=\"'medium'\"\n [mode]=\"'drawer'\"\n [disableFooter]=\"false\"\n [isVisible]=\"visible\"\n [headerTemplate]=\"headerTemplate\"\n [bodyTemplate]=\"bodyTemplate\"\n [footerTemplate]=\"footerTemplate\"\n (openModal)=\"onDialogOpen($event)\"\n (closeModal)=\"onDialogClose($event)\"\n>\n</verben-dialogue>\n\n<ng-template #headerTemplate>\n <div\n class=\"flex items-center justify-between p-3 text-xs border-b-4 border-[#FFE681]\"\n >\n <button class=\"mr-4\" type=\"button\" (click)=\"onDialogClose($event)\">\n <span\n class=\"block w-2.5 h-2.5 border-t border-l border-[#3E3E3E]/70 transform -rotate-45\"\n ></span>\n </button>\n <div class=\"text-center\">\n <h2 class=\"text-sm font-medium\">Select Tags</h2>\n <span class=\"text-xs text-[#3E3E3E]/70\"\n >{{ this.selectedTags.length }}/{{ tags.length }}</span\n >\n </div>\n <span\n class=\"font-medium cursor-pointer text-[#3E3E3E]/70\"\n (click)=\"applySelection()\"\n >Create</span\n >\n </div>\n</ng-template>\n\n<ng-template #bodyTemplate>\n <div class=\"p-3\">\n <div class=\"mb-4 grid gap-4\">\n <!-- <input\n type=\"text\"\n placeholder=\"Enter Name\"\n class=\"w-full px-4 py-2 rounded-lg border border-[#E7C10B] outline-none\"\n [(ngModel)]=\"workflowName\"\n />\n\n <input\n type=\"search\"\n placeholder=\"Filter Tags\"\n class=\"w-full px-4 py-2 rounded-lg border border-[#E7C10B] outline-none\"\n [(ngModel)]=\"searchQuery\"\n />\n </div>\n\n <div class=\"\">\n <div class=\"py-3\">\n <label class=\"flex items-center\">\n <input type=\"checkbox\" class=\"mr-3\" [(ngModel)]=\"allSelected\" />\n <span class=\"text-sm\">Select All</span>\n </label>\n </div>\n\n <div *ngFor=\"let tag of filteredTags\" class=\"py-3\">\n <label class=\"flex items-center\">\n <input\n type=\"checkbox\"\n class=\"mr-3\"\n [checked]=\"isTagSelected(tag.Name)\"\n (change)=\"toggleTagSelection(tag.Name)\"\n />\n <span class=\"text-sm\">{{ tag.Name }}</span>\n <span *ngIf=\"!tag.IsOptional\" class=\"ml-2 text-xs text-red-500\"\n >(Required)</span\n >\n </label>\n </div> -->\n\n <verbena-input\n [(ngModel)]=\"workflowName\"\n [border]=\"'1px solid #9A9FBF66'\"\n placeHolder=\"Enter Swimlane Label\"\n [bgColor]=\"'white'\"\n ></verbena-input>\n\n <verben-drop-down\n selectKey=\"Code\"\n label=\"Tags\"\n styleClass=\"w-full\"\n width=\"100%\"\n [multiselect]=\"true\"\n placeholder=\"Select\"\n [options]=\"tags\"\n optionLabel=\"Name\"\n id=\"tags\"\n [(ngModel)]=\"selectedTags\"\n class=\"form-control\"\n [filter]=\"true\"\n [filterBy]=\"'Name'\"\n [showClear]=\"true\"\n >\n </verben-drop-down>\n </div>\n </div>\n</ng-template>\n\n<ng-template #footerTemplate>\n <div\n class=\"flex justify-between w-full items-center p-4 border-t border-gray-200\"\n >\n <!-- <button\n class=\"px-4 py-2 mr-2 bg-white border border-gray-200 rounded text-sm font-medium\"\n (click)=\"onDialogClose($event)\"\n >\n Cancel\n </button> -->\n\n <verbena-button\n (click)=\"onDialogClose($event)\"\n text=\"Cancel\"\n styleType=\"ylw-outline\"\n ></verbena-button>\n\n <verbena-button\n type=\"submit\"\n text=\"Save\"\n bgColor=\"#FFE681\"\n textColor=\"#404040\"\n borderRadius=\"10px\"\n pd=\"10px 20px\"\n width=\"114px\"\n height=\"39px\"\n [disable]=\"selectedTags.length < 1\"\n (click)=\"applySelection()\"\n ></verbena-button>\n\n <verbena-button\n *ngIf=\"isEditing\"\n width=\"114px\"\n height=\"39px\"\n text=\"Delete\"\n bgColor=\"#999999\"\n textColor=\"#404040\"\n borderRadius=\"10px\"\n pd=\"10px 20px\"\n (click)=\"onDeleteSwimlane()\"\n ></verbena-button>\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5.VerbenDialogueComponent, selector: "verben-dialogue", inputs: ["dialogueWidth", "headerTemplate", "bodyTemplate", "footerTemplate", "showCloseIcon", "dismissOutsideClick", "closeOnEscape", "isVisible", "size", "backdropColor", "customClass", "disableFooter", "margin", "padding", "borderRadius", "dialogueBgColor", "width", "closeIconClass", "boxShadow", "enableTransition", "modalData", "mode", "position", "drawerWidth"], outputs: ["openModal", "closeModal"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.VerbenaButtonComponent, selector: "verbena-button", inputs: ["text", "icon", "useIcon", "svgPosition", "iconPosition", "bgColor", "textColor", "border", "borderRadius", "pd", "width", "height", "fontSize", "fontWeight", "disable", "svgSize", "weight", "variant", "styleType", "svg", "svgWidth", "svgHeight", "iconColor", "svgColor", "buttonClass", "buttonTextClass", "isLoading", "spinnerSize", "spinnerColor"] }, { kind: "component", type: i5.DropDownComponent, selector: "verben-drop-down", inputs: ["options", "width", "showHorizontalLine", "horizontalLineColor", "optionLabel", "optionSubLabel", "optionValue", "placeholder", "invalidMessage", "errorPosition", "loadMoreCaption", "display", "showClear", "lazyLoad", "selectKey", "styleClass", "group", "multiselect", "filter", "avoidDuplication", "filterBy", "debounceTime", "minChar", "disabled", "required", "load", "asyncLabel", "search"], outputs: ["optionsChange", "onChange", "onClick", "onClear"] }, { kind: "component", type: i5.VerbenaInputComponent, selector: "verbena-input", inputs: ["label", "placeHolder", "required", "svgPosition", "minLength", "maxLength", "type", "bgColor", "border", "borderRadius", "textColor", "value", "labelPosition", "labelColor", "disable", "readOnly", "min", "max", "showBorder", "showErrorMessage", "errorMessageColor", "errorBorderColor", "errorPosition", "svg", "fontSize", "svgWidth", "svgHeight", "svgColor", "capitalization", "inputContainerClass", "inputFieldClass", "passLength", "inputWrapperClass", "passwordToggle", "customErrorMessages", "icon", "textPass"], outputs: ["valueChange"] }] });
|
|
3723
3811
|
}
|
|
3724
3812
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SwimlaneDialogComponent, decorators: [{
|
|
3725
3813
|
type: Component,
|
|
3726
|
-
args: [{ selector: 'lib-swimlane-dialog', template: "<verben-dialogue\n [showCloseIcon]=\"true\"\n [dismissOutsideClick]=\"true\"\n [closeOnEscape]=\"true\"\n [size]=\"'medium'\"\n [mode]=\"'drawer'\"\n [disableFooter]=\"false\"\n [isVisible]=\"visible\"\n [headerTemplate]=\"headerTemplate\"\n [bodyTemplate]=\"bodyTemplate\"\n [footerTemplate]=\"footerTemplate\"\n (openModal)=\"onDialogOpen($event)\"\n (closeModal)=\"onDialogClose($event)\"\n>\n</verben-dialogue>\n\n<ng-template #headerTemplate>\n <div\n class=\"flex items-center justify-between p-3 text-xs border-b-4 border-[#FFE681]\"\n >\n <button class=\"mr-4\" type=\"button\" (click)=\"onDialogClose($event)\">\n <span\n class=\"block w-2.5 h-2.5 border-t border-l border-[#3E3E3E]/70 transform -rotate-45\"\n ></span>\n </button>\n <div class=\"text-center\">\n <h2 class=\"text-sm font-medium\">Select Tags</h2>\n <span class=\"text-xs text-[#3E3E3E]/70\"\n >{{ this.selectedTags.length }}/{{ tags.length }}</span\n >\n </div>\n <span\n class=\"font-medium cursor-pointer text-[#3E3E3E]/70\"\n (click)=\"applySelection()\"\n >Create</span\n >\n </div>\n</ng-template>\n\n<ng-template #bodyTemplate>\n <div class=\"p-3\">\n <div class=\"mb-4 grid gap-4\">\n <!-- <input\n type=\"text\"\n placeholder=\"Enter Name\"\n class=\"w-full px-4 py-2 rounded-lg border border-[#E7C10B] outline-none\"\n [(ngModel)]=\"workflowName\"\n />\n\n <input\n type=\"search\"\n placeholder=\"Filter Tags\"\n class=\"w-full px-4 py-2 rounded-lg border border-[#E7C10B] outline-none\"\n [(ngModel)]=\"searchQuery\"\n />\n </div>\n\n <div class=\"\">\n <div class=\"py-3\">\n <label class=\"flex items-center\">\n <input type=\"checkbox\" class=\"mr-3\" [(ngModel)]=\"allSelected\" />\n <span class=\"text-sm\">Select All</span>\n </label>\n </div>\n\n <div *ngFor=\"let tag of filteredTags\" class=\"py-3\">\n <label class=\"flex items-center\">\n <input\n type=\"checkbox\"\n class=\"mr-3\"\n [checked]=\"isTagSelected(tag.Name)\"\n (change)=\"toggleTagSelection(tag.Name)\"\n />\n <span class=\"text-sm\">{{ tag.Name }}</span>\n <span *ngIf=\"!tag.IsOptional\" class=\"ml-2 text-xs text-red-500\"\n >(Required)</span\n >\n </label>\n </div> -->\n\n <verbena-input\n [(ngModel)]=\"workflowName\"\n [border]=\"'1px solid #9A9FBF66'\"\n placeHolder=\"Enter Swimlane Label\"\n [bgColor]=\"'white'\"\n ></verbena-input>\n\n <verben-drop-down\n selectKey=\"Code\"\n label=\"Tags\"\n styleClass=\"w-full\"\n width=\"100%\"\n [multiselect]=\"true\"\n placeholder=\"Select\"\n [options]=\"tags\"\n optionLabel=\"Name\"\n id=\"tags\"\n [(ngModel)]=\"selectedTags\"\n class=\"form-control\"\n [filter]=\"true\"\n [filterBy]=\"'Name'\"\n [showClear]=\"true\"\n >\n </verben-drop-down>\n </div>\n </div>\n</ng-template>\n\n<ng-template #footerTemplate>\n <div\n class=\"flex justify-between w-full items-center p-4 border-t border-gray-200\"\n >\n <!-- <button\n class=\"px-4 py-2 mr-2 bg-white border border-gray-200 rounded text-sm font-medium\"\n (click)=\"onDialogClose($event)\"\n >\n Cancel\n </button> -->\n\n <verbena-button\n (click)=\"onDialogClose($event)\"\n text=\"Cancel\"\n styleType=\"ylw-outline\"\n ></verbena-button>\n\n <verbena-button\n type=\"submit\"\n text=\"Save\"\n bgColor=\"#FFE681\"\n textColor=\"#404040\"\n borderRadius=\"10px\"\n pd=\"10px 20px\"\n width=\"114px\"\n height=\"39px\"\n [disable]=\"selectedTags.length < 1\"\n (click)=\"applySelection()\"\n ></verbena-button>\n\n
|
|
3814
|
+
args: [{ selector: 'lib-swimlane-dialog', template: "<verben-dialogue\n [showCloseIcon]=\"true\"\n [dismissOutsideClick]=\"true\"\n [closeOnEscape]=\"true\"\n [size]=\"'medium'\"\n [mode]=\"'drawer'\"\n [disableFooter]=\"false\"\n [isVisible]=\"visible\"\n [headerTemplate]=\"headerTemplate\"\n [bodyTemplate]=\"bodyTemplate\"\n [footerTemplate]=\"footerTemplate\"\n (openModal)=\"onDialogOpen($event)\"\n (closeModal)=\"onDialogClose($event)\"\n>\n</verben-dialogue>\n\n<ng-template #headerTemplate>\n <div\n class=\"flex items-center justify-between p-3 text-xs border-b-4 border-[#FFE681]\"\n >\n <button class=\"mr-4\" type=\"button\" (click)=\"onDialogClose($event)\">\n <span\n class=\"block w-2.5 h-2.5 border-t border-l border-[#3E3E3E]/70 transform -rotate-45\"\n ></span>\n </button>\n <div class=\"text-center\">\n <h2 class=\"text-sm font-medium\">Select Tags</h2>\n <span class=\"text-xs text-[#3E3E3E]/70\"\n >{{ this.selectedTags.length }}/{{ tags.length }}</span\n >\n </div>\n <span\n class=\"font-medium cursor-pointer text-[#3E3E3E]/70\"\n (click)=\"applySelection()\"\n >Create</span\n >\n </div>\n</ng-template>\n\n<ng-template #bodyTemplate>\n <div class=\"p-3\">\n <div class=\"mb-4 grid gap-4\">\n <!-- <input\n type=\"text\"\n placeholder=\"Enter Name\"\n class=\"w-full px-4 py-2 rounded-lg border border-[#E7C10B] outline-none\"\n [(ngModel)]=\"workflowName\"\n />\n\n <input\n type=\"search\"\n placeholder=\"Filter Tags\"\n class=\"w-full px-4 py-2 rounded-lg border border-[#E7C10B] outline-none\"\n [(ngModel)]=\"searchQuery\"\n />\n </div>\n\n <div class=\"\">\n <div class=\"py-3\">\n <label class=\"flex items-center\">\n <input type=\"checkbox\" class=\"mr-3\" [(ngModel)]=\"allSelected\" />\n <span class=\"text-sm\">Select All</span>\n </label>\n </div>\n\n <div *ngFor=\"let tag of filteredTags\" class=\"py-3\">\n <label class=\"flex items-center\">\n <input\n type=\"checkbox\"\n class=\"mr-3\"\n [checked]=\"isTagSelected(tag.Name)\"\n (change)=\"toggleTagSelection(tag.Name)\"\n />\n <span class=\"text-sm\">{{ tag.Name }}</span>\n <span *ngIf=\"!tag.IsOptional\" class=\"ml-2 text-xs text-red-500\"\n >(Required)</span\n >\n </label>\n </div> -->\n\n <verbena-input\n [(ngModel)]=\"workflowName\"\n [border]=\"'1px solid #9A9FBF66'\"\n placeHolder=\"Enter Swimlane Label\"\n [bgColor]=\"'white'\"\n ></verbena-input>\n\n <verben-drop-down\n selectKey=\"Code\"\n label=\"Tags\"\n styleClass=\"w-full\"\n width=\"100%\"\n [multiselect]=\"true\"\n placeholder=\"Select\"\n [options]=\"tags\"\n optionLabel=\"Name\"\n id=\"tags\"\n [(ngModel)]=\"selectedTags\"\n class=\"form-control\"\n [filter]=\"true\"\n [filterBy]=\"'Name'\"\n [showClear]=\"true\"\n >\n </verben-drop-down>\n </div>\n </div>\n</ng-template>\n\n<ng-template #footerTemplate>\n <div\n class=\"flex justify-between w-full items-center p-4 border-t border-gray-200\"\n >\n <!-- <button\n class=\"px-4 py-2 mr-2 bg-white border border-gray-200 rounded text-sm font-medium\"\n (click)=\"onDialogClose($event)\"\n >\n Cancel\n </button> -->\n\n <verbena-button\n (click)=\"onDialogClose($event)\"\n text=\"Cancel\"\n styleType=\"ylw-outline\"\n ></verbena-button>\n\n <verbena-button\n type=\"submit\"\n text=\"Save\"\n bgColor=\"#FFE681\"\n textColor=\"#404040\"\n borderRadius=\"10px\"\n pd=\"10px 20px\"\n width=\"114px\"\n height=\"39px\"\n [disable]=\"selectedTags.length < 1\"\n (click)=\"applySelection()\"\n ></verbena-button>\n\n <verbena-button\n *ngIf=\"isEditing\"\n width=\"114px\"\n height=\"39px\"\n text=\"Delete\"\n bgColor=\"#999999\"\n textColor=\"#404040\"\n borderRadius=\"10px\"\n pd=\"10px 20px\"\n (click)=\"onDeleteSwimlane()\"\n ></verbena-button>\n </div>\n</ng-template>\n" }]
|
|
3727
3815
|
}], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: WorkflowDataService }, { type: SwimlaneService }], propDecorators: { visible: [{
|
|
3728
3816
|
type: Input
|
|
3817
|
+
}], isEditing: [{
|
|
3818
|
+
type: Input
|
|
3729
3819
|
}], closed: [{
|
|
3730
3820
|
type: Output
|
|
3731
3821
|
}], created: [{
|
|
3732
3822
|
type: Output
|
|
3823
|
+
}], deleted: [{
|
|
3824
|
+
type: Output
|
|
3733
3825
|
}] } });
|
|
3734
3826
|
|
|
3735
3827
|
class ActorTagsDialogComponent {
|
|
@@ -4131,6 +4223,48 @@ class WorkflowDesignerComponent {
|
|
|
4131
4223
|
this.showSwimlaneDialog = false;
|
|
4132
4224
|
this.editingSwimlaneIndex = null;
|
|
4133
4225
|
}
|
|
4226
|
+
onSwimlaneDialogDeleted() {
|
|
4227
|
+
if (this.editingSwimlaneIndex === null) {
|
|
4228
|
+
return;
|
|
4229
|
+
}
|
|
4230
|
+
const index = this.editingSwimlaneIndex;
|
|
4231
|
+
const swimlane = this.state.swimlanes[index];
|
|
4232
|
+
// Guard: stages must be moved out first (also enforced in state.deleteSwimlane).
|
|
4233
|
+
if (swimlane?.nodes?.length) {
|
|
4234
|
+
this.utilService.showError('Move all stages out of this swimlane before deleting it.');
|
|
4235
|
+
return;
|
|
4236
|
+
}
|
|
4237
|
+
// A loaded lane keeps its backend Code in swimlaneRecord (keyed by id/Code).
|
|
4238
|
+
const backendRecord = swimlane?.id
|
|
4239
|
+
? this.state.swimlaneRecord[swimlane.id]
|
|
4240
|
+
: undefined;
|
|
4241
|
+
if (backendRecord?.Code) {
|
|
4242
|
+
// Path A: backend-persisted lane — delete on the server first.
|
|
4243
|
+
this.dataService
|
|
4244
|
+
.deleteSwimLanes([backendRecord.Code])
|
|
4245
|
+
.then(() => {
|
|
4246
|
+
this.finishSwimlaneDelete(index);
|
|
4247
|
+
})
|
|
4248
|
+
.catch((error) => {
|
|
4249
|
+
console.error('Error deleting swimlane:', error);
|
|
4250
|
+
this.utilService.showError('Failed to delete swimlane');
|
|
4251
|
+
});
|
|
4252
|
+
}
|
|
4253
|
+
else {
|
|
4254
|
+
// Path B: never-saved lane — remove from state directly, no API call.
|
|
4255
|
+
this.finishSwimlaneDelete(index);
|
|
4256
|
+
}
|
|
4257
|
+
}
|
|
4258
|
+
finishSwimlaneDelete(index) {
|
|
4259
|
+
const deleted = this.state.deleteSwimlane(index);
|
|
4260
|
+
if (!deleted) {
|
|
4261
|
+
this.utilService.showError('Move all stages out of this swimlane before deleting it.');
|
|
4262
|
+
return;
|
|
4263
|
+
}
|
|
4264
|
+
this.showSwimlaneDialog = false;
|
|
4265
|
+
this.editingSwimlaneIndex = null;
|
|
4266
|
+
this.canvasRef?.updateCanvasSize();
|
|
4267
|
+
}
|
|
4134
4268
|
onSubflowSelected() {
|
|
4135
4269
|
// Reset the selected tool after placing a subflow node
|
|
4136
4270
|
this.selectedTool = null;
|
|
@@ -4139,11 +4273,11 @@ class WorkflowDesignerComponent {
|
|
|
4139
4273
|
this.showActorTagsDialog = true;
|
|
4140
4274
|
}
|
|
4141
4275
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WorkflowDesignerComponent, deps: [{ token: WorkflowDesignerState }, { token: WorkflowDataService }, { token: i1.UtilService }], target: i0.ɵɵFactoryTarget.Component });
|
|
4142
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: WorkflowDesignerComponent, selector: "lib-workflow-designer", inputs: { workflowCode: "workflowCode" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvasRef"], descendants: true }], ngImport: i0, template: "<div class=\"workflow-designer\">\n <div class=\"workflow-header\">\n <h1>{{ state.workflow?.Name }}</h1>\n </div>\n\n <!-- Toolbar Component -->\n <lib-designer-toolbar [selectedTool]=\"selectedTool\" [isSaving]=\"isSaving\"\n [workflowCode]=\"state.workflow?.Code || null\" (toolSelected)=\"onToolSelected($event)\"\n (saveWorkflow)=\"saveWorkflow()\" (openActorTags)=\"openActorTagsDialog()\">\n </lib-designer-toolbar>\n\n <!-- Show loading indicator if needed -->\n <div *ngIf=\"isLoading\" class=\"loading-overlay\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\">Loading workflow...</div>\n </div>\n\n <!-- Canvas Component -->\n <lib-designer-canvas [selectedTool]=\"selectedTool\" (clickedPosition)=\"handleCanvasPositionClick($event)\"\n (subflowSelected)=\"onSubflowSelected()\" #canvasRef>\n </lib-designer-canvas>\n\n <lib-swimlane-dialog [visible]=\"showSwimlaneDialog\" [swimlaneData]=\"editingSwimlane()\"\n (created)=\"onSwimlaneDialogFilled($event)\" (closed)=\"showSwimlaneDialog = false\"></lib-swimlane-dialog>\n\n <lib-actor-tags-dialog [visible]=\"showActorTagsDialog\" [workflowCode]=\"state.workflow?.Code || null\"\n (closed)=\"showActorTagsDialog = false\"></lib-actor-tags-dialog>\n</div>\n", styles: [".workflow-designer{display:flex;flex-direction:column;height:100vh;background-color:#f8fafc}.workflow-header{padding:1rem;background-color:#fff;border-bottom:1px solid #e2e8f0;text-align:center}.workflow-header h1{font-size:1.25rem;font-weight:600;color:#334155;margin:0}.loading-overlay{position:absolute;inset:0;background-color:#ffffffb3;display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:1000}.loading-spinner{border:4px solid #f3f3f3;border-top:4px solid #d8b4fe;border-radius:50%;width:40px;height:40px;animation:spin 1s linear infinite}.loading-text{margin-top:1rem;font-size:1rem;color:#7e22ce}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: DesignerToolbarComponent, selector: "lib-designer-toolbar", inputs: ["selectedTool", "isSaving", "workflowCode"], outputs: ["openActorTags", "toolSelected", "saveWorkflow"] }, { kind: "component", type: DesignerCanvasComponent, selector: "lib-designer-canvas", inputs: ["selectedTool"], outputs: ["clickedPosition", "subflowSelected", "stagePropertiesUpdated", "actionPropertiesUpdated"] }, { kind: "component", type: SwimlaneDialogComponent, selector: "lib-swimlane-dialog", inputs: ["visible", "swimlaneData"], outputs: ["closed", "created"] }, { kind: "component", type: ActorTagsDialogComponent, selector: "lib-actor-tags-dialog", inputs: ["visible", "workflowCode"], outputs: ["closed"] }] });
|
|
4276
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: WorkflowDesignerComponent, selector: "lib-workflow-designer", inputs: { workflowCode: "workflowCode" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvasRef"], descendants: true }], ngImport: i0, template: "<div class=\"workflow-designer\">\n <div class=\"workflow-header\">\n <h1>{{ state.workflow?.Name }}</h1>\n </div>\n\n <!-- Toolbar Component -->\n <lib-designer-toolbar [selectedTool]=\"selectedTool\" [isSaving]=\"isSaving\"\n [workflowCode]=\"state.workflow?.Code || null\" (toolSelected)=\"onToolSelected($event)\"\n (saveWorkflow)=\"saveWorkflow()\" (openActorTags)=\"openActorTagsDialog()\">\n </lib-designer-toolbar>\n\n <!-- Show loading indicator if needed -->\n <div *ngIf=\"isLoading\" class=\"loading-overlay\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\">Loading workflow...</div>\n </div>\n\n <!-- Canvas Component -->\n <lib-designer-canvas [selectedTool]=\"selectedTool\" (clickedPosition)=\"handleCanvasPositionClick($event)\"\n (subflowSelected)=\"onSubflowSelected()\" #canvasRef>\n </lib-designer-canvas>\n\n <lib-swimlane-dialog [visible]=\"showSwimlaneDialog\" [swimlaneData]=\"editingSwimlane()\"\n [isEditing]=\"editingSwimlaneIndex !== null\" (created)=\"onSwimlaneDialogFilled($event)\"\n (deleted)=\"onSwimlaneDialogDeleted()\" (closed)=\"showSwimlaneDialog = false\"></lib-swimlane-dialog>\n\n <lib-actor-tags-dialog [visible]=\"showActorTagsDialog\" [workflowCode]=\"state.workflow?.Code || null\"\n (closed)=\"showActorTagsDialog = false\"></lib-actor-tags-dialog>\n</div>\n", styles: [".workflow-designer{display:flex;flex-direction:column;height:100vh;background-color:#f8fafc}.workflow-header{padding:1rem;background-color:#fff;border-bottom:1px solid #e2e8f0;text-align:center}.workflow-header h1{font-size:1.25rem;font-weight:600;color:#334155;margin:0}.loading-overlay{position:absolute;inset:0;background-color:#ffffffb3;display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:1000}.loading-spinner{border:4px solid #f3f3f3;border-top:4px solid #d8b4fe;border-radius:50%;width:40px;height:40px;animation:spin 1s linear infinite}.loading-text{margin-top:1rem;font-size:1rem;color:#7e22ce}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: DesignerToolbarComponent, selector: "lib-designer-toolbar", inputs: ["selectedTool", "isSaving", "workflowCode"], outputs: ["openActorTags", "toolSelected", "saveWorkflow"] }, { kind: "component", type: DesignerCanvasComponent, selector: "lib-designer-canvas", inputs: ["selectedTool"], outputs: ["clickedPosition", "subflowSelected", "stagePropertiesUpdated", "actionPropertiesUpdated"] }, { kind: "component", type: SwimlaneDialogComponent, selector: "lib-swimlane-dialog", inputs: ["visible", "isEditing", "swimlaneData"], outputs: ["closed", "created", "deleted"] }, { kind: "component", type: ActorTagsDialogComponent, selector: "lib-actor-tags-dialog", inputs: ["visible", "workflowCode"], outputs: ["closed"] }] });
|
|
4143
4277
|
}
|
|
4144
4278
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WorkflowDesignerComponent, decorators: [{
|
|
4145
4279
|
type: Component,
|
|
4146
|
-
args: [{ selector: 'lib-workflow-designer', template: "<div class=\"workflow-designer\">\n <div class=\"workflow-header\">\n <h1>{{ state.workflow?.Name }}</h1>\n </div>\n\n <!-- Toolbar Component -->\n <lib-designer-toolbar [selectedTool]=\"selectedTool\" [isSaving]=\"isSaving\"\n [workflowCode]=\"state.workflow?.Code || null\" (toolSelected)=\"onToolSelected($event)\"\n (saveWorkflow)=\"saveWorkflow()\" (openActorTags)=\"openActorTagsDialog()\">\n </lib-designer-toolbar>\n\n <!-- Show loading indicator if needed -->\n <div *ngIf=\"isLoading\" class=\"loading-overlay\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\">Loading workflow...</div>\n </div>\n\n <!-- Canvas Component -->\n <lib-designer-canvas [selectedTool]=\"selectedTool\" (clickedPosition)=\"handleCanvasPositionClick($event)\"\n (subflowSelected)=\"onSubflowSelected()\" #canvasRef>\n </lib-designer-canvas>\n\n <lib-swimlane-dialog [visible]=\"showSwimlaneDialog\" [swimlaneData]=\"editingSwimlane()\"\n (created)=\"onSwimlaneDialogFilled($event)\" (closed)=\"showSwimlaneDialog = false\"></lib-swimlane-dialog>\n\n <lib-actor-tags-dialog [visible]=\"showActorTagsDialog\" [workflowCode]=\"state.workflow?.Code || null\"\n (closed)=\"showActorTagsDialog = false\"></lib-actor-tags-dialog>\n</div>\n", styles: [".workflow-designer{display:flex;flex-direction:column;height:100vh;background-color:#f8fafc}.workflow-header{padding:1rem;background-color:#fff;border-bottom:1px solid #e2e8f0;text-align:center}.workflow-header h1{font-size:1.25rem;font-weight:600;color:#334155;margin:0}.loading-overlay{position:absolute;inset:0;background-color:#ffffffb3;display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:1000}.loading-spinner{border:4px solid #f3f3f3;border-top:4px solid #d8b4fe;border-radius:50%;width:40px;height:40px;animation:spin 1s linear infinite}.loading-text{margin-top:1rem;font-size:1rem;color:#7e22ce}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
|
|
4280
|
+
args: [{ selector: 'lib-workflow-designer', template: "<div class=\"workflow-designer\">\n <div class=\"workflow-header\">\n <h1>{{ state.workflow?.Name }}</h1>\n </div>\n\n <!-- Toolbar Component -->\n <lib-designer-toolbar [selectedTool]=\"selectedTool\" [isSaving]=\"isSaving\"\n [workflowCode]=\"state.workflow?.Code || null\" (toolSelected)=\"onToolSelected($event)\"\n (saveWorkflow)=\"saveWorkflow()\" (openActorTags)=\"openActorTagsDialog()\">\n </lib-designer-toolbar>\n\n <!-- Show loading indicator if needed -->\n <div *ngIf=\"isLoading\" class=\"loading-overlay\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\">Loading workflow...</div>\n </div>\n\n <!-- Canvas Component -->\n <lib-designer-canvas [selectedTool]=\"selectedTool\" (clickedPosition)=\"handleCanvasPositionClick($event)\"\n (subflowSelected)=\"onSubflowSelected()\" #canvasRef>\n </lib-designer-canvas>\n\n <lib-swimlane-dialog [visible]=\"showSwimlaneDialog\" [swimlaneData]=\"editingSwimlane()\"\n [isEditing]=\"editingSwimlaneIndex !== null\" (created)=\"onSwimlaneDialogFilled($event)\"\n (deleted)=\"onSwimlaneDialogDeleted()\" (closed)=\"showSwimlaneDialog = false\"></lib-swimlane-dialog>\n\n <lib-actor-tags-dialog [visible]=\"showActorTagsDialog\" [workflowCode]=\"state.workflow?.Code || null\"\n (closed)=\"showActorTagsDialog = false\"></lib-actor-tags-dialog>\n</div>\n", styles: [".workflow-designer{display:flex;flex-direction:column;height:100vh;background-color:#f8fafc}.workflow-header{padding:1rem;background-color:#fff;border-bottom:1px solid #e2e8f0;text-align:center}.workflow-header h1{font-size:1.25rem;font-weight:600;color:#334155;margin:0}.loading-overlay{position:absolute;inset:0;background-color:#ffffffb3;display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:1000}.loading-spinner{border:4px solid #f3f3f3;border-top:4px solid #d8b4fe;border-radius:50%;width:40px;height:40px;animation:spin 1s linear infinite}.loading-text{margin-top:1rem;font-size:1rem;color:#7e22ce}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
|
|
4147
4281
|
}], ctorParameters: () => [{ type: WorkflowDesignerState }, { type: WorkflowDataService }, { type: i1.UtilService }], propDecorators: { canvasRef: [{
|
|
4148
4282
|
type: ViewChild,
|
|
4149
4283
|
args: ['canvasRef']
|