@brggroup/share-lib 0.0.40 → 0.0.41

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.
@@ -2748,15 +2748,15 @@ class WF_TemplateStage {
2748
2748
  Name;
2749
2749
  StageType;
2750
2750
  SeqValue;
2751
+ NumberDay;
2751
2752
  LimitValue;
2752
2753
  IsRequireUser;
2753
2754
  // #endregion properties
2754
- OrgImplCode;
2755
+ IsTempId;
2755
2756
  constructor(obj) {
2756
2757
  obj = obj || {};
2757
2758
  this.WF_TemplateStage_Id = obj.WF_TemplateStage_Id || null;
2758
2759
  this.App_Org_Id = obj.App_Org_Id || '';
2759
- this.OrgImplCode = obj.OrgImplCode || '';
2760
2760
  this.CreatedDate = obj.CreatedDate || null;
2761
2761
  this.CreatedUser = obj.CreatedUser || '';
2762
2762
  this.UpdatedDate = obj.UpdatedDate || null;
@@ -2767,8 +2767,10 @@ class WF_TemplateStage {
2767
2767
  this.Name = obj.Name || '';
2768
2768
  this.StageType = obj.StageType || '';
2769
2769
  this.SeqValue = obj.SeqValue || null;
2770
+ this.NumberDay = obj.NumberDay || null;
2770
2771
  this.LimitValue = obj.LimitValue || null;
2771
- this.IsRequireUser = obj.IsRequireUser || null;
2772
+ this.IsRequireUser = obj.IsRequireUser || false;
2773
+ this.IsTempId = obj.IsTempId || false;
2772
2774
  }
2773
2775
  }
2774
2776
  class WF_TemplateStageAction {
@@ -2793,6 +2795,10 @@ class WF_TemplateStageAction {
2793
2795
  To_StageStatus;
2794
2796
  WF_TransitionsRule_Id;
2795
2797
  // #endregion properties
2798
+ lstRoleId;
2799
+ _lstRoleId;
2800
+ lstEmailActionId;
2801
+ _lstEmailActionId;
2796
2802
  constructor(obj) {
2797
2803
  obj = obj || {};
2798
2804
  this.WF_TemplateStageAction_Id = obj.WF_TemplateStageAction_Id || null;
@@ -2814,12 +2820,32 @@ class WF_TemplateStageAction {
2814
2820
  this.To_WF_TemplateStage_Id = obj.To_WF_TemplateStage_Id || null;
2815
2821
  this.To_StageStatus = obj.To_StageStatus || '';
2816
2822
  this.WF_TransitionsRule_Id = obj.WF_TransitionsRule_Id || null;
2823
+ this.lstRoleId = obj.lstRoleId;
2824
+ this._lstRoleId = this.lstRoleId ? this.lstRoleId.split(',') : [];
2825
+ this.lstEmailActionId = obj.lstEmailActionId;
2826
+ this._lstEmailActionId = this.lstEmailActionId
2827
+ ? this.lstEmailActionId
2828
+ .split(',')
2829
+ .map((x) => Number(x.trim()))
2830
+ .filter((x) => !isNaN(x))
2831
+ : [];
2817
2832
  }
2818
2833
  }
2819
2834
  class Workflow extends WF_Template {
2820
- lstStageStatus = [];
2821
- lstActionType = [];
2822
- lstActionStatus = [];
2835
+ lstTemplateType;
2836
+ lstTemplatePrint;
2837
+ lstStageStatus;
2838
+ lstActionType;
2839
+ lstActionStatus;
2840
+ constructor(obj) {
2841
+ obj = obj || {};
2842
+ super(obj);
2843
+ this.lstTemplateType = obj.lstTemplateType || [];
2844
+ this.lstTemplatePrint = obj.lstTemplatePrint || [];
2845
+ this.lstStageStatus = obj.lstStageStatus || [];
2846
+ this.lstActionType = obj.lstActionType || [];
2847
+ this.lstActionStatus = obj.lstActionStatus || [];
2848
+ }
2823
2849
  }
2824
2850
  /**
2825
2851
  * STAGE
@@ -2830,55 +2856,93 @@ class WorkflowStage extends WF_TemplateStage {
2830
2856
  constructor(obj) {
2831
2857
  obj = obj || {};
2832
2858
  super(obj);
2833
- this.lstAction = obj.lstAction;
2859
+ this.lstAction = [];
2860
+ if (obj.lstAction) {
2861
+ obj.lstAction.forEach((x) => {
2862
+ this.lstAction = [...this.lstAction, new WorkflowAction(x)];
2863
+ });
2864
+ }
2834
2865
  this.editorOption = obj.editorOption || new WorkflowStageEditorOption();
2835
2866
  }
2836
2867
  }
2837
2868
  class WorkflowStageEditorOption {
2838
- x = 0;
2839
- y = 0;
2869
+ x;
2870
+ y;
2840
2871
  isReverse;
2841
2872
  isReverseLabel;
2842
2873
  drawerPosition;
2843
2874
  constructor(obj) {
2844
2875
  obj = obj || {};
2845
- this.x = obj.x;
2846
- this.y = obj.y;
2847
- this.isReverse = obj.isReverse;
2848
- this.isReverseLabel = obj.isReverseLabel;
2849
- this.drawerPosition = obj.drawerPosition;
2876
+ this.x = obj.x || 0;
2877
+ this.y = obj.y || 0;
2878
+ this.isReverse = obj.isReverse || false;
2879
+ this.isReverseLabel = obj.isReverseLabel || false;
2880
+ this.drawerPosition = obj.drawerPosition || '';
2850
2881
  }
2851
2882
  }
2852
2883
  /**
2853
2884
  * Action
2854
2885
  */
2855
2886
  class WorkflowAction extends WF_TemplateStageAction {
2887
+ FromStageCode;
2888
+ FromStageName;
2889
+ ToStageCode;
2856
2890
  NextStageStatus; // string
2857
- FromStage;
2858
2891
  FromSide;
2859
- ToStage;
2860
2892
  ToSide;
2861
2893
  allowBack; // true = 2 đầu, false/undefined = 1 đầu
2862
2894
  labelBack;
2863
2895
  isBackAction;
2864
- editorOption = new WorkflowActionEditorOption();
2896
+ editorOption;
2897
+ constructor(obj) {
2898
+ obj = obj || {};
2899
+ super(obj);
2900
+ this.FromStageCode = obj.FromStageCode || '';
2901
+ this.FromStageName = obj.FromStageName || '';
2902
+ this.NextStageStatus = obj.NextStageStatus || '';
2903
+ this.ToStageCode = obj.ToStageCode || '';
2904
+ this.FromSide = obj.FromSide || '';
2905
+ this.ToSide = obj.ToSide || '';
2906
+ this.allowBack = obj.allowBack || false;
2907
+ this.labelBack = obj.labelBack || '';
2908
+ this.isBackAction = obj.isBackAction || false;
2909
+ this.editorOption = new WorkflowActionEditorOption(obj.editorOption);
2910
+ }
2865
2911
  }
2866
2912
  class WorkflowActionEditorOption {
2867
2913
  points;
2868
2914
  drawerPosition;
2915
+ constructor(obj) {
2916
+ obj = obj || {};
2917
+ this.drawerPosition = obj.drawerPosition || '';
2918
+ this.points = [];
2919
+ if (obj.points) {
2920
+ obj.points.forEach((p) => {
2921
+ this.points = [...this.points, { x: p.x, y: p.y }];
2922
+ });
2923
+ }
2924
+ }
2869
2925
  }
2870
2926
  class WorkflowEditorComponent extends BaseComponent {
2871
2927
  //#region NGHIỆP VỤ
2872
2928
  lstOrg = [];
2873
- lstTemplateType = [];
2874
- lstTemplatePrint = [];
2929
+ lstRole = [];
2875
2930
  template = new Workflow();
2876
- lstStage = [
2877
- new WorkflowStage({ Code: 'start', Name: 'Start', x: -35, y: 120, StageType: 'START', SeqValue: 1 }),
2878
- new WorkflowStage({ Code: 'end', Name: 'End', x: 780, y: 120, StageType: 'END', SeqValue: 999 }),
2879
- ];
2931
+ lstStage = [];
2880
2932
  lstAction = [];
2933
+ get lstEmailAction() {
2934
+ if (this.lstAction && this.lstAction.length) {
2935
+ const res = this.lstAction.map((x) => ({
2936
+ ID: x.WF_TemplateStageAction_Id,
2937
+ Name: `${x.FromStageCode}${x.FromStageName ? ' - ' : ''}${x.FromStageName} / ${x.ActionStatus}${x.ActionText ? ' - ' : ''}${x.ActionText}`,
2938
+ }));
2939
+ return res;
2940
+ }
2941
+ return [];
2942
+ }
2881
2943
  onSave = new EventEmitter();
2944
+ onDeleteStage = new EventEmitter();
2945
+ onDeleteAction = new EventEmitter();
2882
2946
  //#endregion
2883
2947
  Math = Math;
2884
2948
  drawTemplateVisibel = false;
@@ -2907,7 +2971,7 @@ class WorkflowEditorComponent extends BaseComponent {
2907
2971
  dragStartPositions = new Map();
2908
2972
  dragStartEdgePoints = new Map();
2909
2973
  /** list các điểm đang được chọn */
2910
- lstSelectedStageCode = new Set();
2974
+ lstSelectedStageId = new Set();
2911
2975
  // SNAP point
2912
2976
  gridSize = 20; // 10 / 20 / 25 tuỳ thích
2913
2977
  snapToGrid = true;
@@ -2985,42 +3049,72 @@ class WorkflowEditorComponent extends BaseComponent {
2985
3049
  this.moveSelectedNodesBy(dx, dy);
2986
3050
  }
2987
3051
  }
2988
- ngOnInit() {
2989
- console.log('ngOnInit');
2990
- console.log('template', this.template);
2991
- console.log('lstStage', this.lstStage);
2992
- console.log('lstAction', this.lstAction);
3052
+ ngOnInit() { }
3053
+ ngAfterViewInit() {
3054
+ this.updateCanvasSize();
3055
+ }
3056
+ afterInput() {
3057
+ this.template = this.template ? new Workflow(this.template) : new Workflow();
2993
3058
  if (!this.lstStage || !this.lstStage.length) {
2994
3059
  this.lstStage = [
2995
- { Code: 'start', Name: 'Start', x: 5000 + -35, y: 5000 + 120, StageType: 'START', SeqValue: 1 },
2996
- {
3060
+ new WorkflowStage({
3061
+ Code: 'start',
3062
+ Name: 'Start',
3063
+ StageType: 'START',
3064
+ SeqValue: 1,
3065
+ editorOption: {
3066
+ x: 5000 + -35,
3067
+ y: 5000 + 120,
3068
+ },
3069
+ }),
3070
+ new WorkflowStage({
2997
3071
  Code: 'end',
2998
3072
  Name: 'End',
2999
- x: 5000 + 120,
3000
- y: 5000 + 380,
3001
3073
  StageType: 'END',
3002
- isReverseLabel: true,
3003
3074
  SeqValue: 999,
3004
- },
3075
+ editorOption: {
3076
+ x: 5000 + 120,
3077
+ y: 5000 + 300,
3078
+ isReverseLabel: true,
3079
+ },
3080
+ }),
3005
3081
  ];
3006
3082
  }
3083
+ else {
3084
+ let lstStage = [];
3085
+ this.lstStage.forEach((x) => {
3086
+ lstStage = [...lstStage, new WorkflowStage(x)];
3087
+ });
3088
+ this.lstStage = lstStage;
3089
+ }
3090
+ if (!this.lstAction || !this.lstAction.length) {
3091
+ this.lstAction = [];
3092
+ }
3093
+ else {
3094
+ let lstAction = [];
3095
+ this.lstAction.forEach((x) => {
3096
+ lstAction = [...lstAction, new WorkflowAction(x)];
3097
+ });
3098
+ this.lstAction = lstAction;
3099
+ }
3007
3100
  this.lstStage.forEach((x) => {
3008
- x.lstAction = this.lstAction.filter((y) => y.FromStage == x.Code);
3101
+ x.lstAction = this.lstAction.filter((y) => y.WF_TemplateStage_Id == x.WF_TemplateStage_Id);
3009
3102
  });
3010
- }
3011
- ngAfterViewInit() {
3012
- this.updateCanvasSize();
3103
+ console.log('WorkflowEditorComponent ngOnInit');
3104
+ console.log('template', this.template);
3105
+ console.log('lstStage', this.lstStage);
3106
+ console.log('lstAction', this.lstAction);
3013
3107
  }
3014
3108
  moveSelectedNodesBy(dx, dy) {
3015
- if (this.lstSelectedStageCode.size === 0)
3109
+ if (this.lstSelectedStageId.size === 0)
3016
3110
  return;
3017
3111
  // ⭐ UNDO SNAPSHOT
3018
3112
  this.pushUndo({
3019
3113
  type: 'move-nodes',
3020
- before: this.cloneNodePositions(this.lstSelectedStageCode),
3114
+ before: this.cloneNodePositions(this.lstSelectedStageId),
3021
3115
  });
3022
3116
  for (const n of this.lstStage) {
3023
- if (!this.lstSelectedStageCode.has(n.Code))
3117
+ if (!this.lstSelectedStageId.has(n.WF_TemplateStage_Id))
3024
3118
  continue;
3025
3119
  n.editorOption.x = this.clamp(n.editorOption.x + dx, 0, this.CANVAS_WIDTH - this.NODE_WIDTH);
3026
3120
  n.editorOption.y = this.clamp(n.editorOption.y + dy, 0, this.CANVAS_HEIGHT - this.NODE_HEIGHT);
@@ -3031,7 +3125,8 @@ class WorkflowEditorComponent extends BaseComponent {
3031
3125
  }
3032
3126
  addStage() {
3033
3127
  console.log('addStage');
3034
- const code = 'New_Stage_' + Math.round(Math.random() * 1000);
3128
+ const id = Date.now();
3129
+ const code = 'New_Stage';
3035
3130
  // tìm vị trí trống (đơn giản & hiệu quả)
3036
3131
  const baseX = 200 - this.panX;
3037
3132
  const baseY = 120 - this.panY;
@@ -3043,6 +3138,8 @@ class WorkflowEditorComponent extends BaseComponent {
3043
3138
  y += GAP_Y;
3044
3139
  }
3045
3140
  const stage = new WorkflowStage();
3141
+ stage.WF_TemplateStage_Id = id;
3142
+ stage.IsTempId = true;
3046
3143
  stage.Code = code;
3047
3144
  stage.Name = 'New Stage';
3048
3145
  stage.editorOption.x = x;
@@ -3055,13 +3152,13 @@ class WorkflowEditorComponent extends BaseComponent {
3055
3152
  this.hoverStage = stage;
3056
3153
  }
3057
3154
  isConnectingFrom(node) {
3058
- return this.connectingFrom?.node.Code === node.Code;
3155
+ return this.connectingFrom?.node.WF_TemplateStage_Id === node.WF_TemplateStage_Id;
3059
3156
  }
3060
3157
  isDraggingFrom(node) {
3061
- return this.draggingNode?.Code === node.Code;
3158
+ return this.draggingNode?.WF_TemplateStage_Id === node.WF_TemplateStage_Id;
3062
3159
  }
3063
3160
  isSelectedNode(node) {
3064
- return this.selectedStage?.Code === node.Code;
3161
+ return this.selectedStage?.WF_TemplateStage_Id === node.WF_TemplateStage_Id;
3065
3162
  }
3066
3163
  cancelConnecting() {
3067
3164
  if (this.connectingFrom) {
@@ -3072,27 +3169,32 @@ class WorkflowEditorComponent extends BaseComponent {
3072
3169
  }
3073
3170
  }
3074
3171
  //#region NGHIỆP VỤ
3172
+ onselectedRoleEmail(action) {
3173
+ action.lstRoleId = action._lstRoleId ? action._lstRoleId.join(',') : '';
3174
+ action.lstEmailActionId = action._lstEmailActionId ? action._lstEmailActionId.join(',') : '';
3175
+ console.log('onselectedRoleEmail', action);
3176
+ }
3075
3177
  addAction() {
3076
3178
  if (!this.selectedStage)
3077
3179
  return;
3078
3180
  const action = new WorkflowAction();
3079
- action.FromStage = this.selectedStage.Code;
3181
+ action.WF_TemplateStage_Id = this.selectedStage.WF_TemplateStage_Id;
3080
3182
  action.FromSide = 'right';
3081
3183
  this.selectedStage.lstAction = this.selectedStage.lstAction ? [...this.selectedStage.lstAction, action] : [action];
3082
3184
  this.lstAction = this.lstAction ? [...this.lstAction, action] : [action];
3083
3185
  }
3084
3186
  onchangeAllowBack(action) {
3085
3187
  console.log('onchangeAllowBack', action);
3086
- const stage = this.lstStage.find((x) => x.Code == action.ToStage);
3188
+ const stage = this.lstStage.find((x) => x.WF_TemplateStage_Id == action.To_WF_TemplateStage_Id);
3087
3189
  if (!stage) {
3088
3190
  this.notiService.error('Stage not found');
3089
3191
  return;
3090
3192
  }
3091
3193
  if (action.allowBack) {
3092
3194
  const newAction = new WorkflowAction();
3093
- newAction.FromStage = action.ToStage;
3195
+ newAction.WF_TemplateStage_Id = action.To_WF_TemplateStage_Id;
3094
3196
  newAction.FromSide = 'right';
3095
- newAction.ToStage = action.FromStage;
3197
+ newAction.To_WF_TemplateStage_Id = action.WF_TemplateStage_Id;
3096
3198
  newAction.ToSide = 'left';
3097
3199
  newAction.isBackAction = true;
3098
3200
  console.log('newAction', newAction);
@@ -3102,7 +3204,9 @@ class WorkflowEditorComponent extends BaseComponent {
3102
3204
  }
3103
3205
  else {
3104
3206
  action.labelBack = '';
3105
- const backAction = this.lstAction.find((x) => x.FromStage == action.ToStage && x.ToStage == action.FromStage && x.isBackAction);
3207
+ const backAction = this.lstAction.find((x) => x.WF_TemplateStage_Id == action.To_WF_TemplateStage_Id &&
3208
+ x.To_WF_TemplateStage_Id == action.WF_TemplateStage_Id &&
3209
+ x.isBackAction);
3106
3210
  console.log('remove action', backAction);
3107
3211
  if (!backAction) {
3108
3212
  this.notiService.error('Action not found');
@@ -3115,7 +3219,9 @@ class WorkflowEditorComponent extends BaseComponent {
3115
3219
  }
3116
3220
  }
3117
3221
  onchangeLabelBack(action) {
3118
- const backAction = this.lstAction.find((x) => x.FromStage == action.ToStage && x.ToStage == action.FromStage && x.isBackAction);
3222
+ const backAction = this.lstAction.find((x) => x.WF_TemplateStage_Id == action.To_WF_TemplateStage_Id &&
3223
+ x.To_WF_TemplateStage_Id == action.WF_TemplateStage_Id &&
3224
+ x.isBackAction);
3119
3225
  if (!backAction) {
3120
3226
  this.notiService.error('Action not found');
3121
3227
  }
@@ -3125,7 +3231,9 @@ class WorkflowEditorComponent extends BaseComponent {
3125
3231
  }
3126
3232
  onchangeActionText(action) {
3127
3233
  if (action.isBackAction) {
3128
- const goAction = this.lstAction.find((x) => x.FromStage == action.ToStage && x.ToStage == action.FromStage && !x.isBackAction);
3234
+ const goAction = this.lstAction.find((x) => x.WF_TemplateStage_Id == action.To_WF_TemplateStage_Id &&
3235
+ x.To_WF_TemplateStage_Id == action.WF_TemplateStage_Id &&
3236
+ !x.isBackAction);
3129
3237
  if (!goAction) {
3130
3238
  this.notiService.error('Action not found');
3131
3239
  }
@@ -3137,37 +3245,42 @@ class WorkflowEditorComponent extends BaseComponent {
3137
3245
  onchangeNextStage(action) {
3138
3246
  console.log('onchangeNextStage', action);
3139
3247
  }
3140
- async deleteNode() {
3248
+ async deleteStage() {
3249
+ console.log('deleteStage', this.selectedStage);
3141
3250
  if (!this.selectedStage)
3142
3251
  return;
3143
- if (!(await this.confirm(`Xoá node: ${this.selectedStage.Name}`)))
3252
+ if (!(await this.confirm(`Xoá stage?`, `${this.selectedStage.Code} - ${this.selectedStage.Name}`)))
3144
3253
  return;
3145
3254
  const node = this.selectedStage;
3146
3255
  // 🔹 snapshot edges liên quan
3147
- const relatedEdges = this.lstAction.filter((e) => e.FromStage === node.Code || e.ToStage === node.Code);
3256
+ const relatedEdges = this.lstAction.filter((e) => e.WF_TemplateStage_Id === node.WF_TemplateStage_Id || e.To_WF_TemplateStage_Id === node.WF_TemplateStage_Id);
3148
3257
  // 🔹 snapshot vị trí node trong mảng
3149
- const nodeIndex = this.lstStage.findIndex((n) => n.Code === node.Code);
3150
- // PUSH UNDO
3151
- this.pushUndo({
3152
- type: 'delete-node',
3153
- node: { ...node }, // clone
3154
- nodeIndex,
3155
- edges: relatedEdges.map((e) => ({ ...e })),
3156
- });
3258
+ const nodeIndex = this.lstStage.findIndex((n) => n.WF_TemplateStage_Id === node.WF_TemplateStage_Id);
3259
+ // bỏ undo khi xóa node vì bắn event ra ngoài để xóa db
3260
+ // // ⭐ PUSH UNDO
3261
+ // this.pushUndo({
3262
+ // type: 'delete-node',
3263
+ // node: { ...node }, // clone
3264
+ // nodeIndex,
3265
+ // edges: relatedEdges.map((e) => ({ ...e })),
3266
+ // });
3157
3267
  // ❌ xoá edges
3158
- this.lstAction = this.lstAction.filter((e) => e.FromStage !== node.Code && e.ToStage !== node.Code);
3268
+ this.lstAction = this.lstAction.filter((e) => e.WF_TemplateStage_Id !== node.WF_TemplateStage_Id && e.To_WF_TemplateStage_Id !== node.WF_TemplateStage_Id);
3159
3269
  // ❌ xoá node
3160
3270
  this.lstStage.splice(nodeIndex, 1);
3271
+ this.onDeleteStage.emit(node);
3161
3272
  this.selectedStage = undefined;
3162
3273
  }
3163
3274
  async deleteAction(action) {
3275
+ console.log('deleteAction', action);
3164
3276
  if (!(await this.confirm(`Delete action ???`)))
3165
3277
  return;
3166
- const stage = this.lstStage.find((x) => x.Code == action.FromStage);
3278
+ const stage = this.lstStage.find((x) => x.WF_TemplateStage_Id == action.WF_TemplateStage_Id);
3167
3279
  if (!stage)
3168
3280
  return;
3169
3281
  stage.lstAction = stage.lstAction?.filter((x) => x != action);
3170
3282
  this.lstAction = this.lstAction.filter((x) => x != action);
3283
+ this.onDeleteAction.emit(action);
3171
3284
  this.selectedAction = undefined;
3172
3285
  this.hoverAction = undefined;
3173
3286
  }
@@ -3241,6 +3354,21 @@ class WorkflowEditorComponent extends BaseComponent {
3241
3354
  this.inputActionTypeVisible = false;
3242
3355
  }
3243
3356
  //#endregion
3357
+ //#region Action role
3358
+ inputActionRoleValue = '';
3359
+ handleCloseActionRole(removedTag) {
3360
+ this.template.lstActionStatus = this.template.lstActionStatus.filter((tag) => tag !== removedTag);
3361
+ }
3362
+ handleInputConfirmActionRole() {
3363
+ if (this.inputActionRoleValue &&
3364
+ !this.template.lstActionStatus?.find((x) => x.Code === this.inputActionRoleValue)) {
3365
+ this.template.lstActionStatus = this.template.lstActionStatus
3366
+ ? [...this.template.lstActionStatus, { Code: this.inputValue }]
3367
+ : [{ Code: this.inputValue }];
3368
+ }
3369
+ this.inputActionRoleValue = '';
3370
+ }
3371
+ //#endregion
3244
3372
  //#region Action status
3245
3373
  inputVisible = false;
3246
3374
  inputValue = '';
@@ -3293,7 +3421,7 @@ class WorkflowEditorComponent extends BaseComponent {
3293
3421
  this.isSelecting = true;
3294
3422
  this.selectStart = p;
3295
3423
  this.selectEnd = p;
3296
- this.lstSelectedStageCode.clear();
3424
+ this.lstSelectedStageId.clear();
3297
3425
  }
3298
3426
  onMouseMoveCanvas(event) {
3299
3427
  if (this.isPanning && this.panStart) {
@@ -3354,9 +3482,9 @@ class WorkflowEditorComponent extends BaseComponent {
3354
3482
  let maxX = -Infinity;
3355
3483
  let maxY = -Infinity;
3356
3484
  for (const n of this.lstStage) {
3357
- if (!this.lstSelectedStageCode.has(n.Code))
3485
+ if (!this.lstSelectedStageId.has(n.WF_TemplateStage_Id))
3358
3486
  continue;
3359
- const start = this.dragStartPositions.get(n.Code);
3487
+ const start = this.dragStartPositions.get(n.WF_TemplateStage_Id);
3360
3488
  minX = Math.min(minX, start.x);
3361
3489
  minY = Math.min(minY, start.y);
3362
3490
  maxX = Math.max(maxX, start.x + nodeW);
@@ -3367,9 +3495,9 @@ class WorkflowEditorComponent extends BaseComponent {
3367
3495
  const clampedDy = this.clamp(sdy, -minY, this.CANVAS_HEIGHT - maxY);
3368
3496
  // 🔹 move nodes
3369
3497
  for (const n of this.lstStage) {
3370
- if (!this.lstSelectedStageCode.has(n.Code))
3498
+ if (!this.lstSelectedStageId.has(n.WF_TemplateStage_Id))
3371
3499
  continue;
3372
- const start = this.dragStartPositions.get(n.Code);
3500
+ const start = this.dragStartPositions.get(n.WF_TemplateStage_Id);
3373
3501
  n.editorOption.x = start.x + clampedDx;
3374
3502
  n.editorOption.y = start.y + clampedDy;
3375
3503
  }
@@ -3459,21 +3587,21 @@ class WorkflowEditorComponent extends BaseComponent {
3459
3587
  this.axisLock = null;
3460
3588
  const p = this.getSvgPoint(event);
3461
3589
  // CASE 1️⃣: node nằm trong selection → kéo cả group
3462
- if (this.lstSelectedStageCode.has(node.Code)) {
3590
+ if (this.lstSelectedStageId.has(node.WF_TemplateStage_Id)) {
3463
3591
  /* =============================
3464
3592
  * UNDO SNAPSHOT (GROUP)
3465
3593
  * ============================= */
3466
3594
  this.pushUndo({
3467
3595
  type: 'move-nodes',
3468
- before: this.cloneNodePositions(this.lstSelectedStageCode),
3596
+ before: this.cloneNodePositions(this.lstSelectedStageId),
3469
3597
  });
3470
3598
  this.draggingGroup = true;
3471
3599
  this.dragStartMouse = p;
3472
3600
  // 🔹 snapshot node positions
3473
3601
  this.dragStartPositions.clear();
3474
3602
  for (const n of this.lstStage) {
3475
- if (this.lstSelectedStageCode.has(n.Code)) {
3476
- this.dragStartPositions.set(n.Code, { x: n.editorOption.x, y: n.editorOption.y });
3603
+ if (this.lstSelectedStageId.has(n.WF_TemplateStage_Id)) {
3604
+ this.dragStartPositions.set(n.WF_TemplateStage_Id, { x: n.editorOption.x, y: n.editorOption.y });
3477
3605
  }
3478
3606
  }
3479
3607
  // 🔹 snapshot edge points
@@ -3481,21 +3609,22 @@ class WorkflowEditorComponent extends BaseComponent {
3481
3609
  for (const e of this.lstAction) {
3482
3610
  if (!e.editorOption.points?.length)
3483
3611
  continue;
3484
- if (this.lstSelectedStageCode.has(e.FromStage || '') || this.lstSelectedStageCode.has(e.ToStage || '')) {
3612
+ if (this.lstSelectedStageId.has(e.WF_TemplateStage_Id) ||
3613
+ this.lstSelectedStageId.has(e.To_WF_TemplateStage_Id)) {
3485
3614
  this.dragStartEdgePoints.set(e, e.editorOption.points.map((p) => ({ x: p.x, y: p.y })));
3486
3615
  }
3487
3616
  }
3488
3617
  return;
3489
3618
  }
3490
3619
  // CASE 2️⃣: node chưa được chọn → kéo node đơn
3491
- this.lstSelectedStageCode.clear();
3620
+ this.lstSelectedStageId.clear();
3492
3621
  // this.selectedNodeIds.add(node.id);
3493
3622
  /* =============================
3494
3623
  * UNDO SNAPSHOT (1 NODE)
3495
3624
  * ============================= */
3496
3625
  this.pushUndo({
3497
3626
  type: 'move-nodes',
3498
- before: this.cloneNodePositions(new Set([node.Code])),
3627
+ before: this.cloneNodePositions(new Set([node.WF_TemplateStage_Id])),
3499
3628
  });
3500
3629
  this.draggingNode = node;
3501
3630
  this.dragStartX = event.clientX;
@@ -3507,26 +3636,31 @@ class WorkflowEditorComponent extends BaseComponent {
3507
3636
  onClickStage(node) {
3508
3637
  console.log('onClickStage', node);
3509
3638
  this.hoverStage = undefined;
3639
+ this.selectedStage = undefined;
3510
3640
  if (this.isDragging)
3511
3641
  return;
3512
3642
  if (this.connectingFrom) {
3513
- if (this.connectingFrom.node.Code !== node.Code) {
3514
- const existed = this.lstAction.some((e) => e.FromStage === this.connectingFrom.node.Code && e.ToStage === node.Code);
3643
+ if (this.connectingFrom.node.WF_TemplateStage_Id !== node.WF_TemplateStage_Id) {
3644
+ const existed = this.lstAction.some((e) => e.WF_TemplateStage_Id === this.connectingFrom.node.WF_TemplateStage_Id &&
3645
+ e.To_WF_TemplateStage_Id === node.WF_TemplateStage_Id);
3515
3646
  if (!existed) {
3516
3647
  const newAction = new WorkflowAction();
3517
- newAction.FromStage = this.connectingFrom.node.Code;
3648
+ newAction.WF_TemplateStage_Id = this.connectingFrom.node.WF_TemplateStage_Id;
3518
3649
  newAction.FromSide = this.connectingFrom.side;
3519
- newAction.ToStage = node.Code;
3650
+ newAction.To_WF_TemplateStage_Id = node.WF_TemplateStage_Id;
3520
3651
  newAction.ToSide = 'left';
3521
3652
  // ⭐ NẾU CÓ WAYPOINT → MANUAL ROUTE
3522
3653
  if (this.connectingPoints.length > 0) {
3523
3654
  newAction.editorOption.points = [...this.connectingPoints];
3524
3655
  }
3525
3656
  this.lstAction.push(newAction);
3526
- const stage = this.lstStage.find((x) => x.Code == newAction.FromStage);
3657
+ const stage = this.lstStage.find((x) => x.WF_TemplateStage_Id == newAction.WF_TemplateStage_Id);
3527
3658
  if (stage) {
3528
3659
  stage.lstAction = stage.lstAction ? [...stage.lstAction, newAction] : [newAction];
3529
3660
  }
3661
+ console.log('from action', this.connectingFrom.node);
3662
+ console.log('to action', node);
3663
+ console.log('newAction', newAction);
3530
3664
  }
3531
3665
  }
3532
3666
  this.cancelConnecting();
@@ -3534,11 +3668,11 @@ class WorkflowEditorComponent extends BaseComponent {
3534
3668
  }
3535
3669
  if (this.isDragging)
3536
3670
  return;
3537
- if (this.lstSelectedStageCode.size)
3671
+ if (this.lstSelectedStageId.size)
3538
3672
  return;
3539
3673
  // if (node.id == 'start' || node.id == 'end') return;
3674
+ this.hoverStage = node;
3540
3675
  this.selectedStage = node;
3541
- console.log(this.selectedStage);
3542
3676
  }
3543
3677
  //#endregion
3544
3678
  //#region EDGE action
@@ -3569,10 +3703,14 @@ class WorkflowEditorComponent extends BaseComponent {
3569
3703
  return;
3570
3704
  }
3571
3705
  if (doAction) {
3572
- this.selectedAction = edge;
3573
- this.selectedBackAction = this.lstAction.find((x) => x.isBackAction == true &&
3574
- x.FromStage == this.selectedAction?.ToStage &&
3575
- x.ToStage == this.selectedAction?.FromStage);
3706
+ // k cấu hình ở đây nữa, cấu trong stage
3707
+ // this.selectedAction = edge;
3708
+ // this.selectedBackAction = this.lstAction.find(
3709
+ // (x) =>
3710
+ // x.isBackAction == true &&
3711
+ // x.WF_TemplateStage_Id == this.selectedAction?.To_WF_TemplateStage_Id &&
3712
+ // x.To_WF_TemplateStage_Id == this.selectedAction?.WF_TemplateStage_Id,
3713
+ // );
3576
3714
  }
3577
3715
  else {
3578
3716
  // 👉 SINGLE CLICK (chờ xem có dbl không)
@@ -3622,20 +3760,21 @@ class WorkflowEditorComponent extends BaseComponent {
3622
3760
  * CLICK IN (LEFT) → KẾT THÚC
3623
3761
  * ============================= */
3624
3762
  if (side === 'left' && this.connectingFrom) {
3625
- if (this.connectingFrom.node.Code !== node.Code) {
3626
- const existed = this.lstAction.some((e) => e.FromStage === this.connectingFrom.node.Code && e.ToStage === node.Code);
3763
+ if (this.connectingFrom.node.WF_TemplateStage_Id !== node.WF_TemplateStage_Id) {
3764
+ const existed = this.lstAction.some((e) => e.WF_TemplateStage_Id === this.connectingFrom.node.WF_TemplateStage_Id &&
3765
+ e.To_WF_TemplateStage_Id === node.WF_TemplateStage_Id);
3627
3766
  if (!existed) {
3628
3767
  const newAction = new WorkflowAction();
3629
- newAction.FromStage = this.connectingFrom.node.Code;
3768
+ newAction.WF_TemplateStage_Id = this.connectingFrom.node.WF_TemplateStage_Id;
3630
3769
  newAction.FromSide = this.connectingFrom.side;
3631
- newAction.ToStage = node.Code;
3770
+ newAction.To_WF_TemplateStage_Id = node.WF_TemplateStage_Id;
3632
3771
  newAction.ToSide = 'left';
3633
3772
  // ⭐ NẾU CÓ WAYPOINT → MANUAL ROUTE
3634
3773
  if (this.connectingPoints.length > 0) {
3635
3774
  newAction.editorOption.points = [...this.connectingPoints];
3636
3775
  }
3637
3776
  this.lstAction.push(newAction);
3638
- const stage = this.lstStage.find((x) => x.Code == newAction.FromStage);
3777
+ const stage = this.lstStage.find((x) => x.WF_TemplateStage_Id == newAction.WF_TemplateStage_Id);
3639
3778
  if (stage) {
3640
3779
  stage.lstAction = stage.lstAction ? [...stage.lstAction, newAction] : [newAction];
3641
3780
  }
@@ -3666,10 +3805,6 @@ class WorkflowEditorComponent extends BaseComponent {
3666
3805
  if (!edge.editorOption.points)
3667
3806
  return;
3668
3807
  edge.editorOption.points.splice(index, 1);
3669
- // Nếu xoá hết → quay về auto route
3670
- if (edge.editorOption.points.length === 0) {
3671
- delete edge.editorOption.points;
3672
- }
3673
3808
  }
3674
3809
  //#endregion
3675
3810
  //#region UNDO REDU
@@ -3678,8 +3813,8 @@ class WorkflowEditorComponent extends BaseComponent {
3678
3813
  cloneNodePositions(nodeIds) {
3679
3814
  const map = new Map();
3680
3815
  for (const n of this.lstStage) {
3681
- if (nodeIds.has(n.Code)) {
3682
- map.set(n.Code, { x: n.editorOption.x, y: n.editorOption.y });
3816
+ if (nodeIds.has(n.WF_TemplateStage_Id)) {
3817
+ map.set(n.WF_TemplateStage_Id, { x: n.editorOption.x, y: n.editorOption.y });
3683
3818
  }
3684
3819
  }
3685
3820
  return map;
@@ -3687,7 +3822,7 @@ class WorkflowEditorComponent extends BaseComponent {
3687
3822
  pushAlignUndo() {
3688
3823
  this.pushUndo({
3689
3824
  type: 'move-nodes',
3690
- before: this.cloneNodePositions(this.lstSelectedStageCode),
3825
+ before: this.cloneNodePositions(this.lstSelectedStageId),
3691
3826
  });
3692
3827
  }
3693
3828
  pushUndo(action) {
@@ -3721,7 +3856,7 @@ class WorkflowEditorComponent extends BaseComponent {
3721
3856
  });
3722
3857
  // restore
3723
3858
  action.before.forEach((pos, id) => {
3724
- const node = this.lstStage.find((n) => n.Code === id);
3859
+ const node = this.lstStage.find((n) => n.WF_TemplateStage_Id === id);
3725
3860
  if (node) {
3726
3861
  node.editorOption.x = pos.x;
3727
3862
  node.editorOption.y = pos.y;
@@ -3739,8 +3874,8 @@ class WorkflowEditorComponent extends BaseComponent {
3739
3874
  case 'delete-node': {
3740
3875
  const nodeId = action.node.id;
3741
3876
  // redo = xoá lại
3742
- this.lstAction = this.lstAction.filter((e) => e.FromStage !== nodeId && e.ToStage !== nodeId);
3743
- const idx = this.lstStage.findIndex((n) => n.Code === nodeId);
3877
+ this.lstAction = this.lstAction.filter((e) => e.WF_TemplateStage_Id !== nodeId && e.To_WF_TemplateStage_Id !== nodeId);
3878
+ const idx = this.lstStage.findIndex((n) => n.WF_TemplateStage_Id === nodeId);
3744
3879
  if (idx >= 0)
3745
3880
  this.lstStage.splice(idx, 1);
3746
3881
  this.undoStack.push(action);
@@ -3755,7 +3890,7 @@ class WorkflowEditorComponent extends BaseComponent {
3755
3890
  before: after,
3756
3891
  });
3757
3892
  action.before.forEach((pos, id) => {
3758
- const node = this.lstStage.find((n) => n.Code === id);
3893
+ const node = this.lstStage.find((n) => n.WF_TemplateStage_Id === id);
3759
3894
  if (node) {
3760
3895
  node.editorOption.x = pos.x;
3761
3896
  node.editorOption.y = pos.y;
@@ -3771,10 +3906,10 @@ class WorkflowEditorComponent extends BaseComponent {
3771
3906
  NODE_HEIGHT = 80;
3772
3907
  //#region ALIGN
3773
3908
  getSelectedNodes() {
3774
- return this.lstStage.filter((n) => this.lstSelectedStageCode.has(n.Code));
3909
+ return this.lstStage.filter((n) => this.lstSelectedStageId.has(n.WF_TemplateStage_Id));
3775
3910
  }
3776
3911
  alignLeft() {
3777
- if (this.lstSelectedStageCode.size < 2)
3912
+ if (this.lstSelectedStageId.size < 2)
3778
3913
  return;
3779
3914
  this.pushAlignUndo();
3780
3915
  const nodes = this.getSelectedNodes();
@@ -3782,7 +3917,7 @@ class WorkflowEditorComponent extends BaseComponent {
3782
3917
  nodes.forEach((n) => (n.editorOption.x = minX));
3783
3918
  }
3784
3919
  alignCenter() {
3785
- if (this.lstSelectedStageCode.size < 2)
3920
+ if (this.lstSelectedStageId.size < 2)
3786
3921
  return;
3787
3922
  this.pushAlignUndo();
3788
3923
  const nodes = this.getSelectedNodes();
@@ -3793,7 +3928,7 @@ class WorkflowEditorComponent extends BaseComponent {
3793
3928
  });
3794
3929
  }
3795
3930
  alignRight() {
3796
- if (this.lstSelectedStageCode.size < 2)
3931
+ if (this.lstSelectedStageId.size < 2)
3797
3932
  return;
3798
3933
  this.pushAlignUndo();
3799
3934
  const nodes = this.getSelectedNodes();
@@ -3801,7 +3936,7 @@ class WorkflowEditorComponent extends BaseComponent {
3801
3936
  nodes.forEach((n) => (n.editorOption.x = maxX - this.NODE_WIDTH));
3802
3937
  }
3803
3938
  alignTop() {
3804
- if (this.lstSelectedStageCode.size < 2)
3939
+ if (this.lstSelectedStageId.size < 2)
3805
3940
  return;
3806
3941
  this.pushAlignUndo();
3807
3942
  const nodes = this.getSelectedNodes();
@@ -3809,7 +3944,7 @@ class WorkflowEditorComponent extends BaseComponent {
3809
3944
  nodes.forEach((n) => (n.editorOption.y = minY));
3810
3945
  }
3811
3946
  alignMiddle() {
3812
- if (this.lstSelectedStageCode.size < 2)
3947
+ if (this.lstSelectedStageId.size < 2)
3813
3948
  return;
3814
3949
  this.pushAlignUndo();
3815
3950
  const nodes = this.getSelectedNodes();
@@ -3820,7 +3955,7 @@ class WorkflowEditorComponent extends BaseComponent {
3820
3955
  });
3821
3956
  }
3822
3957
  alignBottom() {
3823
- if (this.lstSelectedStageCode.size < 2)
3958
+ if (this.lstSelectedStageId.size < 2)
3824
3959
  return;
3825
3960
  this.pushAlignUndo();
3826
3961
  const nodes = this.getSelectedNodes();
@@ -3828,7 +3963,7 @@ class WorkflowEditorComponent extends BaseComponent {
3828
3963
  nodes.forEach((n) => (n.editorOption.y = maxY - this.NODE_HEIGHT));
3829
3964
  }
3830
3965
  distributeHorizontal() {
3831
- if (this.lstSelectedStageCode.size < 3)
3966
+ if (this.lstSelectedStageId.size < 3)
3832
3967
  return;
3833
3968
  this.pushAlignUndo();
3834
3969
  const nodes = this.getSelectedNodes().sort((a, b) => a.editorOption.x - b.editorOption.x);
@@ -3847,7 +3982,7 @@ class WorkflowEditorComponent extends BaseComponent {
3847
3982
  });
3848
3983
  }
3849
3984
  distributeVertical() {
3850
- if (this.lstSelectedStageCode.size < 3)
3985
+ if (this.lstSelectedStageId.size < 3)
3851
3986
  return;
3852
3987
  this.pushAlignUndo();
3853
3988
  const nodes = this.getSelectedNodes().sort((a, b) => a.editorOption.y - b.editorOption.y);
@@ -3889,8 +4024,12 @@ class WorkflowEditorComponent extends BaseComponent {
3889
4024
  //#endregion
3890
4025
  //#region HELPER
3891
4026
  isEdgeReversed(edge) {
3892
- const from = this.getNodeCenter(this.lstStage.find((x) => x.Code == edge.FromStage), 'right');
3893
- const to = this.getNodeCenter(this.lstStage.find((x) => x.Code == edge.ToStage), 'left');
4027
+ const x = this.lstStage.find((x) => x.WF_TemplateStage_Id == edge.WF_TemplateStage_Id);
4028
+ const y = this.lstStage.find((x) => x.WF_TemplateStage_Id == edge.To_WF_TemplateStage_Id);
4029
+ if (!x || !y)
4030
+ return false;
4031
+ const from = this.getNodeCenter(x, 'right');
4032
+ const to = this.getNodeCenter(y, 'left');
3894
4033
  return to.x < from.x;
3895
4034
  }
3896
4035
  getEdgeLabelPosition(edge) {
@@ -3900,8 +4039,12 @@ class WorkflowEditorComponent extends BaseComponent {
3900
4039
  return { x: mid.x, y: mid.y };
3901
4040
  }
3902
4041
  // fallback: giữa from → to
3903
- const from = this.getNodeCenter(this.lstStage.find((x) => x.Code == edge.FromStage), 'right');
3904
- const to = this.getNodeCenter(this.lstStage.find((x) => x.Code == edge.ToStage), 'left');
4042
+ const x = this.lstStage.find((x) => x.WF_TemplateStage_Id == edge.WF_TemplateStage_Id);
4043
+ const y = this.lstStage.find((x) => x.WF_TemplateStage_Id == edge.To_WF_TemplateStage_Id);
4044
+ if (!x || !y)
4045
+ return { x: 0, y: 0 };
4046
+ const from = this.getNodeCenter(x, 'right');
4047
+ const to = this.getNodeCenter(y, 'left');
3905
4048
  return {
3906
4049
  x: (from.x + to.x) / 2,
3907
4050
  y: (from.y + to.y) / 2,
@@ -3960,10 +4103,10 @@ class WorkflowEditorComponent extends BaseComponent {
3960
4103
  return Math.max(0, index);
3961
4104
  }
3962
4105
  getEdgeFullPoints(edge) {
3963
- if (!edge.FromStage || !edge.ToStage)
4106
+ if (!edge.WF_TemplateStage_Id || !edge.To_WF_TemplateStage_Id)
3964
4107
  return null;
3965
- const from = this.getNode(edge.FromStage);
3966
- const to = this.getNode(edge.ToStage);
4108
+ const from = this.getNode(edge.WF_TemplateStage_Id);
4109
+ const to = this.getNode(edge.To_WF_TemplateStage_Id);
3967
4110
  return [
3968
4111
  { x: from.editorOption.x + 160, y: from.editorOption.y + 40 },
3969
4112
  ...(edge.editorOption.points || []),
@@ -3985,20 +4128,20 @@ class WorkflowEditorComponent extends BaseComponent {
3985
4128
  return Math.hypot(p.x - proj.x, p.y - proj.y);
3986
4129
  }
3987
4130
  isPositionOccupied(x, y) {
3988
- return this.lstStage.some((n) => Math.abs(n.editorOption.x - x) < 160 && Math.abs(n.editorOption.y - y) < 80);
4131
+ return this.lstStage.some((n) => Math.abs(n.editorOption?.x - x) < 160 && Math.abs(n.editorOption?.y - y) < 80);
3989
4132
  }
3990
4133
  getCanvasWidth() {
3991
4134
  // return 3000;
3992
4135
  const PADDING = 200;
3993
4136
  const MIN_WIDTH = 800;
3994
- const maxX = Math.max(...this.lstStage.map((n) => (n.StageType == 'END' ? n.editorOption.x : n.editorOption.x + 160)), // 160 = node width
4137
+ const maxX = Math.max(...this.lstStage.map((n) => (n.StageType == 'END' ? n.editorOption?.x : n.editorOption?.x + 160)), // 160 = node width
3995
4138
  MIN_WIDTH);
3996
4139
  return maxX + PADDING;
3997
4140
  }
3998
4141
  getCanvasHeight() {
3999
4142
  // return 2000;
4000
4143
  const PADDING = 100;
4001
- const maxY = Math.max(...this.lstStage.map((n) => n.editorOption.y + 80), 400);
4144
+ const maxY = Math.max(...this.lstStage.map((n) => n.editorOption?.y + 80), 400);
4002
4145
  return maxY + PADDING;
4003
4146
  }
4004
4147
  /* =============================
@@ -4024,7 +4167,7 @@ class WorkflowEditorComponent extends BaseComponent {
4024
4167
  const y1 = Math.min(this.selectStart.y, this.selectEnd.y);
4025
4168
  const x2 = Math.max(this.selectStart.x, this.selectEnd.x);
4026
4169
  const y2 = Math.max(this.selectStart.y, this.selectEnd.y);
4027
- this.lstSelectedStageCode.clear();
4170
+ this.lstSelectedStageId.clear();
4028
4171
  for (const n of this.lstStage) {
4029
4172
  const nx1 = n.editorOption.x;
4030
4173
  const ny1 = n.editorOption.y;
@@ -4032,7 +4175,7 @@ class WorkflowEditorComponent extends BaseComponent {
4032
4175
  const ny2 = n.editorOption.y + 80;
4033
4176
  const intersect = nx2 >= x1 && nx1 <= x2 && ny2 >= y1 && ny1 <= y2;
4034
4177
  if (intersect) {
4035
- this.lstSelectedStageCode.add(n.Code);
4178
+ this.lstSelectedStageId.add(n.WF_TemplateStage_Id);
4036
4179
  }
4037
4180
  }
4038
4181
  }
@@ -4050,15 +4193,15 @@ class WorkflowEditorComponent extends BaseComponent {
4050
4193
  return Math.round(value / this.gridSize) * this.gridSize;
4051
4194
  }
4052
4195
  getNode(id) {
4053
- return this.lstStage.find((n) => n.Code === id);
4196
+ return this.lstStage.find((n) => n.WF_TemplateStage_Id === id);
4054
4197
  }
4055
4198
  //#endregion
4056
4199
  //#region BUILD PATH
4057
4200
  buildPath(edge) {
4058
- if (!edge.FromStage || !edge.ToStage)
4201
+ if (!edge.WF_TemplateStage_Id || !edge.To_WF_TemplateStage_Id)
4059
4202
  return '';
4060
- const from = this.getNode(edge.FromStage);
4061
- const to = this.getNode(edge.ToStage);
4203
+ const from = this.getNode(edge.WF_TemplateStage_Id);
4204
+ const to = this.getNode(edge.To_WF_TemplateStage_Id);
4062
4205
  const start = {
4063
4206
  x: from.editorOption.x + (from.editorOption.isReverse ? 0 : 160),
4064
4207
  y: from.editorOption.y + 40,
@@ -4224,7 +4367,7 @@ class WorkflowEditorComponent extends BaseComponent {
4224
4367
  const x1 = from.node.editorOption.isReverse ? from.node.editorOption.x + 160 : from.node.editorOption.x;
4225
4368
  const y1 = from.node.editorOption.y + 40;
4226
4369
  return this.lstStage.some((n) => {
4227
- if (n.Code === from.node.Code)
4370
+ if (n.WF_TemplateStage_Id === from.node.WF_TemplateStage_Id)
4228
4371
  return false;
4229
4372
  // node phải nằm giữa theo trục X
4230
4373
  if (!this.isNodeBetweenX(x1, x2, n))
@@ -4263,7 +4406,7 @@ class WorkflowEditorComponent extends BaseComponent {
4263
4406
  const x2 = toX;
4264
4407
  const y2 = routeY;
4265
4408
  return !this.lstStage.some((n) => {
4266
- if (n.Code === from.node.Code)
4409
+ if (n.WF_TemplateStage_Id === from.node.WF_TemplateStage_Id)
4267
4410
  return false;
4268
4411
  // node phải nằm giữa theo trục X
4269
4412
  if (!this.isNodeBetweenX(x1, x2, n))
@@ -4273,7 +4416,7 @@ class WorkflowEditorComponent extends BaseComponent {
4273
4416
  });
4274
4417
  }
4275
4418
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WorkflowEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
4276
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: WorkflowEditorComponent, isStandalone: true, selector: "app-workflow-editor", inputs: { lstOrg: "lstOrg", lstTemplateType: "lstTemplateType", lstTemplatePrint: "lstTemplatePrint", template: "template", lstStage: "lstStage", lstAction: "lstAction" }, outputs: { onSave: "onSave" }, host: { listeners: { "window:keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, static: true }, { propertyName: "svgRef", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "inputStageStatusElement", first: true, predicate: ["inputStageStatusElement"], descendants: true }, { propertyName: "inputActionTypeElement", first: true, predicate: ["inputActionTypeElement"], descendants: true }, { propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n #canvasRef\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n [style.width.px]=\"CANVAS_WIDTH\"\n [style.height.px]=\"CANVAS_HEIGHT\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n>\n <!-- \n\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\" \n\n style=\"width: 100%; height: calc(100vh - 120px)\"\n \n -->\n\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Template setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> T\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger nz-tooltip=\"Save\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Add stage\" (click)=\"addStage()\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n\n <span class=\"divider\"></span>\n\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n\n <span class=\"divider\"></span>\n\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.transform]=\"'translate(' + panX + 'px,' + panY + 'px)'\"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- <div class=\"zoom-toolbar\">\n <button nz-button nzSize=\"small\" (click)=\"zoomOut()\">\u2212</button>\n <span>{{ zoom * 100 | number: \"1.0-0\" }}%</span>\n <button nz-button nzSize=\"small\" (click)=\"zoomIn()\">+</button>\n </div> -->\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g [attr.transform]=\"svgTransform\">\n <!-- DEFS -->\n <defs>\n <!-- glow effect -->\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <!-- arrow markers -->\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-blue-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <path\n class=\"edge\"\n [attr.id]=\"'edge-path-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-blue)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-blue-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- text b\u00E1m theo line -->\n <!-- \n <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text> \n \n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text>\n -->\n\n <!-- text th\u1EB3ng n\u1EB1m ngang -->\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER (LU\u00D4N TR\u00CAN C\u00D9NG) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-red-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text>\n\n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text> -->\n\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- preview -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- lstStage -->\n @for (n of lstStage; track $index) {\n @if (n.StageType == \"NODE\") {\n <nz-card\n #nodeEl\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"n == selectedStage || n == hoverStage || lstSelectedStageCode.has(n.Code)\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">{{ n.Code }}</div>\n\n <div>{{ n.Name }}</div>\n\n @if (!n.editorOption.isReverse) {\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n } @else {\n <div class=\"connector connector-right reverse\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left reverse\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n }\n </nz-card>\n }\n <!-- START NODE -->\n @else if (n.StageType === \"START\") {\n <nz-card\n class=\"workflow-node workflow-node-start\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">&nbsp;</div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageCode.has(n.Code)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? -83 : 1\"\n [nzColor]=\"'green'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right connector-start\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n </nz-card>\n }\n\n <!-- END NODE -->\n @else if (n.StageType === \"END\") {\n <nz-card\n class=\"workflow-node workflow-node-end\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">&nbsp;</div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageCode.has(n.Code)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? 65 : -5\"\n [nzColor]=\"'red'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-end\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n }\n\n <!-- POINTS -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverAction!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- TEMPLATE -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; Template </ng-template>\n <ng-container *nzDrawerContent>\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"template.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"template.Name\"></extend-input>\n <extend-select\n [label]=\"'Type'\"\n [lstItem]=\"lstTemplateType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.DocType\"\n ></extend-select>\n <extend-textarea [label]=\"'Desscription'\" [(_ngModel)]=\"template.Description\"></extend-textarea>\n <extend-select\n [label]=\"'Print template'\"\n [lstItem]=\"lstTemplatePrint\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.TemplatePrint\"\n ></extend-select>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"template.IsActive\"></extend-checkbox>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Stage status</h3>\n\n @for (tag of template.lstStageStatus; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableStageStatus(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseStageStatus(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstStageStatus && template.lstStageStatus.length\" />\n\n @if (!inputStageStatusVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputStageStatus()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputStageStatusElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputStageStatusCode\"\n (keydown.enter)=\"inputStageStatusNameElement.select()\"\n />\n <input\n #inputStageStatusNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputStageStatusName\"\n (blur)=\"handleInputStageStatusConfirm()\"\n (keydown.enter)=\"handleInputStageStatusConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Action type</h3>\n\n @for (tag of template.lstActionType; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableActionType(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseActionType(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionType && template.lstActionType.length\" />\n\n @if (!inputActionTypeVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputActionType()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputActionTypeElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputActionTypeCode\"\n (keydown.enter)=\"inputActionTypeNameElement.select()\"\n />\n <input\n #inputActionTypeNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputActionTypeName\"\n (blur)=\"handleInputActionTypeConfirm()\"\n (keydown.enter)=\"handleInputActionTypeConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Action status</h3>\n\n @for (tag of template.lstActionStatus; track tag) {\n <nz-tag [nzMode]=\"checkRemoveableActionStatus(tag) ? 'closeable' : 'default'\" (nzOnClose)=\"handleClose(tag)\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionStatus && template.lstActionStatus.length\" />\n\n @if (!inputVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n <nz-icon nzType=\"plus\" />\n New Action status\n </nz-tag>\n } @else {\n <input\n #inputElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"+ New Action status\"\n [(ngModel)]=\"inputValue\"\n (blur)=\"handleInputConfirm()\"\n (keydown.enter)=\"handleInputConfirm()\"\n />\n }\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\">\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n <button nz-button nzDanger (click)=\"save()\">Save</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- STAGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleStage\"\n [nzPlacement]=\"selectedStage?.editorOption?.drawerPosition ? selectedStage?.editorOption?.drawerPosition : 'right'\"\n [nzVisible]=\"!!selectedStage\"\n [nzWidth]=\"750\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedStage = undefined\"\n>\n <ng-template #drawerTitleStage>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedStage) {\n @if (selectedStage.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n STAGE\n } @else {\n STAGE\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedStage\">\n <nz-radio-group [(ngModel)]=\"selectedStage.StageType\">\n <label nz-radio nzValue=\"START\" [nzDisabled]=\"selectedStage.StageType != 'START'\">START</label>\n <label nz-radio nzValue=\"NODE\" [nzDisabled]=\"selectedStage.StageType != 'NODE'\">NODE</label>\n <label nz-radio nzValue=\"END\" [nzDisabled]=\"selectedStage.StageType != 'END'\">END</label>\n </nz-radio-group>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"32\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Code'\"\n [layOutType]=\"'vertical'\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Code\"\n ></extend-input>\n\n <extend-textarea\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Name'\"\n [layOutType]=\"'vertical'\"\n [autoSize]=\"true\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Name\"\n ></extend-textarea>\n </div>\n\n <div nz-row [nzGutter]=\"32\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Sequence'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedStage.SeqValue\"\n ></extend-input-number>\n\n <extend-select\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Org implement'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstOrg\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedStage.OrgImplCode\"\n ></extend-select>\n </div>\n\n @if ([\"START\", \"END\"].indexOf(selectedStage.StageType) < 0) {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverse\"\n ></extend-checkbox>\n\n <extend-checkbox\n [label]=\"'Require user action'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.IsRequireUser\"\n ></extend-checkbox>\n } @else {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverseLabel\"\n ></extend-checkbox>\n }\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\">\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;List Action</h3>\n <div nz-col>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"addAction()\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n </div>\n </div>\n\n <nz-table\n nzSize=\"small\"\n [nzData]=\"selectedStage.lstAction || []\"\n [nzShowPagination]=\"false\"\n [nzNoResult]=\"'&nbsp;'\"\n >\n <thead>\n <tr [hidden]=\"true\">\n <th nzWidth=\"50px\"></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (action of selectedStage.lstAction; track $index) {\n <tr>\n <td>\n <nz-icon\n nzType=\"delete\"\n nzTheme=\"outline\"\n class=\"color-warn cursor-pointer icon-size-16\"\n (click)=\"$event.stopPropagation(); deleteAction(action)\"\n ></nz-icon>\n </td>\n <td (click)=\"hoverAction = action\">\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"action.ActionText\"\n (_ngModelChange)=\"onchangeActionText(action)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(action)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.NextStageStatus\"\n ></extend-select>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </nz-table>\n\n <box [height]=\"16\"></box>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedStage && selectedStage.editorOption.drawerPosition == 'left' ? 'end' : 'start'\"\n >\n <button nz-button (click)=\"selectedStage = undefined\">Close</button>\n <button\n *ngIf=\"selectedStage && ['START', 'END'].indexOf(selectedStage.StageType) < 0\"\n nz-button\n nzDanger\n (click)=\"deleteNode()\"\n >\n Delete\n </button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- EDGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleAction\"\n nzTitle=\"ACTION\"\n [nzPlacement]=\"selectedAction?.editorOption?.drawerPosition ? selectedAction?.editorOption?.drawerPosition : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"750\"\n [nzVisible]=\"!!selectedAction\"\n [nzFooter]=\"footerTplAction\"\n (nzOnClose)=\"selectedAction = undefined\"\n>\n <ng-template #drawerTitleAction>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedAction) {\n @if (selectedAction.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n ACTION\n } @else {\n ACTION\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedAction\">\n <strong>{{ selectedAction.FromStage }} -> {{ selectedAction.ToStage }}</strong>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(selectedAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.NextStageStatus\"\n ></extend-select>\n </div>\n\n <!-- <box [height]=\"16\"></box> -->\n <nz-divider></nz-divider>\n\n <extend-checkbox\n [label]=\"'Allow back'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedAction.allowBack\"\n (_ngModelChange)=\"onchangeAllowBack(selectedAction)\"\n ></extend-checkbox>\n\n <box [height]=\"16\"></box>\n\n @if (selectedAction.allowBack) {\n <strong>{{ selectedAction.ToStage }} -> {{ selectedAction.FromStage }}</strong>\n\n @if (selectedBackAction) {\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedBackAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedBackAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(selectedBackAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.NextStageStatus\"\n ></extend-select>\n </div>\n }\n }\n </ng-container>\n </ng-container>\n <ng-template #footerTplAction>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedAction && selectedAction.editorOption.drawerPosition == 'left' ? 'end' : 'start'\"\n >\n <button nz-button (click)=\"selectedAction = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteAction(selectedAction!)\">Delete</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- setting editor -->\n<nz-drawer\n [nzTitle]=\"drawSettingTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"settingVisible\"\n (nzOnClose)=\"settingVisible = false\"\n>\n <ng-template #drawSettingTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox [label]=\"'Show grid'\" [labelSpan]=\"0\" [(_ngModel)]=\"wfcSetting.ShowGrid\"></extend-checkbox>\n\n <box [height]=\"16\"></box>\n </div>\n </ng-container>\n</nz-drawer>\n", styles: ["@charset \"UTF-8\";.workflow-canvas{position:relative;width:100%;height:600px;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:10000px;height:10000px}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node-start{background-color:unset;display:flex;justify-content:right}.workflow-node-end{background-color:unset;display:flex}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-3px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-6px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}.zoom-toolbar{position:absolute;top:8px;left:8px;z-index:10;display:flex;align-items:center;gap:6px;background:#fff;padding:4px 6px;border-radius:6px;box-shadow:0 2px 6px #00000026}.zoom-toolbar span{min-width:40px;text-align:center;font-size:12px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.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: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzCardModule }, { kind: "component", type: i3$1.NzCardComponent, selector: "nz-card", inputs: ["nzBordered", "nzLoading", "nzHoverable", "nzBodyStyle", "nzCover", "nzActions", "nzType", "nzSize", "nzTitle", "nzExtra"], exportAs: ["nzCard"] }, { kind: "ngmodule", type: NzDrawerModule }, { kind: "component", type: i4$1.NzDrawerComponent, selector: "nz-drawer", inputs: ["nzContent", "nzCloseIcon", "nzClosable", "nzMaskClosable", "nzMask", "nzCloseOnNavigation", "nzNoAnimation", "nzKeyboard", "nzTitle", "nzExtra", "nzFooter", "nzPlacement", "nzSize", "nzMaskStyle", "nzBodyStyle", "nzWrapClassName", "nzWidth", "nzHeight", "nzZIndex", "nzOffsetX", "nzOffsetY", "nzVisible"], outputs: ["nzOnViewInit", "nzOnClose", "nzVisibleChange"], exportAs: ["nzDrawer"] }, { kind: "directive", type: i4$1.NzDrawerContentDirective, selector: "[nzDrawerContent]", exportAs: ["nzDrawerContent"] }, { kind: "ngmodule", type: NzTagModule }, { kind: "component", type: i5$2.NzTagComponent, selector: "nz-tag", inputs: ["nzMode", "nzColor", "nzChecked", "nzBordered"], outputs: ["nzOnClose", "nzCheckedChange"], exportAs: ["nzTag"] }, { kind: "ngmodule", type: NzRadioModule }, { kind: "component", type: i6$3.NzRadioComponent, selector: "[nz-radio],[nz-radio-button]", inputs: ["nzValue", "nzDisabled", "nzAutoFocus", "nz-radio-button"], exportAs: ["nzRadio"] }, { kind: "component", type: i6$3.NzRadioGroupComponent, selector: "nz-radio-group", inputs: ["nzDisabled", "nzButtonStyle", "nzSize", "nzName"], exportAs: ["nzRadioGroup"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i2.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "component", type: Box, selector: "box", inputs: ["display", "width", "height"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i8.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i9.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i10.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i11.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }, { kind: "component", type: ExtendInput, selector: "extend-input", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "inputClass", "labelSpan", "allowClear", "disabled", "readOnly", "required", "noBottom", "selectModeType", "autocomplete", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange", "onclickClearIcon", "onenter"] }, { kind: "component", type: ExtendSelectComponent, selector: "extend-select", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "disabled", "required", "noBottom", "multiple", "showSelectAll", "maxTagCount", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "displayFields", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange", "itemChange", "onFocus"] }, { kind: "component", type: ExtendCheckbox, selector: "extend-checkbox", inputs: ["label", "labelSpan", "disabled", "formData", "controlName", "valueType", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "component", type: ExtendTextArea, selector: "extend-textarea", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "inputSpan", "disabled", "required", "noBottom", "selectModeType", "inputClass", "minRows", "maxRows", "autoSize", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i6$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "ngmodule", type: NzGridModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzFlexModule }, { kind: "directive", type: i14.NzFlexDirective, selector: "[nz-flex],nz-flex", inputs: ["nzVertical", "nzJustify", "nzAlign", "nzGap", "nzWrap", "nzFlex"], exportAs: ["nzFlex"] }, { kind: "component", type: ExtendInputNumber, selector: "extend-input-number", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "disabled", "required", "noBottom", "size", "min", "max", "precision", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "separatorType", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzTableModule }, { kind: "component", type: i15.NzTableComponent, selector: "nz-table", inputs: ["nzTableLayout", "nzShowTotal", "nzItemRender", "nzTitle", "nzFooter", "nzNoResult", "nzPageSizeOptions", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualForTrackBy", "nzLoadingDelay", "nzPageIndex", "nzPageSize", "nzTotal", "nzWidthConfig", "nzData", "nzCustomColumn", "nzPaginationPosition", "nzScroll", "noDataVirtualHeight", "nzPaginationType", "nzFrontPagination", "nzTemplateMode", "nzShowPagination", "nzLoading", "nzOuterBordered", "nzLoadingIndicator", "nzBordered", "nzSize", "nzShowSizeChanger", "nzHideOnSinglePage", "nzShowQuickJumper", "nzSimple"], outputs: ["nzPageSizeChange", "nzPageIndexChange", "nzQueryParams", "nzCurrentPageDataChange", "nzCustomColumnChange"], exportAs: ["nzTable"] }, { kind: "directive", type: i15.NzTableCellDirective, selector: "th:not(.nz-disable-th):not([mat-cell]), td:not(.nz-disable-td):not([mat-cell])" }, { kind: "directive", type: i15.NzThMeasureDirective, selector: "th", inputs: ["nzWidth", "colspan", "colSpan", "rowspan", "rowSpan"] }, { kind: "component", type: i15.NzTheadComponent, selector: "thead:not(.ant-table-thead)", outputs: ["nzSortOrderChange"] }, { kind: "component", type: i15.NzTbodyComponent, selector: "tbody" }, { kind: "directive", type: i15.NzTrDirective, selector: "tr:not([mat-row]):not([mat-header-row]):not([nz-table-measure-row]):not([nzExpand]):not([nz-table-fixed-row])" }, { kind: "ngmodule", type: NzDividerModule }, { kind: "component", type: i16.NzDividerComponent, selector: "nz-divider", inputs: ["nzText", "nzType", "nzOrientation", "nzVariant", "nzDashed", "nzPlain"], exportAs: ["nzDivider"] }] });
4419
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: WorkflowEditorComponent, isStandalone: true, selector: "app-workflow-editor", inputs: { lstOrg: "lstOrg", lstRole: "lstRole" }, outputs: { onSave: "onSave", onDeleteStage: "onDeleteStage", onDeleteAction: "onDeleteAction" }, host: { listeners: { "window:keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, static: true }, { propertyName: "svgRef", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "inputStageStatusElement", first: true, predicate: ["inputStageStatusElement"], descendants: true }, { propertyName: "inputActionTypeElement", first: true, predicate: ["inputActionTypeElement"], descendants: true }, { propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n #canvasRef\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n [style.width.px]=\"CANVAS_WIDTH\"\n [style.height.px]=\"CANVAS_HEIGHT\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n>\n <!-- \n\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\" \n\n style=\"width: 100%; height: calc(100vh - 120px)\"\n \n -->\n\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Template setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> T\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger nz-tooltip=\"Save\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Add stage\" (click)=\"addStage()\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n\n <span class=\"divider\"></span>\n\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n\n <span class=\"divider\"></span>\n\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 3\" (click)=\"distributeVertical()\">\u21C5</button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.transform]=\"'translate(' + panX + 'px,' + panY + 'px)'\"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- <div class=\"zoom-toolbar\">\n <button nz-button nzSize=\"small\" (click)=\"zoomOut()\">\u2212</button>\n <span>{{ zoom * 100 | number: \"1.0-0\" }}%</span>\n <button nz-button nzSize=\"small\" (click)=\"zoomIn()\">+</button>\n </div> -->\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g [attr.transform]=\"svgTransform\">\n <!-- DEFS -->\n <defs>\n <!-- glow effect -->\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <!-- arrow markers -->\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-blue-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <path\n class=\"edge\"\n [attr.id]=\"'edge-path-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-blue)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-blue-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- text b\u00E1m theo line -->\n <!-- \n <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text> \n \n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text>\n -->\n\n <!-- text th\u1EB3ng n\u1EB1m ngang -->\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER (LU\u00D4N TR\u00CAN C\u00D9NG) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-red-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text>\n\n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text> -->\n\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- preview -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- lstStage -->\n @for (n of lstStage; track $index) {\n @if (n.StageType == \"NODE\") {\n <nz-card\n #nodeEl\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"n == selectedStage || n == hoverStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">{{ n.Code }}</div>\n\n <div>{{ n.Name }}</div>\n\n @if (!n.editorOption.isReverse) {\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n } @else {\n <div class=\"connector connector-right reverse\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left reverse\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n }\n </nz-card>\n }\n <!-- START NODE -->\n @else if (n.StageType === \"START\") {\n <nz-card\n class=\"workflow-node workflow-node-start\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">&nbsp;</div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? -83 : 1\"\n [nzColor]=\"'green'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right connector-start\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n </nz-card>\n }\n\n <!-- END NODE -->\n @else if (n.StageType === \"END\") {\n <nz-card\n class=\"workflow-node workflow-node-end\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">&nbsp;</div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? 65 : -5\"\n [nzColor]=\"'red'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-end\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n }\n\n <!-- POINTS -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverAction!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- drawer TEMPLATE -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; Template </ng-template>\n <ng-container *nzDrawerContent>\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"template.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"template.Name\"></extend-input>\n <extend-select\n [label]=\"'Type'\"\n [lstItem]=\"template.lstTemplateType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.DocType\"\n ></extend-select>\n <extend-textarea [label]=\"'Desscription'\" [(_ngModel)]=\"template.Description\"></extend-textarea>\n <extend-select\n [label]=\"'Print template'\"\n [lstItem]=\"template.lstTemplatePrint\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.TemplatePrint\"\n ></extend-select>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"template.IsActive\"></extend-checkbox>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Stage</h3>\n\n @for (tag of lstStage; track tag) {\n <nz-tag (click)=\"hoverStage = tag\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Stage status</h3>\n\n @for (tag of template.lstStageStatus; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableStageStatus(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseStageStatus(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstStageStatus && template.lstStageStatus.length\" />\n\n @if (!inputStageStatusVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputStageStatus()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputStageStatusElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputStageStatusCode\"\n (keydown.enter)=\"inputStageStatusNameElement.select()\"\n />\n <input\n #inputStageStatusNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputStageStatusName\"\n (blur)=\"handleInputStageStatusConfirm()\"\n (keydown.enter)=\"handleInputStageStatusConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Action type</h3>\n\n @for (tag of template.lstActionType; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableActionType(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseActionType(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionType && template.lstActionType.length\" />\n\n @if (!inputActionTypeVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputActionType()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputActionTypeElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputActionTypeCode\"\n (keydown.enter)=\"inputActionTypeNameElement.select()\"\n />\n <input\n #inputActionTypeNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputActionTypeName\"\n (blur)=\"handleInputActionTypeConfirm()\"\n (keydown.enter)=\"handleInputActionTypeConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Action status</h3>\n\n @for (tag of template.lstActionStatus; track tag) {\n <nz-tag [nzMode]=\"checkRemoveableActionStatus(tag) ? 'closeable' : 'default'\" (nzOnClose)=\"handleClose(tag)\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionStatus && template.lstActionStatus.length\" />\n\n @if (!inputVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n <nz-icon nzType=\"plus\" />\n New Action status\n </nz-tag>\n } @else {\n <input\n #inputElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"+ New Action status\"\n [(ngModel)]=\"inputValue\"\n (blur)=\"handleInputConfirm()\"\n (keydown.enter)=\"handleInputConfirm()\"\n />\n }\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\">\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n <button nz-button nzDanger (click)=\"save()\">Save</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- drawer STAGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleStage\"\n [nzPlacement]=\"selectedStage?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzVisible]=\"!!selectedStage\"\n [nzWidth]=\"750\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedStage = undefined\"\n>\n <ng-template #drawerTitleStage>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedStage && selectedStage.editorOption) {\n @if (selectedStage.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n STAGE\n } @else {\n STAGE\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedStage\">\n <nz-radio-group [(ngModel)]=\"selectedStage.StageType\">\n <label nz-radio nzValue=\"START\" [nzDisabled]=\"selectedStage.StageType != 'START'\">START</label>\n <label nz-radio nzValue=\"NODE\" [nzDisabled]=\"selectedStage.StageType != 'NODE'\">NODE</label>\n <label nz-radio nzValue=\"END\" [nzDisabled]=\"selectedStage.StageType != 'END'\">END</label>\n </nz-radio-group>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Code'\"\n [layOutType]=\"'vertical'\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Code\"\n ></extend-input>\n\n <extend-textarea\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Name'\"\n [layOutType]=\"'vertical'\"\n [autoSize]=\"true\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Name\"\n ></extend-textarea>\n </div>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Sequence'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedStage.SeqValue\"\n ></extend-input-number>\n\n <extend-select\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Org implement'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstOrg\"\n [valueField]=\"'App_Org_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedStage.App_Org_Id\"\n ></extend-select>\n </div>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Number Day'\"\n [layOutType]=\"'vertical'\"\n [precision]=\"1\"\n [(_ngModel)]=\"selectedStage.NumberDay\"\n ></extend-input-number>\n </div>\n\n @if (selectedStage.editorOption) {\n @if ([\"START\", \"END\"].indexOf(selectedStage.StageType) < 0) {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverse\"\n ></extend-checkbox>\n\n <extend-checkbox\n [label]=\"'Require user action'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.IsRequireUser\"\n ></extend-checkbox>\n } @else {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverseLabel\"\n ></extend-checkbox>\n }\n }\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\">\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;List Action</h3>\n <div nz-col>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"addAction()\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n </div>\n </div>\n\n <nz-table\n nzSize=\"small\"\n [nzData]=\"selectedStage.lstAction || []\"\n [nzShowPagination]=\"false\"\n [nzNoResult]=\"'&nbsp;'\"\n >\n <thead>\n <tr [hidden]=\"true\">\n <th nzWidth=\"50px\"></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (action of selectedStage.lstAction; track $index) {\n <tr>\n <td>\n <nz-icon\n nzType=\"delete\"\n nzTheme=\"outline\"\n class=\"color-warn cursor-pointer icon-size-16\"\n (click)=\"$event.stopPropagation(); deleteAction(action)\"\n ></nz-icon>\n </td>\n <td (click)=\"hoverAction = action\">\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"action.ActionText\"\n (_ngModelChange)=\"onchangeActionText(action)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(action)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.NextStageStatus\"\n ></extend-select>\n </div>\n <box [height]=\"8\"></box>\n <div nz-row><strong>Role</strong></div>\n <div nz-row>\n <extend-select\n nz-col\n nzSpan=\"24\"\n [size]=\"'small'\"\n [lstItem]=\"lstRole\"\n [valueField]=\"'App_Role_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [multiple]=\"true\"\n [(_ngModel)]=\"action._lstRoleId\"\n (_ngModelChange)=\"onselectedRoleEmail(action)\"\n ></extend-select>\n </div>\n <box [height]=\"8\"></box>\n <div nz-row>\n <strong>Email action</strong>\n </div>\n <div nz-row>\n <extend-select\n nz-col\n nzSpan=\"24\"\n [size]=\"'small'\"\n [lstItem]=\"lstEmailAction\"\n [valueField]=\"'ID'\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"action._lstEmailActionId\"\n (_ngModelChange)=\"onselectedRoleEmail(action)\"\n ></extend-select>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </nz-table>\n\n <box [height]=\"16\"></box>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"\n selectedStage && selectedStage.editorOption && selectedStage.editorOption.drawerPosition == 'left'\n ? 'start'\n : 'end'\n \"\n >\n <button nz-button nzDanger nzDanger (click)=\"save()\">Save</button>\n <button nz-button (click)=\"selectedStage = undefined\">Close</button>\n <button\n *ngIf=\"selectedStage && ['START', 'END'].indexOf(selectedStage.StageType) < 0\"\n nz-button\n nzDanger\n (click)=\"deleteStage()\"\n >\n Delete\n </button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- drawer ACTION -->\n<nz-drawer\n [nzTitle]=\"drawerTitleAction\"\n nzTitle=\"ACTION\"\n [nzPlacement]=\"selectedAction?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"750\"\n [nzVisible]=\"!!selectedAction\"\n [nzFooter]=\"footerTplAction\"\n (nzOnClose)=\"selectedAction = undefined\"\n>\n <ng-template #drawerTitleAction>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedAction && selectedAction.editorOption) {\n @if (selectedAction.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n ACTION\n } @else {\n ACTION\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedAction\">\n <strong>{{ selectedAction.FromStageCode }} -> {{ selectedAction.ToStageCode }}</strong>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(selectedAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.NextStageStatus\"\n ></extend-select>\n </div>\n\n <!-- <box [height]=\"16\"></box> -->\n <nz-divider></nz-divider>\n\n <extend-checkbox\n [label]=\"'Allow back'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedAction.allowBack\"\n (_ngModelChange)=\"onchangeAllowBack(selectedAction)\"\n ></extend-checkbox>\n\n <box [height]=\"16\"></box>\n\n @if (selectedAction.allowBack) {\n <strong>{{ selectedAction.ToStageCode }} -> {{ selectedAction.FromStageCode }}</strong>\n\n @if (selectedBackAction) {\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedBackAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedBackAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(selectedBackAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.NextStageStatus\"\n ></extend-select>\n </div>\n }\n }\n </ng-container>\n </ng-container>\n <ng-template #footerTplAction>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedAction && selectedAction.editorOption.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger nzDanger (click)=\"save()\">Save</button>\n <button nz-button (click)=\"selectedAction = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteAction(selectedAction!)\">Delete</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- setting editor -->\n<nz-drawer\n [nzTitle]=\"drawSettingTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"settingVisible\"\n (nzOnClose)=\"settingVisible = false\"\n>\n <ng-template #drawSettingTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox [label]=\"'Show grid'\" [labelSpan]=\"0\" [(_ngModel)]=\"wfcSetting.ShowGrid\"></extend-checkbox>\n\n <box [height]=\"16\"></box>\n </div>\n </ng-container>\n</nz-drawer>\n", styles: ["@charset \"UTF-8\";.workflow-canvas{position:relative;width:100%;height:600px;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:10000px;height:10000px}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node-start{background-color:unset;display:flex;justify-content:right}.workflow-node-end{background-color:unset;display:flex}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-3px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-6px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}.zoom-toolbar{position:absolute;top:8px;left:8px;z-index:10;display:flex;align-items:center;gap:6px;background:#fff;padding:4px 6px;border-radius:6px;box-shadow:0 2px 6px #00000026}.zoom-toolbar span{min-width:40px;text-align:center;font-size:12px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.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: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzCardModule }, { kind: "component", type: i3$1.NzCardComponent, selector: "nz-card", inputs: ["nzBordered", "nzLoading", "nzHoverable", "nzBodyStyle", "nzCover", "nzActions", "nzType", "nzSize", "nzTitle", "nzExtra"], exportAs: ["nzCard"] }, { kind: "ngmodule", type: NzDrawerModule }, { kind: "component", type: i4$1.NzDrawerComponent, selector: "nz-drawer", inputs: ["nzContent", "nzCloseIcon", "nzClosable", "nzMaskClosable", "nzMask", "nzCloseOnNavigation", "nzNoAnimation", "nzKeyboard", "nzTitle", "nzExtra", "nzFooter", "nzPlacement", "nzSize", "nzMaskStyle", "nzBodyStyle", "nzWrapClassName", "nzWidth", "nzHeight", "nzZIndex", "nzOffsetX", "nzOffsetY", "nzVisible"], outputs: ["nzOnViewInit", "nzOnClose", "nzVisibleChange"], exportAs: ["nzDrawer"] }, { kind: "directive", type: i4$1.NzDrawerContentDirective, selector: "[nzDrawerContent]", exportAs: ["nzDrawerContent"] }, { kind: "ngmodule", type: NzTagModule }, { kind: "component", type: i5$2.NzTagComponent, selector: "nz-tag", inputs: ["nzMode", "nzColor", "nzChecked", "nzBordered"], outputs: ["nzOnClose", "nzCheckedChange"], exportAs: ["nzTag"] }, { kind: "ngmodule", type: NzRadioModule }, { kind: "component", type: i6$3.NzRadioComponent, selector: "[nz-radio],[nz-radio-button]", inputs: ["nzValue", "nzDisabled", "nzAutoFocus", "nz-radio-button"], exportAs: ["nzRadio"] }, { kind: "component", type: i6$3.NzRadioGroupComponent, selector: "nz-radio-group", inputs: ["nzDisabled", "nzButtonStyle", "nzSize", "nzName"], exportAs: ["nzRadioGroup"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i2.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "component", type: Box, selector: "box", inputs: ["display", "width", "height"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i8.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i9.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i10.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i11.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }, { kind: "component", type: ExtendInput, selector: "extend-input", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "inputClass", "labelSpan", "allowClear", "disabled", "readOnly", "required", "noBottom", "selectModeType", "autocomplete", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange", "onclickClearIcon", "onenter"] }, { kind: "component", type: ExtendSelectComponent, selector: "extend-select", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "disabled", "required", "noBottom", "multiple", "showSelectAll", "maxTagCount", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "displayFields", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange", "itemChange", "onFocus"] }, { kind: "component", type: ExtendCheckbox, selector: "extend-checkbox", inputs: ["label", "labelSpan", "disabled", "formData", "controlName", "valueType", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "component", type: ExtendTextArea, selector: "extend-textarea", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "inputSpan", "disabled", "required", "noBottom", "selectModeType", "inputClass", "minRows", "maxRows", "autoSize", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i6$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "ngmodule", type: NzGridModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzFlexModule }, { kind: "directive", type: i14.NzFlexDirective, selector: "[nz-flex],nz-flex", inputs: ["nzVertical", "nzJustify", "nzAlign", "nzGap", "nzWrap", "nzFlex"], exportAs: ["nzFlex"] }, { kind: "component", type: ExtendInputNumber, selector: "extend-input-number", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "disabled", "required", "noBottom", "size", "min", "max", "precision", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "separatorType", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzTableModule }, { kind: "component", type: i15.NzTableComponent, selector: "nz-table", inputs: ["nzTableLayout", "nzShowTotal", "nzItemRender", "nzTitle", "nzFooter", "nzNoResult", "nzPageSizeOptions", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualForTrackBy", "nzLoadingDelay", "nzPageIndex", "nzPageSize", "nzTotal", "nzWidthConfig", "nzData", "nzCustomColumn", "nzPaginationPosition", "nzScroll", "noDataVirtualHeight", "nzPaginationType", "nzFrontPagination", "nzTemplateMode", "nzShowPagination", "nzLoading", "nzOuterBordered", "nzLoadingIndicator", "nzBordered", "nzSize", "nzShowSizeChanger", "nzHideOnSinglePage", "nzShowQuickJumper", "nzSimple"], outputs: ["nzPageSizeChange", "nzPageIndexChange", "nzQueryParams", "nzCurrentPageDataChange", "nzCustomColumnChange"], exportAs: ["nzTable"] }, { kind: "directive", type: i15.NzTableCellDirective, selector: "th:not(.nz-disable-th):not([mat-cell]), td:not(.nz-disable-td):not([mat-cell])" }, { kind: "directive", type: i15.NzThMeasureDirective, selector: "th", inputs: ["nzWidth", "colspan", "colSpan", "rowspan", "rowSpan"] }, { kind: "component", type: i15.NzTheadComponent, selector: "thead:not(.ant-table-thead)", outputs: ["nzSortOrderChange"] }, { kind: "component", type: i15.NzTbodyComponent, selector: "tbody" }, { kind: "directive", type: i15.NzTrDirective, selector: "tr:not([mat-row]):not([mat-header-row]):not([nz-table-measure-row]):not([nzExpand]):not([nz-table-fixed-row])" }, { kind: "ngmodule", type: NzDividerModule }, { kind: "component", type: i16.NzDividerComponent, selector: "nz-divider", inputs: ["nzText", "nzType", "nzOrientation", "nzVariant", "nzDashed", "nzPlain"], exportAs: ["nzDivider"] }] });
4277
4420
  }
4278
4421
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WorkflowEditorComponent, decorators: [{
4279
4422
  type: Component,
@@ -4298,22 +4441,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
4298
4441
  ExtendInputNumber,
4299
4442
  NzTableModule,
4300
4443
  NzDividerModule,
4301
- ], template: "<div\n #canvasRef\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n [style.width.px]=\"CANVAS_WIDTH\"\n [style.height.px]=\"CANVAS_HEIGHT\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n>\n <!-- \n\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\" \n\n style=\"width: 100%; height: calc(100vh - 120px)\"\n \n -->\n\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Template setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> T\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger nz-tooltip=\"Save\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Add stage\" (click)=\"addStage()\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n\n <span class=\"divider\"></span>\n\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n\n <span class=\"divider\"></span>\n\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.transform]=\"'translate(' + panX + 'px,' + panY + 'px)'\"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- <div class=\"zoom-toolbar\">\n <button nz-button nzSize=\"small\" (click)=\"zoomOut()\">\u2212</button>\n <span>{{ zoom * 100 | number: \"1.0-0\" }}%</span>\n <button nz-button nzSize=\"small\" (click)=\"zoomIn()\">+</button>\n </div> -->\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g [attr.transform]=\"svgTransform\">\n <!-- DEFS -->\n <defs>\n <!-- glow effect -->\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <!-- arrow markers -->\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-blue-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <path\n class=\"edge\"\n [attr.id]=\"'edge-path-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-blue)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-blue-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- text b\u00E1m theo line -->\n <!-- \n <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text> \n \n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text>\n -->\n\n <!-- text th\u1EB3ng n\u1EB1m ngang -->\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER (LU\u00D4N TR\u00CAN C\u00D9NG) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-red-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text>\n\n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text> -->\n\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- preview -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- lstStage -->\n @for (n of lstStage; track $index) {\n @if (n.StageType == \"NODE\") {\n <nz-card\n #nodeEl\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"n == selectedStage || n == hoverStage || lstSelectedStageCode.has(n.Code)\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">{{ n.Code }}</div>\n\n <div>{{ n.Name }}</div>\n\n @if (!n.editorOption.isReverse) {\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n } @else {\n <div class=\"connector connector-right reverse\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left reverse\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n }\n </nz-card>\n }\n <!-- START NODE -->\n @else if (n.StageType === \"START\") {\n <nz-card\n class=\"workflow-node workflow-node-start\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">&nbsp;</div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageCode.has(n.Code)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? -83 : 1\"\n [nzColor]=\"'green'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right connector-start\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n </nz-card>\n }\n\n <!-- END NODE -->\n @else if (n.StageType === \"END\") {\n <nz-card\n class=\"workflow-node workflow-node-end\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">&nbsp;</div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageCode.has(n.Code)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? 65 : -5\"\n [nzColor]=\"'red'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-end\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n }\n\n <!-- POINTS -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverAction!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- TEMPLATE -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; Template </ng-template>\n <ng-container *nzDrawerContent>\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"template.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"template.Name\"></extend-input>\n <extend-select\n [label]=\"'Type'\"\n [lstItem]=\"lstTemplateType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.DocType\"\n ></extend-select>\n <extend-textarea [label]=\"'Desscription'\" [(_ngModel)]=\"template.Description\"></extend-textarea>\n <extend-select\n [label]=\"'Print template'\"\n [lstItem]=\"lstTemplatePrint\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.TemplatePrint\"\n ></extend-select>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"template.IsActive\"></extend-checkbox>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Stage status</h3>\n\n @for (tag of template.lstStageStatus; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableStageStatus(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseStageStatus(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstStageStatus && template.lstStageStatus.length\" />\n\n @if (!inputStageStatusVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputStageStatus()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputStageStatusElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputStageStatusCode\"\n (keydown.enter)=\"inputStageStatusNameElement.select()\"\n />\n <input\n #inputStageStatusNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputStageStatusName\"\n (blur)=\"handleInputStageStatusConfirm()\"\n (keydown.enter)=\"handleInputStageStatusConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Action type</h3>\n\n @for (tag of template.lstActionType; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableActionType(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseActionType(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionType && template.lstActionType.length\" />\n\n @if (!inputActionTypeVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputActionType()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputActionTypeElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputActionTypeCode\"\n (keydown.enter)=\"inputActionTypeNameElement.select()\"\n />\n <input\n #inputActionTypeNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputActionTypeName\"\n (blur)=\"handleInputActionTypeConfirm()\"\n (keydown.enter)=\"handleInputActionTypeConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Action status</h3>\n\n @for (tag of template.lstActionStatus; track tag) {\n <nz-tag [nzMode]=\"checkRemoveableActionStatus(tag) ? 'closeable' : 'default'\" (nzOnClose)=\"handleClose(tag)\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionStatus && template.lstActionStatus.length\" />\n\n @if (!inputVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n <nz-icon nzType=\"plus\" />\n New Action status\n </nz-tag>\n } @else {\n <input\n #inputElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"+ New Action status\"\n [(ngModel)]=\"inputValue\"\n (blur)=\"handleInputConfirm()\"\n (keydown.enter)=\"handleInputConfirm()\"\n />\n }\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\">\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n <button nz-button nzDanger (click)=\"save()\">Save</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- STAGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleStage\"\n [nzPlacement]=\"selectedStage?.editorOption?.drawerPosition ? selectedStage?.editorOption?.drawerPosition : 'right'\"\n [nzVisible]=\"!!selectedStage\"\n [nzWidth]=\"750\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedStage = undefined\"\n>\n <ng-template #drawerTitleStage>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedStage) {\n @if (selectedStage.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n STAGE\n } @else {\n STAGE\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedStage\">\n <nz-radio-group [(ngModel)]=\"selectedStage.StageType\">\n <label nz-radio nzValue=\"START\" [nzDisabled]=\"selectedStage.StageType != 'START'\">START</label>\n <label nz-radio nzValue=\"NODE\" [nzDisabled]=\"selectedStage.StageType != 'NODE'\">NODE</label>\n <label nz-radio nzValue=\"END\" [nzDisabled]=\"selectedStage.StageType != 'END'\">END</label>\n </nz-radio-group>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"32\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Code'\"\n [layOutType]=\"'vertical'\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Code\"\n ></extend-input>\n\n <extend-textarea\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Name'\"\n [layOutType]=\"'vertical'\"\n [autoSize]=\"true\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Name\"\n ></extend-textarea>\n </div>\n\n <div nz-row [nzGutter]=\"32\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Sequence'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedStage.SeqValue\"\n ></extend-input-number>\n\n <extend-select\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Org implement'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstOrg\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedStage.OrgImplCode\"\n ></extend-select>\n </div>\n\n @if ([\"START\", \"END\"].indexOf(selectedStage.StageType) < 0) {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverse\"\n ></extend-checkbox>\n\n <extend-checkbox\n [label]=\"'Require user action'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.IsRequireUser\"\n ></extend-checkbox>\n } @else {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverseLabel\"\n ></extend-checkbox>\n }\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\">\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;List Action</h3>\n <div nz-col>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"addAction()\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n </div>\n </div>\n\n <nz-table\n nzSize=\"small\"\n [nzData]=\"selectedStage.lstAction || []\"\n [nzShowPagination]=\"false\"\n [nzNoResult]=\"'&nbsp;'\"\n >\n <thead>\n <tr [hidden]=\"true\">\n <th nzWidth=\"50px\"></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (action of selectedStage.lstAction; track $index) {\n <tr>\n <td>\n <nz-icon\n nzType=\"delete\"\n nzTheme=\"outline\"\n class=\"color-warn cursor-pointer icon-size-16\"\n (click)=\"$event.stopPropagation(); deleteAction(action)\"\n ></nz-icon>\n </td>\n <td (click)=\"hoverAction = action\">\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"action.ActionText\"\n (_ngModelChange)=\"onchangeActionText(action)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(action)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.NextStageStatus\"\n ></extend-select>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </nz-table>\n\n <box [height]=\"16\"></box>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedStage && selectedStage.editorOption.drawerPosition == 'left' ? 'end' : 'start'\"\n >\n <button nz-button (click)=\"selectedStage = undefined\">Close</button>\n <button\n *ngIf=\"selectedStage && ['START', 'END'].indexOf(selectedStage.StageType) < 0\"\n nz-button\n nzDanger\n (click)=\"deleteNode()\"\n >\n Delete\n </button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- EDGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleAction\"\n nzTitle=\"ACTION\"\n [nzPlacement]=\"selectedAction?.editorOption?.drawerPosition ? selectedAction?.editorOption?.drawerPosition : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"750\"\n [nzVisible]=\"!!selectedAction\"\n [nzFooter]=\"footerTplAction\"\n (nzOnClose)=\"selectedAction = undefined\"\n>\n <ng-template #drawerTitleAction>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedAction) {\n @if (selectedAction.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n ACTION\n } @else {\n ACTION\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedAction\">\n <strong>{{ selectedAction.FromStage }} -> {{ selectedAction.ToStage }}</strong>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(selectedAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.NextStageStatus\"\n ></extend-select>\n </div>\n\n <!-- <box [height]=\"16\"></box> -->\n <nz-divider></nz-divider>\n\n <extend-checkbox\n [label]=\"'Allow back'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedAction.allowBack\"\n (_ngModelChange)=\"onchangeAllowBack(selectedAction)\"\n ></extend-checkbox>\n\n <box [height]=\"16\"></box>\n\n @if (selectedAction.allowBack) {\n <strong>{{ selectedAction.ToStage }} -> {{ selectedAction.FromStage }}</strong>\n\n @if (selectedBackAction) {\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedBackAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedBackAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(selectedBackAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.NextStageStatus\"\n ></extend-select>\n </div>\n }\n }\n </ng-container>\n </ng-container>\n <ng-template #footerTplAction>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedAction && selectedAction.editorOption.drawerPosition == 'left' ? 'end' : 'start'\"\n >\n <button nz-button (click)=\"selectedAction = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteAction(selectedAction!)\">Delete</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- setting editor -->\n<nz-drawer\n [nzTitle]=\"drawSettingTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"settingVisible\"\n (nzOnClose)=\"settingVisible = false\"\n>\n <ng-template #drawSettingTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox [label]=\"'Show grid'\" [labelSpan]=\"0\" [(_ngModel)]=\"wfcSetting.ShowGrid\"></extend-checkbox>\n\n <box [height]=\"16\"></box>\n </div>\n </ng-container>\n</nz-drawer>\n", styles: ["@charset \"UTF-8\";.workflow-canvas{position:relative;width:100%;height:600px;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:10000px;height:10000px}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node-start{background-color:unset;display:flex;justify-content:right}.workflow-node-end{background-color:unset;display:flex}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-3px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-6px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}.zoom-toolbar{position:absolute;top:8px;left:8px;z-index:10;display:flex;align-items:center;gap:6px;background:#fff;padding:4px 6px;border-radius:6px;box-shadow:0 2px 6px #00000026}.zoom-toolbar span{min-width:40px;text-align:center;font-size:12px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}\n"] }]
4444
+ ], template: "<div\n #canvasRef\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n [style.width.px]=\"CANVAS_WIDTH\"\n [style.height.px]=\"CANVAS_HEIGHT\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n>\n <!-- \n\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\" \n\n style=\"width: 100%; height: calc(100vh - 120px)\"\n \n -->\n\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Template setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> T\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger nz-tooltip=\"Save\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Add stage\" (click)=\"addStage()\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n\n <span class=\"divider\"></span>\n\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n\n <span class=\"divider\"></span>\n\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 3\" (click)=\"distributeVertical()\">\u21C5</button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.transform]=\"'translate(' + panX + 'px,' + panY + 'px)'\"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- <div class=\"zoom-toolbar\">\n <button nz-button nzSize=\"small\" (click)=\"zoomOut()\">\u2212</button>\n <span>{{ zoom * 100 | number: \"1.0-0\" }}%</span>\n <button nz-button nzSize=\"small\" (click)=\"zoomIn()\">+</button>\n </div> -->\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g [attr.transform]=\"svgTransform\">\n <!-- DEFS -->\n <defs>\n <!-- glow effect -->\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <!-- arrow markers -->\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-blue-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <path\n class=\"edge\"\n [attr.id]=\"'edge-path-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-blue)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-blue-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- text b\u00E1m theo line -->\n <!-- \n <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text> \n \n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text>\n -->\n\n <!-- text th\u1EB3ng n\u1EB1m ngang -->\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER (LU\u00D4N TR\u00CAN C\u00D9NG) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-red-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text>\n\n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text> -->\n\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- preview -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- lstStage -->\n @for (n of lstStage; track $index) {\n @if (n.StageType == \"NODE\") {\n <nz-card\n #nodeEl\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"n == selectedStage || n == hoverStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">{{ n.Code }}</div>\n\n <div>{{ n.Name }}</div>\n\n @if (!n.editorOption.isReverse) {\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n } @else {\n <div class=\"connector connector-right reverse\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left reverse\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n }\n </nz-card>\n }\n <!-- START NODE -->\n @else if (n.StageType === \"START\") {\n <nz-card\n class=\"workflow-node workflow-node-start\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">&nbsp;</div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? -83 : 1\"\n [nzColor]=\"'green'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right connector-start\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n </nz-card>\n }\n\n <!-- END NODE -->\n @else if (n.StageType === \"END\") {\n <nz-card\n class=\"workflow-node workflow-node-end\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">&nbsp;</div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? 65 : -5\"\n [nzColor]=\"'red'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-end\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n }\n\n <!-- POINTS -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverAction!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- drawer TEMPLATE -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; Template </ng-template>\n <ng-container *nzDrawerContent>\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"template.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"template.Name\"></extend-input>\n <extend-select\n [label]=\"'Type'\"\n [lstItem]=\"template.lstTemplateType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.DocType\"\n ></extend-select>\n <extend-textarea [label]=\"'Desscription'\" [(_ngModel)]=\"template.Description\"></extend-textarea>\n <extend-select\n [label]=\"'Print template'\"\n [lstItem]=\"template.lstTemplatePrint\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.TemplatePrint\"\n ></extend-select>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"template.IsActive\"></extend-checkbox>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Stage</h3>\n\n @for (tag of lstStage; track tag) {\n <nz-tag (click)=\"hoverStage = tag\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Stage status</h3>\n\n @for (tag of template.lstStageStatus; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableStageStatus(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseStageStatus(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstStageStatus && template.lstStageStatus.length\" />\n\n @if (!inputStageStatusVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputStageStatus()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputStageStatusElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputStageStatusCode\"\n (keydown.enter)=\"inputStageStatusNameElement.select()\"\n />\n <input\n #inputStageStatusNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputStageStatusName\"\n (blur)=\"handleInputStageStatusConfirm()\"\n (keydown.enter)=\"handleInputStageStatusConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Action type</h3>\n\n @for (tag of template.lstActionType; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableActionType(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseActionType(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionType && template.lstActionType.length\" />\n\n @if (!inputActionTypeVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputActionType()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputActionTypeElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputActionTypeCode\"\n (keydown.enter)=\"inputActionTypeNameElement.select()\"\n />\n <input\n #inputActionTypeNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputActionTypeName\"\n (blur)=\"handleInputActionTypeConfirm()\"\n (keydown.enter)=\"handleInputActionTypeConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;Action status</h3>\n\n @for (tag of template.lstActionStatus; track tag) {\n <nz-tag [nzMode]=\"checkRemoveableActionStatus(tag) ? 'closeable' : 'default'\" (nzOnClose)=\"handleClose(tag)\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionStatus && template.lstActionStatus.length\" />\n\n @if (!inputVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n <nz-icon nzType=\"plus\" />\n New Action status\n </nz-tag>\n } @else {\n <input\n #inputElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"+ New Action status\"\n [(ngModel)]=\"inputValue\"\n (blur)=\"handleInputConfirm()\"\n (keydown.enter)=\"handleInputConfirm()\"\n />\n }\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\">\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n <button nz-button nzDanger (click)=\"save()\">Save</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- drawer STAGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleStage\"\n [nzPlacement]=\"selectedStage?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzVisible]=\"!!selectedStage\"\n [nzWidth]=\"750\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedStage = undefined\"\n>\n <ng-template #drawerTitleStage>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedStage && selectedStage.editorOption) {\n @if (selectedStage.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n STAGE\n } @else {\n STAGE\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedStage\">\n <nz-radio-group [(ngModel)]=\"selectedStage.StageType\">\n <label nz-radio nzValue=\"START\" [nzDisabled]=\"selectedStage.StageType != 'START'\">START</label>\n <label nz-radio nzValue=\"NODE\" [nzDisabled]=\"selectedStage.StageType != 'NODE'\">NODE</label>\n <label nz-radio nzValue=\"END\" [nzDisabled]=\"selectedStage.StageType != 'END'\">END</label>\n </nz-radio-group>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Code'\"\n [layOutType]=\"'vertical'\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Code\"\n ></extend-input>\n\n <extend-textarea\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Name'\"\n [layOutType]=\"'vertical'\"\n [autoSize]=\"true\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Name\"\n ></extend-textarea>\n </div>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Sequence'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedStage.SeqValue\"\n ></extend-input-number>\n\n <extend-select\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Org implement'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstOrg\"\n [valueField]=\"'App_Org_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedStage.App_Org_Id\"\n ></extend-select>\n </div>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Number Day'\"\n [layOutType]=\"'vertical'\"\n [precision]=\"1\"\n [(_ngModel)]=\"selectedStage.NumberDay\"\n ></extend-input-number>\n </div>\n\n @if (selectedStage.editorOption) {\n @if ([\"START\", \"END\"].indexOf(selectedStage.StageType) < 0) {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverse\"\n ></extend-checkbox>\n\n <extend-checkbox\n [label]=\"'Require user action'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.IsRequireUser\"\n ></extend-checkbox>\n } @else {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverseLabel\"\n ></extend-checkbox>\n }\n }\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\">\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" />&nbsp;List Action</h3>\n <div nz-col>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"addAction()\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n </div>\n </div>\n\n <nz-table\n nzSize=\"small\"\n [nzData]=\"selectedStage.lstAction || []\"\n [nzShowPagination]=\"false\"\n [nzNoResult]=\"'&nbsp;'\"\n >\n <thead>\n <tr [hidden]=\"true\">\n <th nzWidth=\"50px\"></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (action of selectedStage.lstAction; track $index) {\n <tr>\n <td>\n <nz-icon\n nzType=\"delete\"\n nzTheme=\"outline\"\n class=\"color-warn cursor-pointer icon-size-16\"\n (click)=\"$event.stopPropagation(); deleteAction(action)\"\n ></nz-icon>\n </td>\n <td (click)=\"hoverAction = action\">\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"action.ActionText\"\n (_ngModelChange)=\"onchangeActionText(action)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(action)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.NextStageStatus\"\n ></extend-select>\n </div>\n <box [height]=\"8\"></box>\n <div nz-row><strong>Role</strong></div>\n <div nz-row>\n <extend-select\n nz-col\n nzSpan=\"24\"\n [size]=\"'small'\"\n [lstItem]=\"lstRole\"\n [valueField]=\"'App_Role_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [multiple]=\"true\"\n [(_ngModel)]=\"action._lstRoleId\"\n (_ngModelChange)=\"onselectedRoleEmail(action)\"\n ></extend-select>\n </div>\n <box [height]=\"8\"></box>\n <div nz-row>\n <strong>Email action</strong>\n </div>\n <div nz-row>\n <extend-select\n nz-col\n nzSpan=\"24\"\n [size]=\"'small'\"\n [lstItem]=\"lstEmailAction\"\n [valueField]=\"'ID'\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"action._lstEmailActionId\"\n (_ngModelChange)=\"onselectedRoleEmail(action)\"\n ></extend-select>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </nz-table>\n\n <box [height]=\"16\"></box>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"\n selectedStage && selectedStage.editorOption && selectedStage.editorOption.drawerPosition == 'left'\n ? 'start'\n : 'end'\n \"\n >\n <button nz-button nzDanger nzDanger (click)=\"save()\">Save</button>\n <button nz-button (click)=\"selectedStage = undefined\">Close</button>\n <button\n *ngIf=\"selectedStage && ['START', 'END'].indexOf(selectedStage.StageType) < 0\"\n nz-button\n nzDanger\n (click)=\"deleteStage()\"\n >\n Delete\n </button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- drawer ACTION -->\n<nz-drawer\n [nzTitle]=\"drawerTitleAction\"\n nzTitle=\"ACTION\"\n [nzPlacement]=\"selectedAction?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"750\"\n [nzVisible]=\"!!selectedAction\"\n [nzFooter]=\"footerTplAction\"\n (nzOnClose)=\"selectedAction = undefined\"\n>\n <ng-template #drawerTitleAction>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedAction && selectedAction.editorOption) {\n @if (selectedAction.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n ACTION\n } @else {\n ACTION\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedAction\">\n <strong>{{ selectedAction.FromStageCode }} -> {{ selectedAction.ToStageCode }}</strong>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(selectedAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.NextStageStatus\"\n ></extend-select>\n </div>\n\n <!-- <box [height]=\"16\"></box> -->\n <nz-divider></nz-divider>\n\n <extend-checkbox\n [label]=\"'Allow back'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedAction.allowBack\"\n (_ngModelChange)=\"onchangeAllowBack(selectedAction)\"\n ></extend-checkbox>\n\n <box [height]=\"16\"></box>\n\n @if (selectedAction.allowBack) {\n <strong>{{ selectedAction.ToStageCode }} -> {{ selectedAction.FromStageCode }}</strong>\n\n @if (selectedBackAction) {\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedBackAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedBackAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(selectedBackAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.NextStageStatus\"\n ></extend-select>\n </div>\n }\n }\n </ng-container>\n </ng-container>\n <ng-template #footerTplAction>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedAction && selectedAction.editorOption.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger nzDanger (click)=\"save()\">Save</button>\n <button nz-button (click)=\"selectedAction = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteAction(selectedAction!)\">Delete</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- setting editor -->\n<nz-drawer\n [nzTitle]=\"drawSettingTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"settingVisible\"\n (nzOnClose)=\"settingVisible = false\"\n>\n <ng-template #drawSettingTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox [label]=\"'Show grid'\" [labelSpan]=\"0\" [(_ngModel)]=\"wfcSetting.ShowGrid\"></extend-checkbox>\n\n <box [height]=\"16\"></box>\n </div>\n </ng-container>\n</nz-drawer>\n", styles: ["@charset \"UTF-8\";.workflow-canvas{position:relative;width:100%;height:600px;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:10000px;height:10000px}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node-start{background-color:unset;display:flex;justify-content:right}.workflow-node-end{background-color:unset;display:flex}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-3px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-6px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}.zoom-toolbar{position:absolute;top:8px;left:8px;z-index:10;display:flex;align-items:center;gap:6px;background:#fff;padding:4px 6px;border-radius:6px;box-shadow:0 2px 6px #00000026}.zoom-toolbar span{min-width:40px;text-align:center;font-size:12px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}\n"] }]
4302
4445
  }], propDecorators: { lstOrg: [{
4303
4446
  type: Input
4304
- }], lstTemplateType: [{
4305
- type: Input
4306
- }], lstTemplatePrint: [{
4307
- type: Input
4308
- }], template: [{
4309
- type: Input
4310
- }], lstStage: [{
4311
- type: Input
4312
- }], lstAction: [{
4447
+ }], lstRole: [{
4313
4448
  type: Input
4314
4449
  }], onSave: [{
4315
4450
  type: Output,
4316
4451
  args: ['onSave']
4452
+ }], onDeleteStage: [{
4453
+ type: Output,
4454
+ args: ['onDeleteStage']
4455
+ }], onDeleteAction: [{
4456
+ type: Output,
4457
+ args: ['onDeleteAction']
4317
4458
  }], canvasRef: [{
4318
4459
  type: ViewChild,
4319
4460
  args: ['canvas', { static: true }]