@masterteam/workflow 0.0.44 → 0.0.46

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.
@@ -84,7 +84,10 @@
84
84
  "unknownAppAction": "إجراء غير معروف",
85
85
  "unknownAppActionHint": "إجراء التطبيق هذا لم يعد متاحًا أو غير مسجَّل في الخلفية. تم الحفاظ على الإعدادات المحفوظة، لكن لا يمكن تحرير الخطوة حتى يُستعاد الإجراء.",
86
86
  "edit": "تعديل",
87
- "delete": "حذف"
87
+ "delete": "حذف",
88
+ "connectionBlockedTitle": "اتصال غير مسموح به",
89
+ "connectionIntoInitialBlocked": "يجب أن تبقى الخطوة الأولية في المقدمة — لا يمكن لأي خطوة الاتصال بها.",
90
+ "connectionAfterCommitBlocked": "لا يُسمح إلا بخطوات إجراءات التطبيق بعد تأكيد النموذج المعتمد."
88
91
  }
89
92
  }
90
93
  }
@@ -84,7 +84,10 @@
84
84
  "unknownAppAction": "Unknown App Action",
85
85
  "unknownAppActionHint": "This app action is no longer available or is not registered in the backend. The saved configuration is preserved, but the step cannot be edited until the action is restored.",
86
86
  "edit": "Edit",
87
- "delete": "Delete"
87
+ "delete": "Delete",
88
+ "connectionBlockedTitle": "Connection not allowed",
89
+ "connectionIntoInitialBlocked": "The initial step must stay first — no step can connect into it.",
90
+ "connectionAfterCommitBlocked": "Only app-action steps can run after Commit Approved Form."
88
91
  }
89
92
  }
90
93
  }
@@ -1,2 +1,2 @@
1
- /*! tailwindcss v4.3.1 | MIT License | https://tailwindcss.com */
1
+ /*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
2
2
  @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-200:oklch(88.5% .062 18.334);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-800:oklch(47.3% .137 46.201);--color-sky-100:oklch(95.1% .026 236.824);--color-sky-800:oklch(44.3% .11 240.79);--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.\!absolute{position:absolute!important}.absolute{position:absolute}.static{position:static}.start-4{inset-inline-start:calc(var(--spacing) * 4)}.end-4{inset-inline-end:calc(var(--spacing) * 4)}.top-4{top:calc(var(--spacing) * 4)}.z-10{z-index:10}.ms-1{margin-inline-start:var(--spacing)}.\!mt-28{margin-top:calc(var(--spacing) * 28)!important}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.flex{display:flex}.grid{display:grid}.inline{display:inline}.inline-flex{display:inline-flex}.h-full{height:100%}.\!w-\[25rem\]{width:25rem!important}.\!w-\[42rem\]{width:42rem!important}.\!w-\[calc\(100\%-25rem\)\]{width:calc(100% - 25rem)!important}.\!w-full{width:100%!important}.w-1\/2{width:50%}.w-2\/3{width:66.6667%}.w-64{width:calc(var(--spacing) * 64)}.w-80{width:calc(var(--spacing) * 80)}.w-full{width:100%}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-10{gap:calc(var(--spacing) * 10)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-200{border-color:var(--color-amber-200)}.border-red-200{border-color:var(--color-red-200)}.border-surface-200{border-color:var(--p-surface-200)}@supports (color:color-mix(in lab, red, red)){.border-surface-200{border-color:color-mix(in srgb, var(--p-surface-200) calc(100% * 1), transparent)}}.border-surface-300{border-color:var(--p-surface-300)}@supports (color:color-mix(in lab, red, red)){.border-surface-300{border-color:color-mix(in srgb, var(--p-surface-300) calc(100% * 1), transparent)}}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-red-50{background-color:var(--color-red-50)}.bg-sky-100{background-color:var(--color-sky-100)}.bg-surface-50{background-color:var(--p-surface-50)}@supports (color:color-mix(in lab, red, red)){.bg-surface-50{background-color:color-mix(in srgb, var(--p-surface-50) calc(100% * 1), transparent)}}.bg-surface-100{background-color:var(--p-surface-100)}@supports (color:color-mix(in lab, red, red)){.bg-surface-100{background-color:color-mix(in srgb, var(--p-surface-100) calc(100% * 1), transparent)}}.bg-surface-200{background-color:var(--p-surface-200)}@supports (color:color-mix(in lab, red, red)){.bg-surface-200{background-color:color-mix(in srgb, var(--p-surface-200) calc(100% * 1), transparent)}}.p-4{padding:calc(var(--spacing) * 4)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.text-start{text-align:start}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.text-amber-800{color:var(--color-amber-800)}.text-muted-color{color:var(--p-text-muted-color)}.text-primary{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.text-primary{color:color-mix(in srgb, var(--p-primary-color) calc(100% * 1), transparent)}}.text-red-700{color:var(--color-red-700)}.text-sky-800{color:var(--color-sky-800)}.text-surface-600{color:var(--p-surface-600)}@supports (color:color-mix(in lab, red, red)){.text-surface-600{color:color-mix(in srgb, var(--p-surface-600) calc(100% * 1), transparent)}}.text-surface-700{color:var(--p-surface-700)}@supports (color:color-mix(in lab, red, red)){.text-surface-700{color:color-mix(in srgb, var(--p-surface-700) calc(100% * 1), transparent)}}.text-surface-900{color:var(--p-surface-900)}@supports (color:color-mix(in lab, red, red)){.text-surface-900{color:color-mix(in srgb, var(--p-surface-900) calc(100% * 1), transparent)}}.uppercase{text-transform:uppercase}.\!shadow-none{--tw-shadow:0 0 #0000!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.hover\:bg-surface-100:hover{background-color:var(--p-surface-100)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-100:hover{background-color:color-mix(in srgb, var(--p-surface-100) calc(100% * 1), transparent)}}}@media not all and (min-width:1025px){.max-\[1025px\]\:w-full{width:100%}}}@keyframes enter{0%{opacity:var(--p-enter-opacity,1);transform:translate3d(var(--p-enter-translate-x,0), var(--p-enter-translate-y,0), 0) scale3d(var(--p-enter-scale,1), var(--p-enter-scale,1), var(--p-enter-scale,1)) rotate(var(--p-enter-rotate,0))}}@keyframes leave{to{opacity:var(--p-leave-opacity,1);transform:translate3d(var(--p-leave-translate-x,0), var(--p-leave-translate-y,0), 0) scale3d(var(--p-leave-scale,1), var(--p-leave-scale,1), var(--p-leave-scale,1)) rotate(var(--p-leave-rotate,0))}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
@@ -13,6 +13,7 @@ import { NumberField } from '@masterteam/components/number-field';
13
13
  import { SelectField } from '@masterteam/components/select-field';
14
14
  import { TextField } from '@masterteam/components/text-field';
15
15
  import { TextareaField } from '@masterteam/components/textarea-field';
16
+ import { ToastService } from '@masterteam/components/toast';
16
17
  import { ToggleField } from '@masterteam/components/toggle-field';
17
18
  import { FormBuilder, FormBuilderFacade } from '@masterteam/form-builder';
18
19
  import { NotificationTemplate, NotificationFacade } from '@masterteam/notification';
@@ -1986,6 +1987,7 @@ class WorkflowBuilder {
1986
1987
  formBuilderFacade = inject(FormBuilderFacade);
1987
1988
  transloco = inject(TranslocoService);
1988
1989
  confirmationService = inject(ConfirmationService);
1990
+ toast = inject(ToastService);
1989
1991
  modal = inject(ModalService);
1990
1992
  isPatchingStepForm = false;
1991
1993
  lastAppActionDescriptorSignature = '';
@@ -2211,6 +2213,25 @@ class WorkflowBuilder {
2211
2213
  showSaveButton: () => this.selectedTab() === 'tab1',
2212
2214
  disableSaveButton: () => this.isNodeDialogSaveDisabled(),
2213
2215
  };
2216
+ /**
2217
+ * Connection guardrail handed to structure-builder, evaluated at draw time
2218
+ * before the connection dialog opens. Enforces the backend-owned lifecycle
2219
+ * ordering during authoring so the user cannot draw an edge that publish
2220
+ * validation would later reject:
2221
+ * - nothing may connect INTO the initial step → it stays first
2222
+ * - only `AppAction` steps may follow `Commit Approved Form` → the commit
2223
+ * step stays last for approval / user-input steps
2224
+ * Backend publish validation remains authoritative (see the ProcessBuilder
2225
+ * AppActions handoff §11).
2226
+ */
2227
+ connectionGuard = (fromNodeId, toNodeId) => {
2228
+ const message = this.getConnectionBlockMessage(fromNodeId, toNodeId);
2229
+ if (!message) {
2230
+ return true;
2231
+ }
2232
+ this.toast.info(message, this.transloco.translate('workflow.builder.connectionBlockedTitle'));
2233
+ return false;
2234
+ };
2214
2235
  connectionForm = signal({
2215
2236
  sections: [
2216
2237
  {
@@ -2231,7 +2252,7 @@ class WorkflowBuilder {
2231
2252
  }, ...(ngDevMode ? [{ debugName: "connectionForm" }] : /* istanbul ignore next */ []));
2232
2253
  connectionFormulaConfig = signal({
2233
2254
  codeOnly: true,
2234
- toolbarTabs: ['functions', 'operators'],
2255
+ toolbarTabs: ['functions', 'properties', 'operators'],
2235
2256
  isProcessBuilder: true,
2236
2257
  }, ...(ngDevMode ? [{ debugName: "connectionFormulaConfig" }] : /* istanbul ignore next */ []));
2237
2258
  steps = computed(() => this.workflowFacade.steps().map((step) => {
@@ -3064,6 +3085,29 @@ class WorkflowBuilder {
3064
3085
  }
3065
3086
  return this.getAppActionConfigMessages().length > 0;
3066
3087
  }
3088
+ /**
3089
+ * Returns a translated reason string when a source→target edge violates the
3090
+ * mandatory first/last ordering, or `null` when the connection is allowed.
3091
+ * Compares as strings because connection endpoints arrive as node-id strings
3092
+ * while step ids are numeric.
3093
+ */
3094
+ getConnectionBlockMessage(fromNodeId, toNodeId) {
3095
+ const steps = this.workflowFacade.steps();
3096
+ const source = steps.find((step) => String(step.id) === String(fromNodeId));
3097
+ const target = steps.find((step) => String(step.id) === String(toNodeId));
3098
+ // The initial step must stay first: nothing may point back into it.
3099
+ if (target?.isInitial) {
3100
+ return this.transloco.translate('workflow.builder.connectionIntoInitialBlocked');
3101
+ }
3102
+ // Only AppAction steps may run after Commit Approved Form, which keeps the
3103
+ // commit step last for approval / user-input steps.
3104
+ if (source?.type === 'ApprovalCommit' &&
3105
+ target &&
3106
+ target.type !== 'AppAction') {
3107
+ return this.transloco.translate('workflow.builder.connectionAfterCommitBlocked');
3108
+ }
3109
+ return null;
3110
+ }
3067
3111
  normalizeRoleValue(value) {
3068
3112
  if (value === null || value === undefined || value === '') {
3069
3113
  return null;
@@ -3086,7 +3130,7 @@ class WorkflowBuilder {
3086
3130
  return '';
3087
3131
  }
3088
3132
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkflowBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
3089
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkflowBuilder, isStandalone: true, selector: "mt-workflow-builder", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workflow.builder'\">\r\n <div class=\"h-full flex flex-col\" id=\"workflow-builder-card\">\r\n <div class=\"flex justify-center w-full py-2\">\r\n <mt-tabs\r\n [active]=\"mainTab()\"\r\n (activeChange)=\"onMainTabChange($event)\"\r\n [options]=\"mainTabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n </div>\r\n @switch (mainTab()) {\r\n @case (\"workflow\") {\r\n @if (!loading()) {\r\n <mt-structure-builder\r\n class=\"flex-1\"\r\n [structureMode]=\"'workflow'\"\r\n [availableNodes]=\"availableNodes()\"\r\n [availableNodesLabel]=\"t('stepTemplates')\"\r\n [connectionForm]=\"connectionForm()\"\r\n [connectionFormulaSchemaId]=\"connectionFormulaSchemaId()\"\r\n [connectionFormulaConfig]=\"connectionFormulaConfig()\"\r\n [nodeActions]=\"nodeActions()\"\r\n [nodes]=\"steps()\"\r\n [connections]=\"connections()\"\r\n (action)=\"onStructureAction($event)\"\r\n [addModalType]=\"'drawer'\"\r\n [addModalStyleClass]=\"editorDrawerStyleClass\"\r\n [updateModalStyleClass]=\"editorDrawerStyleClass\"\r\n [addModalHeader]=\"editorAddHeader\"\r\n [updateModalHeader]=\"editorUpdateHeader\"\r\n [nodeDialogFooterConfig]=\"nodeDialogFooterConfig\"\r\n [appendTo]=\"'page-content'\"\r\n [nodeFields]=\"nodeFields()\"\r\n [availableTabsClass]=\"hasMultipleWorkflows() ? '!mt-28' : ''\"\r\n [layoutDirection]=\"'LR'\"\r\n >\r\n <div flowContent class=\"pointer-events-none\">\r\n @if (hasMultipleWorkflows()) {\r\n <div class=\"pointer-events-auto absolute top-4 start-4 z-10\">\r\n <mt-card class=\"w-64\">\r\n <mt-select-field\r\n [options]=\"workflows()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [ngModel]=\"selectedWorkflowId()\"\r\n (ngModelChange)=\"onWorkflowChange($event)\"\r\n class=\"mt-2\"\r\n />\r\n </mt-card>\r\n </div>\r\n }\r\n <div class=\"pointer-events-auto absolute top-4 end-4 z-10\">\r\n <div class=\"flex flex-col gap-2 w-80\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-10\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"dev.dataflow-01\"\r\n />\r\n <label>{{\r\n \"workflow.builder.enableWorkflow\" | transloco\r\n }}</label>\r\n </div>\r\n <mt-toggle-field\r\n [ngModel]=\"isPublished()\"\r\n (ngModelChange)=\"onPublishToggle($event)\"\r\n [disabled]=\"isPublishDisabled()\"\r\n ></mt-toggle-field>\r\n </div>\r\n </mt-card>\r\n\r\n @if (publishError()) {\r\n <mt-card>\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ publishError() }}\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n <ng-template\r\n #nodeDialog\r\n let-close=\"close\"\r\n let-save=\"save\"\r\n let-node=\"node\"\r\n let-drawerController=\"drawerController\"\r\n >\r\n <div class=\"p-4\">\r\n @if (loadingStep()) {\r\n <div class=\"space-y-4\">\r\n <div class=\"flex gap-2 mb-4\">\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <!-- Form fields skeleton -->\r\n <div class=\"space-y-4\">\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"10rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"3rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"4rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <mt-tabs\r\n [active]=\"selectedTab()\"\r\n (activeChange)=\"onNodeDialogTabChange($event)\"\r\n [options]=\"tabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n @switch (selectedTab()) {\r\n @case (\"tab1\") {\r\n <div class=\"mt-4 space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <mt-text-field\r\n [label]=\"t('nameEnglish')\"\r\n [placeholder]=\"t('enterNameEnglish')\"\r\n [formControl]=\"stepForm.controls.nameEn\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n <mt-text-field\r\n [label]=\"t('nameArabic')\"\r\n [placeholder]=\"t('enterNameArabic')\"\r\n [formControl]=\"stepForm.controls.nameAr\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n </div>\r\n\r\n @if (currentStepType() === \"UserInput\") {\r\n @if (!isEditingInitialNode()) {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"approver\") }}\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('approver')\"\r\n [options]=\"[\r\n { label: t('group'), value: '1' },\r\n { label: t('role'), value: '2' },\r\n ]\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.targetType\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n @if (\r\n stepForm.controls.targetType.value === \"1\"\r\n ) {\r\n <mt-select-field\r\n [label]=\"t('group')\"\r\n [placeholder]=\"t('selectGroup')\"\r\n [options]=\"groups()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [formControl]=\"stepForm.controls.group\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n @if (\r\n stepForm.controls.group.hasError(\r\n \"groupMissing\"\r\n )\r\n ) {\r\n <p class=\"text-sm text-red-700\">\r\n {{ t(\"groupMissing\") }}\r\n </p>\r\n }\r\n } @else {\r\n <mt-select-field\r\n [label]=\"t('role')\"\r\n [placeholder]=\"t('selectRole')\"\r\n [options]=\"roles()\"\r\n [group]=\"hasGroupedRoles()\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.role\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n }\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n } @else {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"app\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-700\"\r\n >\r\n {{ t(\"appLabelPplus\") }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"action\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-900\"\r\n [title]=\"getAppActionKey()\"\r\n >\r\n {{ getAppActionDisplayName() }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n getAppActionDescription();\r\n as description\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-muted-color\"\r\n >\r\n {{ description }}\r\n </div>\r\n }\r\n\r\n @if (\r\n getAppActionDiscoveryMessage();\r\n as discoveryMessage\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ discoveryMessage }}\r\n </div>\r\n }\r\n\r\n @if (isAppActionMissing()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n <div class=\"font-semibold\">\r\n {{ t(\"unknownAppAction\") }}\r\n </div>\r\n <div class=\"mt-1 text-xs\">\r\n {{ t(\"unknownAppActionHint\") }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div>\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionConfiguration\") }}\r\n </div>\r\n <div class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"appActionConfigurationDescription\") }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n loadingAppActionDetail() &&\r\n appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div class=\"space-y-3\">\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"6rem\"\r\n ></p-skeleton>\r\n </div>\r\n } @else if (\r\n !appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-dashed border-surface-300 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionUnavailable\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"schema\" &&\r\n appActionConfigDefinition().fields.length === 0\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionNoConfigRequired\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"raw\"\r\n ) {\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionRawConfigFallback\") }}\r\n </div>\r\n <mt-textarea-field\r\n [label]=\"t('appActionConfigJson')\"\r\n [placeholder]=\"\r\n t('enterAppActionConfigJson')\r\n \"\r\n [formControl]=\"appActionRawConfigControl\"\r\n [rows]=\"'10'\"\r\n ></mt-textarea-field>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (\r\n field of appActionConfigDefinition().fields;\r\n track field.key\r\n ) {\r\n <div class=\"space-y-2\">\r\n @switch (field.kind) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-text-field>\r\n }\r\n @case (\"number\") {\r\n <mt-number-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-number-field>\r\n }\r\n @case (\"toggle\") {\r\n <mt-toggle-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [label]=\"field.title\"\r\n [options]=\"\r\n getAppActionEnumOptions(field)\r\n \"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-select-field>\r\n }\r\n @case (\"json\") {\r\n <mt-textarea-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n [rows]=\"'8'\"\r\n ></mt-textarea-field>\r\n }\r\n }\r\n\r\n @if (field.description) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ field.description }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getAppActionConfigMessages().length) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700\"\r\n >\r\n @for (\r\n message of getAppActionConfigMessages();\r\n track message\r\n ) {\r\n <div>{{ message }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n\r\n @if (isAppActionAfterCommitOnly()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-3 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionAfterCommitGuidance\") }}\r\n </div>\r\n }\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"advancedExecution\") }}\r\n </div>\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n\r\n <mt-select-field\r\n [label]=\"t('failureBehavior')\"\r\n [options]=\"failureBehaviorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.failureBehavior\r\n \"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n <mt-number-field\r\n [label]=\"t('timeoutSeconds')\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.timeoutSeconds\r\n \"\r\n [required]=\"true\"\r\n [min]=\"1\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n\r\n <!--\r\n Read-only informational sections moved to the\r\n end of the form (lowest priority). Both default\r\n collapsed; the entire header is a click target\r\n with a visible \"Show / Hide\" affordance.\r\n -->\r\n @if (getAppActionRuntimeInputs().length) {\r\n <button\r\n type=\"button\"\r\n class=\"group flex w-full items-center justify-between gap-3 rounded-xl border border-surface-200 bg-surface-50 px-3 py-2.5 text-start transition-colors hover:bg-surface-100\"\r\n (click)=\"\r\n resolvedAutomaticallyOpen.set(\r\n !resolvedAutomaticallyOpen()\r\n )\r\n \"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionResolvedAutomatically\") }}\r\n <span\r\n class=\"ms-1 text-xs font-normal text-muted-color\"\r\n >\r\n ({{ getAppActionRuntimeInputs().length }})\r\n </span>\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionResolvedAutomaticallyHint\") }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 inline-flex items-center gap-1 text-xs font-medium text-primary\"\r\n >\r\n {{\r\n resolvedAutomaticallyOpen()\r\n ? t(\"hideDetails\")\r\n : t(\"showDetails\")\r\n }}\r\n <mt-icon\r\n [icon]=\"\r\n resolvedAutomaticallyOpen()\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n />\r\n </span>\r\n </button>\r\n @if (resolvedAutomaticallyOpen()) {\r\n <mt-card>\r\n <div class=\"space-y-2\">\r\n @for (\r\n input of getAppActionRuntimeInputs();\r\n track input.key\r\n ) {\r\n <div\r\n class=\"flex items-start justify-between gap-3 rounded-lg border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ input.key }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{\r\n describeRuntimeInputSource(input)\r\n }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 rounded-full bg-surface-200 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-surface-600\"\r\n >\r\n {{ t(\"appActionRuntime\") }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n\r\n @if (getAppActionOutputs().length) {\r\n <button\r\n type=\"button\"\r\n class=\"group flex w-full items-center justify-between gap-3 rounded-xl border border-surface-200 bg-surface-50 px-3 py-2.5 text-start transition-colors hover:bg-surface-100\"\r\n (click)=\"outputsOpen.set(!outputsOpen())\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionOutputs\") }}\r\n <span\r\n class=\"ms-1 text-xs font-normal text-muted-color\"\r\n >\r\n ({{ getAppActionOutputs().length }})\r\n </span>\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionOutputsHint\") }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 inline-flex items-center gap-1 text-xs font-medium text-primary\"\r\n >\r\n {{\r\n outputsOpen()\r\n ? t(\"hideDetails\")\r\n : t(\"showDetails\")\r\n }}\r\n <mt-icon\r\n [icon]=\"\r\n outputsOpen()\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n />\r\n </span>\r\n </button>\r\n @if (outputsOpen()) {\r\n <mt-card>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (\r\n output of getAppActionOutputs();\r\n track output.key\r\n ) {\r\n <span\r\n class=\"rounded-md bg-surface-100 px-2 py-0.5 text-xs font-mono text-surface-700\"\r\n [title]=\"output.description ?? ''\"\r\n >\r\n {{ output.key }}:{{ output.type }}\r\n </span>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n }\r\n </div>\r\n }\r\n @case (\"tab2\") {\r\n <div class=\"mt-4\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-4\">\r\n <div class=\"flex flex-1 items-center gap-3\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"file.file-check-02\"\r\n />\r\n <div class=\"flex flex-col\">\r\n <label class=\"font-medium\">{{\r\n t(\"configureForm\")\r\n }}</label>\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"configureForm-description\")\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"mt-3 flex gap-2\">\r\n <mt-button\r\n [label]=\"t('configureForm')\"\r\n size=\"small\"\r\n (onClick)=\"openFormModal()\"\r\n ></mt-button>\r\n <mt-button\r\n [label]=\"t('resetForm')\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n [loading]=\"isResettingForm()\"\r\n (onClick)=\"onResetForm()\"\r\n ></mt-button>\r\n </div>\r\n </mt-card>\r\n </div>\r\n }\r\n @case (\"tab3\") {\r\n <div class=\"mt-4\">\r\n <mt-toggle-field\r\n toggleShape=\"card\"\r\n [label]=\"t('show-hide')\"\r\n [descriptionCard]=\"t('show-hide-notifications')\"\r\n icon=\"general.eye\"\r\n [formControl]=\"showHideControl\"\r\n >\r\n <ng-template #toggleCardBottom>\r\n @if (showHideControl.value) {\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureNotifications')\"\r\n size=\"small\"\r\n (onClick)=\"openNotificationsModal()\"\r\n ></mt-button>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-toggle-field>\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n </mt-structure-builder>\r\n } @else {\r\n <p-skeleton width=\"100%\" height=\"50rem\" />\r\n }\r\n }\r\n @case (\"notification\") {\r\n <div class=\"flex-1 flex justify-center items-start p-4\">\r\n <div class=\"w-1/2 max-[1025px]:w-full\">\r\n <mt-card [title]=\"t('notifications')\" paddingless>\r\n <mt-notification-template />\r\n </mt-card>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "component", type: StructureBuilder, selector: "mt-structure-builder", inputs: ["availableNodes", "availableNodesLabel", "nodeForm", "nodeDialogFooterConfig", "connectionForm", "connectionFormulaSchemaId", "connectionFormulaConfig", "nodeActions", "nodeFields", "isAutoLayout", "readonly", "structureMode", "nodeStyle", "addModalType", "updateModalType", "addModalStyleClass", "updateModalStyleClass", "addModalHeader", "updateModalHeader", "appendTo", "availableTabsClass", "layoutDirection", "nodes", "connections", "nodeTemplate"], outputs: ["nodeActionsEvent", "action", "nodesChange", "connectionsChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: i2.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: NotificationTemplate, selector: "mt-notification-template" }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
3133
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkflowBuilder, isStandalone: true, selector: "mt-workflow-builder", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workflow.builder'\">\r\n <div class=\"h-full flex flex-col\" id=\"workflow-builder-card\">\r\n <div class=\"flex justify-center w-full py-2\">\r\n <mt-tabs\r\n [active]=\"mainTab()\"\r\n (activeChange)=\"onMainTabChange($event)\"\r\n [options]=\"mainTabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n </div>\r\n @switch (mainTab()) {\r\n @case (\"workflow\") {\r\n @if (!loading()) {\r\n <mt-structure-builder\r\n class=\"flex-1\"\r\n [structureMode]=\"'workflow'\"\r\n [availableNodes]=\"availableNodes()\"\r\n [availableNodesLabel]=\"t('stepTemplates')\"\r\n [connectionForm]=\"connectionForm()\"\r\n [connectionFormulaSchemaId]=\"connectionFormulaSchemaId()\"\r\n [connectionFormulaConfig]=\"connectionFormulaConfig()\"\r\n [connectionGuard]=\"connectionGuard\"\r\n [nodeActions]=\"nodeActions()\"\r\n [nodes]=\"steps()\"\r\n [connections]=\"connections()\"\r\n (action)=\"onStructureAction($event)\"\r\n [addModalType]=\"'drawer'\"\r\n [addModalStyleClass]=\"editorDrawerStyleClass\"\r\n [updateModalStyleClass]=\"editorDrawerStyleClass\"\r\n [addModalHeader]=\"editorAddHeader\"\r\n [updateModalHeader]=\"editorUpdateHeader\"\r\n [nodeDialogFooterConfig]=\"nodeDialogFooterConfig\"\r\n [appendTo]=\"'page-content'\"\r\n [nodeFields]=\"nodeFields()\"\r\n [availableTabsClass]=\"hasMultipleWorkflows() ? '!mt-28' : ''\"\r\n [layoutDirection]=\"'LR'\"\r\n >\r\n <div flowContent class=\"pointer-events-none\">\r\n @if (hasMultipleWorkflows()) {\r\n <div class=\"pointer-events-auto absolute top-4 start-4 z-10\">\r\n <mt-card class=\"w-64\">\r\n <mt-select-field\r\n [options]=\"workflows()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [ngModel]=\"selectedWorkflowId()\"\r\n (ngModelChange)=\"onWorkflowChange($event)\"\r\n class=\"mt-2\"\r\n />\r\n </mt-card>\r\n </div>\r\n }\r\n <div class=\"pointer-events-auto absolute top-4 end-4 z-10\">\r\n <div class=\"flex flex-col gap-2 w-80\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-10\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"dev.dataflow-01\"\r\n />\r\n <label>{{\r\n \"workflow.builder.enableWorkflow\" | transloco\r\n }}</label>\r\n </div>\r\n <mt-toggle-field\r\n [ngModel]=\"isPublished()\"\r\n (ngModelChange)=\"onPublishToggle($event)\"\r\n [disabled]=\"isPublishDisabled()\"\r\n ></mt-toggle-field>\r\n </div>\r\n </mt-card>\r\n\r\n @if (publishError()) {\r\n <mt-card>\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ publishError() }}\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n <ng-template\r\n #nodeDialog\r\n let-close=\"close\"\r\n let-save=\"save\"\r\n let-node=\"node\"\r\n let-drawerController=\"drawerController\"\r\n >\r\n <div class=\"p-4\">\r\n @if (loadingStep()) {\r\n <div class=\"space-y-4\">\r\n <div class=\"flex gap-2 mb-4\">\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <!-- Form fields skeleton -->\r\n <div class=\"space-y-4\">\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"10rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"3rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"4rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <mt-tabs\r\n [active]=\"selectedTab()\"\r\n (activeChange)=\"onNodeDialogTabChange($event)\"\r\n [options]=\"tabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n @switch (selectedTab()) {\r\n @case (\"tab1\") {\r\n <div class=\"mt-4 space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <mt-text-field\r\n [label]=\"t('nameEnglish')\"\r\n [placeholder]=\"t('enterNameEnglish')\"\r\n [formControl]=\"stepForm.controls.nameEn\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n <mt-text-field\r\n [label]=\"t('nameArabic')\"\r\n [placeholder]=\"t('enterNameArabic')\"\r\n [formControl]=\"stepForm.controls.nameAr\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n </div>\r\n\r\n @if (currentStepType() === \"UserInput\") {\r\n @if (!isEditingInitialNode()) {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"approver\") }}\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('approver')\"\r\n [options]=\"[\r\n { label: t('group'), value: '1' },\r\n { label: t('role'), value: '2' },\r\n ]\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.targetType\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n @if (\r\n stepForm.controls.targetType.value === \"1\"\r\n ) {\r\n <mt-select-field\r\n [label]=\"t('group')\"\r\n [placeholder]=\"t('selectGroup')\"\r\n [options]=\"groups()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [formControl]=\"stepForm.controls.group\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n @if (\r\n stepForm.controls.group.hasError(\r\n \"groupMissing\"\r\n )\r\n ) {\r\n <p class=\"text-sm text-red-700\">\r\n {{ t(\"groupMissing\") }}\r\n </p>\r\n }\r\n } @else {\r\n <mt-select-field\r\n [label]=\"t('role')\"\r\n [placeholder]=\"t('selectRole')\"\r\n [options]=\"roles()\"\r\n [group]=\"hasGroupedRoles()\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.role\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n }\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n } @else {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"app\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-700\"\r\n >\r\n {{ t(\"appLabelPplus\") }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"action\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-900\"\r\n [title]=\"getAppActionKey()\"\r\n >\r\n {{ getAppActionDisplayName() }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n getAppActionDescription();\r\n as description\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-muted-color\"\r\n >\r\n {{ description }}\r\n </div>\r\n }\r\n\r\n @if (\r\n getAppActionDiscoveryMessage();\r\n as discoveryMessage\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ discoveryMessage }}\r\n </div>\r\n }\r\n\r\n @if (isAppActionMissing()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n <div class=\"font-semibold\">\r\n {{ t(\"unknownAppAction\") }}\r\n </div>\r\n <div class=\"mt-1 text-xs\">\r\n {{ t(\"unknownAppActionHint\") }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div>\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionConfiguration\") }}\r\n </div>\r\n <div class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"appActionConfigurationDescription\") }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n loadingAppActionDetail() &&\r\n appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div class=\"space-y-3\">\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"6rem\"\r\n ></p-skeleton>\r\n </div>\r\n } @else if (\r\n !appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-dashed border-surface-300 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionUnavailable\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"schema\" &&\r\n appActionConfigDefinition().fields.length === 0\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionNoConfigRequired\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"raw\"\r\n ) {\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionRawConfigFallback\") }}\r\n </div>\r\n <mt-textarea-field\r\n [label]=\"t('appActionConfigJson')\"\r\n [placeholder]=\"\r\n t('enterAppActionConfigJson')\r\n \"\r\n [formControl]=\"appActionRawConfigControl\"\r\n [rows]=\"'10'\"\r\n ></mt-textarea-field>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (\r\n field of appActionConfigDefinition().fields;\r\n track field.key\r\n ) {\r\n <div class=\"space-y-2\">\r\n @switch (field.kind) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-text-field>\r\n }\r\n @case (\"number\") {\r\n <mt-number-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-number-field>\r\n }\r\n @case (\"toggle\") {\r\n <mt-toggle-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [label]=\"field.title\"\r\n [options]=\"\r\n getAppActionEnumOptions(field)\r\n \"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-select-field>\r\n }\r\n @case (\"json\") {\r\n <mt-textarea-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n [rows]=\"'8'\"\r\n ></mt-textarea-field>\r\n }\r\n }\r\n\r\n @if (field.description) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ field.description }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getAppActionConfigMessages().length) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700\"\r\n >\r\n @for (\r\n message of getAppActionConfigMessages();\r\n track message\r\n ) {\r\n <div>{{ message }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n\r\n @if (isAppActionAfterCommitOnly()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-3 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionAfterCommitGuidance\") }}\r\n </div>\r\n }\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"advancedExecution\") }}\r\n </div>\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n\r\n <mt-select-field\r\n [label]=\"t('failureBehavior')\"\r\n [options]=\"failureBehaviorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.failureBehavior\r\n \"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n <mt-number-field\r\n [label]=\"t('timeoutSeconds')\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.timeoutSeconds\r\n \"\r\n [required]=\"true\"\r\n [min]=\"1\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n\r\n <!--\r\n Read-only informational sections moved to the\r\n end of the form (lowest priority). Both default\r\n collapsed; the entire header is a click target\r\n with a visible \"Show / Hide\" affordance.\r\n -->\r\n @if (getAppActionRuntimeInputs().length) {\r\n <button\r\n type=\"button\"\r\n class=\"group flex w-full items-center justify-between gap-3 rounded-xl border border-surface-200 bg-surface-50 px-3 py-2.5 text-start transition-colors hover:bg-surface-100\"\r\n (click)=\"\r\n resolvedAutomaticallyOpen.set(\r\n !resolvedAutomaticallyOpen()\r\n )\r\n \"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionResolvedAutomatically\") }}\r\n <span\r\n class=\"ms-1 text-xs font-normal text-muted-color\"\r\n >\r\n ({{ getAppActionRuntimeInputs().length }})\r\n </span>\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionResolvedAutomaticallyHint\") }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 inline-flex items-center gap-1 text-xs font-medium text-primary\"\r\n >\r\n {{\r\n resolvedAutomaticallyOpen()\r\n ? t(\"hideDetails\")\r\n : t(\"showDetails\")\r\n }}\r\n <mt-icon\r\n [icon]=\"\r\n resolvedAutomaticallyOpen()\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n />\r\n </span>\r\n </button>\r\n @if (resolvedAutomaticallyOpen()) {\r\n <mt-card>\r\n <div class=\"space-y-2\">\r\n @for (\r\n input of getAppActionRuntimeInputs();\r\n track input.key\r\n ) {\r\n <div\r\n class=\"flex items-start justify-between gap-3 rounded-lg border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ input.key }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{\r\n describeRuntimeInputSource(input)\r\n }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 rounded-full bg-surface-200 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-surface-600\"\r\n >\r\n {{ t(\"appActionRuntime\") }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n\r\n @if (getAppActionOutputs().length) {\r\n <button\r\n type=\"button\"\r\n class=\"group flex w-full items-center justify-between gap-3 rounded-xl border border-surface-200 bg-surface-50 px-3 py-2.5 text-start transition-colors hover:bg-surface-100\"\r\n (click)=\"outputsOpen.set(!outputsOpen())\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionOutputs\") }}\r\n <span\r\n class=\"ms-1 text-xs font-normal text-muted-color\"\r\n >\r\n ({{ getAppActionOutputs().length }})\r\n </span>\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionOutputsHint\") }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 inline-flex items-center gap-1 text-xs font-medium text-primary\"\r\n >\r\n {{\r\n outputsOpen()\r\n ? t(\"hideDetails\")\r\n : t(\"showDetails\")\r\n }}\r\n <mt-icon\r\n [icon]=\"\r\n outputsOpen()\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n />\r\n </span>\r\n </button>\r\n @if (outputsOpen()) {\r\n <mt-card>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (\r\n output of getAppActionOutputs();\r\n track output.key\r\n ) {\r\n <span\r\n class=\"rounded-md bg-surface-100 px-2 py-0.5 text-xs font-mono text-surface-700\"\r\n [title]=\"output.description ?? ''\"\r\n >\r\n {{ output.key }}:{{ output.type }}\r\n </span>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n }\r\n </div>\r\n }\r\n @case (\"tab2\") {\r\n <div class=\"mt-4\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-4\">\r\n <div class=\"flex flex-1 items-center gap-3\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"file.file-check-02\"\r\n />\r\n <div class=\"flex flex-col\">\r\n <label class=\"font-medium\">{{\r\n t(\"configureForm\")\r\n }}</label>\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"configureForm-description\")\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"mt-3 flex gap-2\">\r\n <mt-button\r\n [label]=\"t('configureForm')\"\r\n size=\"small\"\r\n (onClick)=\"openFormModal()\"\r\n ></mt-button>\r\n <mt-button\r\n [label]=\"t('resetForm')\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n [loading]=\"isResettingForm()\"\r\n (onClick)=\"onResetForm()\"\r\n ></mt-button>\r\n </div>\r\n </mt-card>\r\n </div>\r\n }\r\n @case (\"tab3\") {\r\n <div class=\"mt-4\">\r\n <mt-toggle-field\r\n toggleShape=\"card\"\r\n [label]=\"t('show-hide')\"\r\n [descriptionCard]=\"t('show-hide-notifications')\"\r\n icon=\"general.eye\"\r\n [formControl]=\"showHideControl\"\r\n >\r\n <ng-template #toggleCardBottom>\r\n @if (showHideControl.value) {\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureNotifications')\"\r\n size=\"small\"\r\n (onClick)=\"openNotificationsModal()\"\r\n ></mt-button>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-toggle-field>\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n </mt-structure-builder>\r\n } @else {\r\n <p-skeleton width=\"100%\" height=\"50rem\" />\r\n }\r\n }\r\n @case (\"notification\") {\r\n <div class=\"flex-1 flex justify-center items-start p-4\">\r\n <div class=\"w-1/2 max-[1025px]:w-full\">\r\n <mt-card [title]=\"t('notifications')\" paddingless>\r\n <mt-notification-template />\r\n </mt-card>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "component", type: StructureBuilder, selector: "mt-structure-builder", inputs: ["availableNodes", "availableNodesLabel", "nodeForm", "nodeDialogFooterConfig", "connectionForm", "connectionFormulaSchemaId", "connectionFormulaConfig", "connectionGuard", "nodeActions", "nodeFields", "isAutoLayout", "readonly", "structureMode", "nodeStyle", "addModalType", "updateModalType", "addModalStyleClass", "updateModalStyleClass", "addModalHeader", "updateModalHeader", "appendTo", "availableTabsClass", "layoutDirection", "nodes", "connections", "nodeTemplate"], outputs: ["nodeActionsEvent", "action", "nodesChange", "connectionsChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "defaultIcon", "size", "fluid", "disabled", "searchThreshold"], outputs: ["activeChange", "onChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: i2.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: NotificationTemplate, selector: "mt-notification-template" }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "maxLength", "icon", "iconPosition"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required", "maxLength"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
3090
3134
  }
3091
3135
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkflowBuilder, decorators: [{
3092
3136
  type: Component,
@@ -3105,7 +3149,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
3105
3149
  TextField,
3106
3150
  NumberField,
3107
3151
  TextareaField,
3108
- ], host: {}, template: "<ng-container *transloco=\"let t; prefix: 'workflow.builder'\">\r\n <div class=\"h-full flex flex-col\" id=\"workflow-builder-card\">\r\n <div class=\"flex justify-center w-full py-2\">\r\n <mt-tabs\r\n [active]=\"mainTab()\"\r\n (activeChange)=\"onMainTabChange($event)\"\r\n [options]=\"mainTabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n </div>\r\n @switch (mainTab()) {\r\n @case (\"workflow\") {\r\n @if (!loading()) {\r\n <mt-structure-builder\r\n class=\"flex-1\"\r\n [structureMode]=\"'workflow'\"\r\n [availableNodes]=\"availableNodes()\"\r\n [availableNodesLabel]=\"t('stepTemplates')\"\r\n [connectionForm]=\"connectionForm()\"\r\n [connectionFormulaSchemaId]=\"connectionFormulaSchemaId()\"\r\n [connectionFormulaConfig]=\"connectionFormulaConfig()\"\r\n [nodeActions]=\"nodeActions()\"\r\n [nodes]=\"steps()\"\r\n [connections]=\"connections()\"\r\n (action)=\"onStructureAction($event)\"\r\n [addModalType]=\"'drawer'\"\r\n [addModalStyleClass]=\"editorDrawerStyleClass\"\r\n [updateModalStyleClass]=\"editorDrawerStyleClass\"\r\n [addModalHeader]=\"editorAddHeader\"\r\n [updateModalHeader]=\"editorUpdateHeader\"\r\n [nodeDialogFooterConfig]=\"nodeDialogFooterConfig\"\r\n [appendTo]=\"'page-content'\"\r\n [nodeFields]=\"nodeFields()\"\r\n [availableTabsClass]=\"hasMultipleWorkflows() ? '!mt-28' : ''\"\r\n [layoutDirection]=\"'LR'\"\r\n >\r\n <div flowContent class=\"pointer-events-none\">\r\n @if (hasMultipleWorkflows()) {\r\n <div class=\"pointer-events-auto absolute top-4 start-4 z-10\">\r\n <mt-card class=\"w-64\">\r\n <mt-select-field\r\n [options]=\"workflows()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [ngModel]=\"selectedWorkflowId()\"\r\n (ngModelChange)=\"onWorkflowChange($event)\"\r\n class=\"mt-2\"\r\n />\r\n </mt-card>\r\n </div>\r\n }\r\n <div class=\"pointer-events-auto absolute top-4 end-4 z-10\">\r\n <div class=\"flex flex-col gap-2 w-80\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-10\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"dev.dataflow-01\"\r\n />\r\n <label>{{\r\n \"workflow.builder.enableWorkflow\" | transloco\r\n }}</label>\r\n </div>\r\n <mt-toggle-field\r\n [ngModel]=\"isPublished()\"\r\n (ngModelChange)=\"onPublishToggle($event)\"\r\n [disabled]=\"isPublishDisabled()\"\r\n ></mt-toggle-field>\r\n </div>\r\n </mt-card>\r\n\r\n @if (publishError()) {\r\n <mt-card>\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ publishError() }}\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n <ng-template\r\n #nodeDialog\r\n let-close=\"close\"\r\n let-save=\"save\"\r\n let-node=\"node\"\r\n let-drawerController=\"drawerController\"\r\n >\r\n <div class=\"p-4\">\r\n @if (loadingStep()) {\r\n <div class=\"space-y-4\">\r\n <div class=\"flex gap-2 mb-4\">\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <!-- Form fields skeleton -->\r\n <div class=\"space-y-4\">\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"10rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"3rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"4rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <mt-tabs\r\n [active]=\"selectedTab()\"\r\n (activeChange)=\"onNodeDialogTabChange($event)\"\r\n [options]=\"tabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n @switch (selectedTab()) {\r\n @case (\"tab1\") {\r\n <div class=\"mt-4 space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <mt-text-field\r\n [label]=\"t('nameEnglish')\"\r\n [placeholder]=\"t('enterNameEnglish')\"\r\n [formControl]=\"stepForm.controls.nameEn\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n <mt-text-field\r\n [label]=\"t('nameArabic')\"\r\n [placeholder]=\"t('enterNameArabic')\"\r\n [formControl]=\"stepForm.controls.nameAr\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n </div>\r\n\r\n @if (currentStepType() === \"UserInput\") {\r\n @if (!isEditingInitialNode()) {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"approver\") }}\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('approver')\"\r\n [options]=\"[\r\n { label: t('group'), value: '1' },\r\n { label: t('role'), value: '2' },\r\n ]\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.targetType\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n @if (\r\n stepForm.controls.targetType.value === \"1\"\r\n ) {\r\n <mt-select-field\r\n [label]=\"t('group')\"\r\n [placeholder]=\"t('selectGroup')\"\r\n [options]=\"groups()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [formControl]=\"stepForm.controls.group\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n @if (\r\n stepForm.controls.group.hasError(\r\n \"groupMissing\"\r\n )\r\n ) {\r\n <p class=\"text-sm text-red-700\">\r\n {{ t(\"groupMissing\") }}\r\n </p>\r\n }\r\n } @else {\r\n <mt-select-field\r\n [label]=\"t('role')\"\r\n [placeholder]=\"t('selectRole')\"\r\n [options]=\"roles()\"\r\n [group]=\"hasGroupedRoles()\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.role\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n }\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n } @else {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"app\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-700\"\r\n >\r\n {{ t(\"appLabelPplus\") }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"action\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-900\"\r\n [title]=\"getAppActionKey()\"\r\n >\r\n {{ getAppActionDisplayName() }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n getAppActionDescription();\r\n as description\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-muted-color\"\r\n >\r\n {{ description }}\r\n </div>\r\n }\r\n\r\n @if (\r\n getAppActionDiscoveryMessage();\r\n as discoveryMessage\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ discoveryMessage }}\r\n </div>\r\n }\r\n\r\n @if (isAppActionMissing()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n <div class=\"font-semibold\">\r\n {{ t(\"unknownAppAction\") }}\r\n </div>\r\n <div class=\"mt-1 text-xs\">\r\n {{ t(\"unknownAppActionHint\") }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div>\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionConfiguration\") }}\r\n </div>\r\n <div class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"appActionConfigurationDescription\") }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n loadingAppActionDetail() &&\r\n appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div class=\"space-y-3\">\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"6rem\"\r\n ></p-skeleton>\r\n </div>\r\n } @else if (\r\n !appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-dashed border-surface-300 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionUnavailable\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"schema\" &&\r\n appActionConfigDefinition().fields.length === 0\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionNoConfigRequired\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"raw\"\r\n ) {\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionRawConfigFallback\") }}\r\n </div>\r\n <mt-textarea-field\r\n [label]=\"t('appActionConfigJson')\"\r\n [placeholder]=\"\r\n t('enterAppActionConfigJson')\r\n \"\r\n [formControl]=\"appActionRawConfigControl\"\r\n [rows]=\"'10'\"\r\n ></mt-textarea-field>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (\r\n field of appActionConfigDefinition().fields;\r\n track field.key\r\n ) {\r\n <div class=\"space-y-2\">\r\n @switch (field.kind) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-text-field>\r\n }\r\n @case (\"number\") {\r\n <mt-number-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-number-field>\r\n }\r\n @case (\"toggle\") {\r\n <mt-toggle-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [label]=\"field.title\"\r\n [options]=\"\r\n getAppActionEnumOptions(field)\r\n \"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-select-field>\r\n }\r\n @case (\"json\") {\r\n <mt-textarea-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n [rows]=\"'8'\"\r\n ></mt-textarea-field>\r\n }\r\n }\r\n\r\n @if (field.description) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ field.description }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getAppActionConfigMessages().length) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700\"\r\n >\r\n @for (\r\n message of getAppActionConfigMessages();\r\n track message\r\n ) {\r\n <div>{{ message }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n\r\n @if (isAppActionAfterCommitOnly()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-3 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionAfterCommitGuidance\") }}\r\n </div>\r\n }\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"advancedExecution\") }}\r\n </div>\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n\r\n <mt-select-field\r\n [label]=\"t('failureBehavior')\"\r\n [options]=\"failureBehaviorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.failureBehavior\r\n \"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n <mt-number-field\r\n [label]=\"t('timeoutSeconds')\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.timeoutSeconds\r\n \"\r\n [required]=\"true\"\r\n [min]=\"1\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n\r\n <!--\r\n Read-only informational sections moved to the\r\n end of the form (lowest priority). Both default\r\n collapsed; the entire header is a click target\r\n with a visible \"Show / Hide\" affordance.\r\n -->\r\n @if (getAppActionRuntimeInputs().length) {\r\n <button\r\n type=\"button\"\r\n class=\"group flex w-full items-center justify-between gap-3 rounded-xl border border-surface-200 bg-surface-50 px-3 py-2.5 text-start transition-colors hover:bg-surface-100\"\r\n (click)=\"\r\n resolvedAutomaticallyOpen.set(\r\n !resolvedAutomaticallyOpen()\r\n )\r\n \"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionResolvedAutomatically\") }}\r\n <span\r\n class=\"ms-1 text-xs font-normal text-muted-color\"\r\n >\r\n ({{ getAppActionRuntimeInputs().length }})\r\n </span>\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionResolvedAutomaticallyHint\") }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 inline-flex items-center gap-1 text-xs font-medium text-primary\"\r\n >\r\n {{\r\n resolvedAutomaticallyOpen()\r\n ? t(\"hideDetails\")\r\n : t(\"showDetails\")\r\n }}\r\n <mt-icon\r\n [icon]=\"\r\n resolvedAutomaticallyOpen()\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n />\r\n </span>\r\n </button>\r\n @if (resolvedAutomaticallyOpen()) {\r\n <mt-card>\r\n <div class=\"space-y-2\">\r\n @for (\r\n input of getAppActionRuntimeInputs();\r\n track input.key\r\n ) {\r\n <div\r\n class=\"flex items-start justify-between gap-3 rounded-lg border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ input.key }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{\r\n describeRuntimeInputSource(input)\r\n }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 rounded-full bg-surface-200 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-surface-600\"\r\n >\r\n {{ t(\"appActionRuntime\") }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n\r\n @if (getAppActionOutputs().length) {\r\n <button\r\n type=\"button\"\r\n class=\"group flex w-full items-center justify-between gap-3 rounded-xl border border-surface-200 bg-surface-50 px-3 py-2.5 text-start transition-colors hover:bg-surface-100\"\r\n (click)=\"outputsOpen.set(!outputsOpen())\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionOutputs\") }}\r\n <span\r\n class=\"ms-1 text-xs font-normal text-muted-color\"\r\n >\r\n ({{ getAppActionOutputs().length }})\r\n </span>\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionOutputsHint\") }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 inline-flex items-center gap-1 text-xs font-medium text-primary\"\r\n >\r\n {{\r\n outputsOpen()\r\n ? t(\"hideDetails\")\r\n : t(\"showDetails\")\r\n }}\r\n <mt-icon\r\n [icon]=\"\r\n outputsOpen()\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n />\r\n </span>\r\n </button>\r\n @if (outputsOpen()) {\r\n <mt-card>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (\r\n output of getAppActionOutputs();\r\n track output.key\r\n ) {\r\n <span\r\n class=\"rounded-md bg-surface-100 px-2 py-0.5 text-xs font-mono text-surface-700\"\r\n [title]=\"output.description ?? ''\"\r\n >\r\n {{ output.key }}:{{ output.type }}\r\n </span>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n }\r\n </div>\r\n }\r\n @case (\"tab2\") {\r\n <div class=\"mt-4\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-4\">\r\n <div class=\"flex flex-1 items-center gap-3\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"file.file-check-02\"\r\n />\r\n <div class=\"flex flex-col\">\r\n <label class=\"font-medium\">{{\r\n t(\"configureForm\")\r\n }}</label>\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"configureForm-description\")\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"mt-3 flex gap-2\">\r\n <mt-button\r\n [label]=\"t('configureForm')\"\r\n size=\"small\"\r\n (onClick)=\"openFormModal()\"\r\n ></mt-button>\r\n <mt-button\r\n [label]=\"t('resetForm')\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n [loading]=\"isResettingForm()\"\r\n (onClick)=\"onResetForm()\"\r\n ></mt-button>\r\n </div>\r\n </mt-card>\r\n </div>\r\n }\r\n @case (\"tab3\") {\r\n <div class=\"mt-4\">\r\n <mt-toggle-field\r\n toggleShape=\"card\"\r\n [label]=\"t('show-hide')\"\r\n [descriptionCard]=\"t('show-hide-notifications')\"\r\n icon=\"general.eye\"\r\n [formControl]=\"showHideControl\"\r\n >\r\n <ng-template #toggleCardBottom>\r\n @if (showHideControl.value) {\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureNotifications')\"\r\n size=\"small\"\r\n (onClick)=\"openNotificationsModal()\"\r\n ></mt-button>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-toggle-field>\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n </mt-structure-builder>\r\n } @else {\r\n <p-skeleton width=\"100%\" height=\"50rem\" />\r\n }\r\n }\r\n @case (\"notification\") {\r\n <div class=\"flex-1 flex justify-center items-start p-4\">\r\n <div class=\"w-1/2 max-[1025px]:w-full\">\r\n <mt-card [title]=\"t('notifications')\" paddingless>\r\n <mt-notification-template />\r\n </mt-card>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n" }]
3152
+ ], host: {}, template: "<ng-container *transloco=\"let t; prefix: 'workflow.builder'\">\r\n <div class=\"h-full flex flex-col\" id=\"workflow-builder-card\">\r\n <div class=\"flex justify-center w-full py-2\">\r\n <mt-tabs\r\n [active]=\"mainTab()\"\r\n (activeChange)=\"onMainTabChange($event)\"\r\n [options]=\"mainTabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n </div>\r\n @switch (mainTab()) {\r\n @case (\"workflow\") {\r\n @if (!loading()) {\r\n <mt-structure-builder\r\n class=\"flex-1\"\r\n [structureMode]=\"'workflow'\"\r\n [availableNodes]=\"availableNodes()\"\r\n [availableNodesLabel]=\"t('stepTemplates')\"\r\n [connectionForm]=\"connectionForm()\"\r\n [connectionFormulaSchemaId]=\"connectionFormulaSchemaId()\"\r\n [connectionFormulaConfig]=\"connectionFormulaConfig()\"\r\n [connectionGuard]=\"connectionGuard\"\r\n [nodeActions]=\"nodeActions()\"\r\n [nodes]=\"steps()\"\r\n [connections]=\"connections()\"\r\n (action)=\"onStructureAction($event)\"\r\n [addModalType]=\"'drawer'\"\r\n [addModalStyleClass]=\"editorDrawerStyleClass\"\r\n [updateModalStyleClass]=\"editorDrawerStyleClass\"\r\n [addModalHeader]=\"editorAddHeader\"\r\n [updateModalHeader]=\"editorUpdateHeader\"\r\n [nodeDialogFooterConfig]=\"nodeDialogFooterConfig\"\r\n [appendTo]=\"'page-content'\"\r\n [nodeFields]=\"nodeFields()\"\r\n [availableTabsClass]=\"hasMultipleWorkflows() ? '!mt-28' : ''\"\r\n [layoutDirection]=\"'LR'\"\r\n >\r\n <div flowContent class=\"pointer-events-none\">\r\n @if (hasMultipleWorkflows()) {\r\n <div class=\"pointer-events-auto absolute top-4 start-4 z-10\">\r\n <mt-card class=\"w-64\">\r\n <mt-select-field\r\n [options]=\"workflows()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [ngModel]=\"selectedWorkflowId()\"\r\n (ngModelChange)=\"onWorkflowChange($event)\"\r\n class=\"mt-2\"\r\n />\r\n </mt-card>\r\n </div>\r\n }\r\n <div class=\"pointer-events-auto absolute top-4 end-4 z-10\">\r\n <div class=\"flex flex-col gap-2 w-80\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-10\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"dev.dataflow-01\"\r\n />\r\n <label>{{\r\n \"workflow.builder.enableWorkflow\" | transloco\r\n }}</label>\r\n </div>\r\n <mt-toggle-field\r\n [ngModel]=\"isPublished()\"\r\n (ngModelChange)=\"onPublishToggle($event)\"\r\n [disabled]=\"isPublishDisabled()\"\r\n ></mt-toggle-field>\r\n </div>\r\n </mt-card>\r\n\r\n @if (publishError()) {\r\n <mt-card>\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ publishError() }}\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n <ng-template\r\n #nodeDialog\r\n let-close=\"close\"\r\n let-save=\"save\"\r\n let-node=\"node\"\r\n let-drawerController=\"drawerController\"\r\n >\r\n <div class=\"p-4\">\r\n @if (loadingStep()) {\r\n <div class=\"space-y-4\">\r\n <div class=\"flex gap-2 mb-4\">\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <!-- Form fields skeleton -->\r\n <div class=\"space-y-4\">\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"10rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"3rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"4rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <mt-tabs\r\n [active]=\"selectedTab()\"\r\n (activeChange)=\"onNodeDialogTabChange($event)\"\r\n [options]=\"tabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n @switch (selectedTab()) {\r\n @case (\"tab1\") {\r\n <div class=\"mt-4 space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <mt-text-field\r\n [label]=\"t('nameEnglish')\"\r\n [placeholder]=\"t('enterNameEnglish')\"\r\n [formControl]=\"stepForm.controls.nameEn\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n <mt-text-field\r\n [label]=\"t('nameArabic')\"\r\n [placeholder]=\"t('enterNameArabic')\"\r\n [formControl]=\"stepForm.controls.nameAr\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n </div>\r\n\r\n @if (currentStepType() === \"UserInput\") {\r\n @if (!isEditingInitialNode()) {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"approver\") }}\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('approver')\"\r\n [options]=\"[\r\n { label: t('group'), value: '1' },\r\n { label: t('role'), value: '2' },\r\n ]\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.targetType\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n @if (\r\n stepForm.controls.targetType.value === \"1\"\r\n ) {\r\n <mt-select-field\r\n [label]=\"t('group')\"\r\n [placeholder]=\"t('selectGroup')\"\r\n [options]=\"groups()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [formControl]=\"stepForm.controls.group\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n @if (\r\n stepForm.controls.group.hasError(\r\n \"groupMissing\"\r\n )\r\n ) {\r\n <p class=\"text-sm text-red-700\">\r\n {{ t(\"groupMissing\") }}\r\n </p>\r\n }\r\n } @else {\r\n <mt-select-field\r\n [label]=\"t('role')\"\r\n [placeholder]=\"t('selectRole')\"\r\n [options]=\"roles()\"\r\n [group]=\"hasGroupedRoles()\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.role\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n }\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n } @else {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"app\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-700\"\r\n >\r\n {{ t(\"appLabelPplus\") }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"action\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-900\"\r\n [title]=\"getAppActionKey()\"\r\n >\r\n {{ getAppActionDisplayName() }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n getAppActionDescription();\r\n as description\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-muted-color\"\r\n >\r\n {{ description }}\r\n </div>\r\n }\r\n\r\n @if (\r\n getAppActionDiscoveryMessage();\r\n as discoveryMessage\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ discoveryMessage }}\r\n </div>\r\n }\r\n\r\n @if (isAppActionMissing()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n <div class=\"font-semibold\">\r\n {{ t(\"unknownAppAction\") }}\r\n </div>\r\n <div class=\"mt-1 text-xs\">\r\n {{ t(\"unknownAppActionHint\") }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div>\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionConfiguration\") }}\r\n </div>\r\n <div class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"appActionConfigurationDescription\") }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n loadingAppActionDetail() &&\r\n appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div class=\"space-y-3\">\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"6rem\"\r\n ></p-skeleton>\r\n </div>\r\n } @else if (\r\n !appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-dashed border-surface-300 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionUnavailable\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"schema\" &&\r\n appActionConfigDefinition().fields.length === 0\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionNoConfigRequired\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"raw\"\r\n ) {\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionRawConfigFallback\") }}\r\n </div>\r\n <mt-textarea-field\r\n [label]=\"t('appActionConfigJson')\"\r\n [placeholder]=\"\r\n t('enterAppActionConfigJson')\r\n \"\r\n [formControl]=\"appActionRawConfigControl\"\r\n [rows]=\"'10'\"\r\n ></mt-textarea-field>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (\r\n field of appActionConfigDefinition().fields;\r\n track field.key\r\n ) {\r\n <div class=\"space-y-2\">\r\n @switch (field.kind) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-text-field>\r\n }\r\n @case (\"number\") {\r\n <mt-number-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-number-field>\r\n }\r\n @case (\"toggle\") {\r\n <mt-toggle-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [label]=\"field.title\"\r\n [options]=\"\r\n getAppActionEnumOptions(field)\r\n \"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-select-field>\r\n }\r\n @case (\"json\") {\r\n <mt-textarea-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n [rows]=\"'8'\"\r\n ></mt-textarea-field>\r\n }\r\n }\r\n\r\n @if (field.description) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ field.description }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getAppActionConfigMessages().length) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700\"\r\n >\r\n @for (\r\n message of getAppActionConfigMessages();\r\n track message\r\n ) {\r\n <div>{{ message }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n\r\n @if (isAppActionAfterCommitOnly()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-3 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionAfterCommitGuidance\") }}\r\n </div>\r\n }\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"advancedExecution\") }}\r\n </div>\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n\r\n <mt-select-field\r\n [label]=\"t('failureBehavior')\"\r\n [options]=\"failureBehaviorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.failureBehavior\r\n \"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n <mt-number-field\r\n [label]=\"t('timeoutSeconds')\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.timeoutSeconds\r\n \"\r\n [required]=\"true\"\r\n [min]=\"1\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n\r\n <!--\r\n Read-only informational sections moved to the\r\n end of the form (lowest priority). Both default\r\n collapsed; the entire header is a click target\r\n with a visible \"Show / Hide\" affordance.\r\n -->\r\n @if (getAppActionRuntimeInputs().length) {\r\n <button\r\n type=\"button\"\r\n class=\"group flex w-full items-center justify-between gap-3 rounded-xl border border-surface-200 bg-surface-50 px-3 py-2.5 text-start transition-colors hover:bg-surface-100\"\r\n (click)=\"\r\n resolvedAutomaticallyOpen.set(\r\n !resolvedAutomaticallyOpen()\r\n )\r\n \"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionResolvedAutomatically\") }}\r\n <span\r\n class=\"ms-1 text-xs font-normal text-muted-color\"\r\n >\r\n ({{ getAppActionRuntimeInputs().length }})\r\n </span>\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionResolvedAutomaticallyHint\") }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 inline-flex items-center gap-1 text-xs font-medium text-primary\"\r\n >\r\n {{\r\n resolvedAutomaticallyOpen()\r\n ? t(\"hideDetails\")\r\n : t(\"showDetails\")\r\n }}\r\n <mt-icon\r\n [icon]=\"\r\n resolvedAutomaticallyOpen()\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n />\r\n </span>\r\n </button>\r\n @if (resolvedAutomaticallyOpen()) {\r\n <mt-card>\r\n <div class=\"space-y-2\">\r\n @for (\r\n input of getAppActionRuntimeInputs();\r\n track input.key\r\n ) {\r\n <div\r\n class=\"flex items-start justify-between gap-3 rounded-lg border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ input.key }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{\r\n describeRuntimeInputSource(input)\r\n }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 rounded-full bg-surface-200 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-surface-600\"\r\n >\r\n {{ t(\"appActionRuntime\") }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n\r\n @if (getAppActionOutputs().length) {\r\n <button\r\n type=\"button\"\r\n class=\"group flex w-full items-center justify-between gap-3 rounded-xl border border-surface-200 bg-surface-50 px-3 py-2.5 text-start transition-colors hover:bg-surface-100\"\r\n (click)=\"outputsOpen.set(!outputsOpen())\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionOutputs\") }}\r\n <span\r\n class=\"ms-1 text-xs font-normal text-muted-color\"\r\n >\r\n ({{ getAppActionOutputs().length }})\r\n </span>\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionOutputsHint\") }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 inline-flex items-center gap-1 text-xs font-medium text-primary\"\r\n >\r\n {{\r\n outputsOpen()\r\n ? t(\"hideDetails\")\r\n : t(\"showDetails\")\r\n }}\r\n <mt-icon\r\n [icon]=\"\r\n outputsOpen()\r\n ? 'arrow.chevron-up'\r\n : 'arrow.chevron-down'\r\n \"\r\n />\r\n </span>\r\n </button>\r\n @if (outputsOpen()) {\r\n <mt-card>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (\r\n output of getAppActionOutputs();\r\n track output.key\r\n ) {\r\n <span\r\n class=\"rounded-md bg-surface-100 px-2 py-0.5 text-xs font-mono text-surface-700\"\r\n [title]=\"output.description ?? ''\"\r\n >\r\n {{ output.key }}:{{ output.type }}\r\n </span>\r\n }\r\n </div>\r\n </mt-card>\r\n }\r\n }\r\n }\r\n </div>\r\n }\r\n @case (\"tab2\") {\r\n <div class=\"mt-4\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-4\">\r\n <div class=\"flex flex-1 items-center gap-3\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"file.file-check-02\"\r\n />\r\n <div class=\"flex flex-col\">\r\n <label class=\"font-medium\">{{\r\n t(\"configureForm\")\r\n }}</label>\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"configureForm-description\")\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"mt-3 flex gap-2\">\r\n <mt-button\r\n [label]=\"t('configureForm')\"\r\n size=\"small\"\r\n (onClick)=\"openFormModal()\"\r\n ></mt-button>\r\n <mt-button\r\n [label]=\"t('resetForm')\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n [loading]=\"isResettingForm()\"\r\n (onClick)=\"onResetForm()\"\r\n ></mt-button>\r\n </div>\r\n </mt-card>\r\n </div>\r\n }\r\n @case (\"tab3\") {\r\n <div class=\"mt-4\">\r\n <mt-toggle-field\r\n toggleShape=\"card\"\r\n [label]=\"t('show-hide')\"\r\n [descriptionCard]=\"t('show-hide-notifications')\"\r\n icon=\"general.eye\"\r\n [formControl]=\"showHideControl\"\r\n >\r\n <ng-template #toggleCardBottom>\r\n @if (showHideControl.value) {\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureNotifications')\"\r\n size=\"small\"\r\n (onClick)=\"openNotificationsModal()\"\r\n ></mt-button>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-toggle-field>\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n </mt-structure-builder>\r\n } @else {\r\n <p-skeleton width=\"100%\" height=\"50rem\" />\r\n }\r\n }\r\n @case (\"notification\") {\r\n <div class=\"flex-1 flex justify-center items-start p-4\">\r\n <div class=\"w-1/2 max-[1025px]:w-full\">\r\n <mt-card [title]=\"t('notifications')\" paddingless>\r\n <mt-notification-template />\r\n </mt-card>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n" }]
3109
3153
  }], ctorParameters: () => [] });
3110
3154
 
3111
3155
  // store/app.state.ts