@memberjunction/ng-user-routines 0.0.0 → 5.45.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/my-routines-list.component.d.ts +119 -0
- package/dist/lib/my-routines-list.component.d.ts.map +1 -0
- package/dist/lib/my-routines-list.component.js +574 -0
- package/dist/lib/my-routines-list.component.js.map +1 -0
- package/dist/lib/new-routine.component.d.ts +182 -0
- package/dist/lib/new-routine.component.d.ts.map +1 -0
- package/dist/lib/new-routine.component.js +1070 -0
- package/dist/lib/new-routine.component.js.map +1 -0
- package/dist/lib/routine-history.component.d.ts +65 -0
- package/dist/lib/routine-history.component.d.ts.map +1 -0
- package/dist/lib/routine-history.component.js +290 -0
- package/dist/lib/routine-history.component.js.map +1 -0
- package/dist/lib/routine-target-catalog.d.ts +48 -0
- package/dist/lib/routine-target-catalog.d.ts.map +1 -0
- package/dist/lib/routine-target-catalog.js +59 -0
- package/dist/lib/routine-target-catalog.js.map +1 -0
- package/dist/lib/routine-ui-helpers.d.ts +49 -0
- package/dist/lib/routine-ui-helpers.d.ts.map +1 -0
- package/dist/lib/routine-ui-helpers.js +174 -0
- package/dist/lib/routine-ui-helpers.js.map +1 -0
- package/dist/lib/user-routines-command-center.component.d.ts +88 -0
- package/dist/lib/user-routines-command-center.component.d.ts.map +1 -0
- package/dist/lib/user-routines-command-center.component.js +372 -0
- package/dist/lib/user-routines-command-center.component.js.map +1 -0
- package/dist/lib/user-routines-events.d.ts +88 -0
- package/dist/lib/user-routines-events.d.ts.map +1 -0
- package/dist/lib/user-routines-events.js +97 -0
- package/dist/lib/user-routines-events.js.map +1 -0
- package/dist/lib/user-routines-slide-in.component.d.ts +57 -0
- package/dist/lib/user-routines-slide-in.component.d.ts.map +1 -0
- package/dist/lib/user-routines-slide-in.component.js +170 -0
- package/dist/lib/user-routines-slide-in.component.js.map +1 -0
- package/dist/lib/user-routines.module.d.ts +37 -0
- package/dist/lib/user-routines.module.d.ts.map +1 -0
- package/dist/lib/user-routines.module.js +113 -0
- package/dist/lib/user-routines.module.js.map +1 -0
- package/dist/public-api.d.ts +10 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +19 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +49 -7
- package/README.md +0 -45
|
@@ -0,0 +1,1070 @@
|
|
|
1
|
+
import { ChangeDetectorRef, Component, EventEmitter, Input, Output, inject } from '@angular/core';
|
|
2
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
|
+
import { CompositeKey, RunView } from '@memberjunction/core';
|
|
4
|
+
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
5
|
+
import { UserRoutineEngine } from '@memberjunction/core-entities';
|
|
6
|
+
import { BuildCronExpression, CRON_DAY_NAMES, DescribeCronExpression, IsPlausibleCronExpression, NormalizeUUID, ParseCronExpression, } from '@memberjunction/global';
|
|
7
|
+
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
8
|
+
import { FromDateTimeLocal, GetLocalTimezone, GetTimezoneOptions, IsPlausibleEmail, ParseSkillIDs, SerializeSkillIDs, ToDateTimeLocal, ValidateOptionalJson, } from './routine-ui-helpers';
|
|
9
|
+
import { LoadRoutineTargetCatalog } from './routine-target-catalog';
|
|
10
|
+
import { AfterRoutineCreatedEventArgs, BeforeRoutineCreatedEventArgs } from './user-routines-events';
|
|
11
|
+
import * as i0 from "@angular/core";
|
|
12
|
+
import * as i1 from "@angular/forms";
|
|
13
|
+
import * as i2 from "@memberjunction/ng-ui-components";
|
|
14
|
+
import * as i3 from "@memberjunction/ng-shared-generic";
|
|
15
|
+
import * as i4 from "@memberjunction/ng-code-editor";
|
|
16
|
+
import * as i5 from "@memberjunction/ng-trees";
|
|
17
|
+
import * as i6 from "@memberjunction/ng-composer";
|
|
18
|
+
const _c0 = () => ["agent-mentions"];
|
|
19
|
+
const _forTrack0 = ($index, $item) => $item.Value;
|
|
20
|
+
const _forTrack1 = ($index, $item) => $item.ID;
|
|
21
|
+
function NewRoutineComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
22
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
23
|
+
i0.ɵɵelement(1, "mj-loading", 2);
|
|
24
|
+
i0.ɵɵelementEnd();
|
|
25
|
+
} }
|
|
26
|
+
function NewRoutineComponent_Conditional_1_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
27
|
+
i0.ɵɵelementStart(0, "li");
|
|
28
|
+
i0.ɵɵtext(1);
|
|
29
|
+
i0.ɵɵelementEnd();
|
|
30
|
+
} if (rf & 2) {
|
|
31
|
+
const error_r2 = ctx.$implicit;
|
|
32
|
+
i0.ɵɵadvance();
|
|
33
|
+
i0.ɵɵtextInterpolate(error_r2);
|
|
34
|
+
} }
|
|
35
|
+
function NewRoutineComponent_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
36
|
+
i0.ɵɵelementStart(0, "mj-alert", 3)(1, "ul", 28);
|
|
37
|
+
i0.ɵɵrepeaterCreate(2, NewRoutineComponent_Conditional_1_Conditional_1_For_3_Template, 2, 1, "li", null, i0.ɵɵrepeaterTrackByIdentity);
|
|
38
|
+
i0.ɵɵelementEnd()();
|
|
39
|
+
} if (rf & 2) {
|
|
40
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
41
|
+
i0.ɵɵadvance(2);
|
|
42
|
+
i0.ɵɵrepeater(ctx_r2.ValidationErrors);
|
|
43
|
+
} }
|
|
44
|
+
function NewRoutineComponent_Conditional_1_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
45
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
46
|
+
i0.ɵɵelementStart(0, "mj-tree-dropdown", 29);
|
|
47
|
+
i0.ɵɵlistener("AfterNodeSelect", function NewRoutineComponent_Conditional_1_Conditional_14_Template_mj_tree_dropdown_AfterNodeSelect_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OnAgentNodeSelected($event)); });
|
|
48
|
+
i0.ɵɵelementEnd();
|
|
49
|
+
} if (rf & 2) {
|
|
50
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
51
|
+
i0.ɵɵproperty("BranchConfig", ctx_r2.AgentTreeBranchConfig)("LeafConfig", ctx_r2.AgentTreeLeafConfig)("Value", ctx_r2.SelectedAgentKey)("Clearable", false);
|
|
52
|
+
} }
|
|
53
|
+
function NewRoutineComponent_Conditional_1_For_26_Template(rf, ctx) { if (rf & 1) {
|
|
54
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
55
|
+
i0.ɵɵelementStart(0, "button", 30);
|
|
56
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_For_26_Template_button_click_0_listener() { const option_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SetScheduleKind(option_r6.Value)); });
|
|
57
|
+
i0.ɵɵtext(1);
|
|
58
|
+
i0.ɵɵelementEnd();
|
|
59
|
+
} if (rf & 2) {
|
|
60
|
+
const option_r6 = ctx.$implicit;
|
|
61
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
62
|
+
i0.ɵɵclassProp("editor-segment--active", ctx_r2.ScheduleKind === option_r6.Value);
|
|
63
|
+
i0.ɵɵadvance();
|
|
64
|
+
i0.ɵɵtextInterpolate1(" ", option_r6.Label, " ");
|
|
65
|
+
} }
|
|
66
|
+
function NewRoutineComponent_Conditional_1_Case_28_Template(rf, ctx) { if (rf & 1) {
|
|
67
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
68
|
+
i0.ɵɵelementStart(0, "div", 17)(1, "label", 9);
|
|
69
|
+
i0.ɵɵtext(2, "At minute");
|
|
70
|
+
i0.ɵɵelementEnd();
|
|
71
|
+
i0.ɵɵelementStart(3, "mj-numeric-input", 31);
|
|
72
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Case_28_Template_mj_numeric_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.ScheduleMinute, $event) || (ctx_r2.ScheduleMinute = $event); return i0.ɵɵresetView($event); });
|
|
73
|
+
i0.ɵɵelementEnd();
|
|
74
|
+
i0.ɵɵelementStart(4, "span", 22);
|
|
75
|
+
i0.ɵɵtext(5, "past every hour");
|
|
76
|
+
i0.ɵɵelementEnd()();
|
|
77
|
+
} if (rf & 2) {
|
|
78
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
79
|
+
i0.ɵɵadvance(3);
|
|
80
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.ScheduleMinute);
|
|
81
|
+
i0.ɵɵproperty("Min", 0)("Max", 59)("Step", 5);
|
|
82
|
+
} }
|
|
83
|
+
function NewRoutineComponent_Conditional_1_Case_29_Template(rf, ctx) { if (rf & 1) {
|
|
84
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
85
|
+
i0.ɵɵelementStart(0, "div", 17)(1, "label", 9);
|
|
86
|
+
i0.ɵɵtext(2, "At");
|
|
87
|
+
i0.ɵɵelementEnd();
|
|
88
|
+
i0.ɵɵelementStart(3, "input", 32);
|
|
89
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Case_29_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.ScheduleTime, $event) || (ctx_r2.ScheduleTime = $event); return i0.ɵɵresetView($event); });
|
|
90
|
+
i0.ɵɵelementEnd();
|
|
91
|
+
i0.ɵɵelementStart(4, "span", 22);
|
|
92
|
+
i0.ɵɵtext(5, "every day");
|
|
93
|
+
i0.ɵɵelementEnd()();
|
|
94
|
+
} if (rf & 2) {
|
|
95
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
96
|
+
i0.ɵɵadvance(3);
|
|
97
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.ScheduleTime);
|
|
98
|
+
} }
|
|
99
|
+
function NewRoutineComponent_Conditional_1_Case_30_Template(rf, ctx) { if (rf & 1) {
|
|
100
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
101
|
+
i0.ɵɵelementStart(0, "div", 17)(1, "label", 9);
|
|
102
|
+
i0.ɵɵtext(2, "Every");
|
|
103
|
+
i0.ɵɵelementEnd();
|
|
104
|
+
i0.ɵɵelementStart(3, "mj-dropdown", 33);
|
|
105
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Case_30_Template_mj_dropdown_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.ScheduleDayOfWeek, $event) || (ctx_r2.ScheduleDayOfWeek = $event); return i0.ɵɵresetView($event); });
|
|
106
|
+
i0.ɵɵelementEnd();
|
|
107
|
+
i0.ɵɵelementStart(4, "label", 9);
|
|
108
|
+
i0.ɵɵtext(5, "at");
|
|
109
|
+
i0.ɵɵelementEnd();
|
|
110
|
+
i0.ɵɵelementStart(6, "input", 32);
|
|
111
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Case_30_Template_input_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.ScheduleTime, $event) || (ctx_r2.ScheduleTime = $event); return i0.ɵɵresetView($event); });
|
|
112
|
+
i0.ɵɵelementEnd()();
|
|
113
|
+
} if (rf & 2) {
|
|
114
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
115
|
+
i0.ɵɵadvance(3);
|
|
116
|
+
i0.ɵɵproperty("Data", ctx_r2.DayOfWeekOptions)("ValuePrimitive", true);
|
|
117
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.ScheduleDayOfWeek);
|
|
118
|
+
i0.ɵɵadvance(3);
|
|
119
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.ScheduleTime);
|
|
120
|
+
} }
|
|
121
|
+
function NewRoutineComponent_Conditional_1_Case_31_Template(rf, ctx) { if (rf & 1) {
|
|
122
|
+
const _r10 = i0.ɵɵgetCurrentView();
|
|
123
|
+
i0.ɵɵelementStart(0, "div", 17)(1, "label", 9);
|
|
124
|
+
i0.ɵɵtext(2, "On day");
|
|
125
|
+
i0.ɵɵelementEnd();
|
|
126
|
+
i0.ɵɵelementStart(3, "mj-dropdown", 33);
|
|
127
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Case_31_Template_mj_dropdown_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.ScheduleDayOfMonth, $event) || (ctx_r2.ScheduleDayOfMonth = $event); return i0.ɵɵresetView($event); });
|
|
128
|
+
i0.ɵɵelementEnd();
|
|
129
|
+
i0.ɵɵelementStart(4, "label", 9);
|
|
130
|
+
i0.ɵɵtext(5, "at");
|
|
131
|
+
i0.ɵɵelementEnd();
|
|
132
|
+
i0.ɵɵelementStart(6, "input", 32);
|
|
133
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Case_31_Template_input_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.ScheduleTime, $event) || (ctx_r2.ScheduleTime = $event); return i0.ɵɵresetView($event); });
|
|
134
|
+
i0.ɵɵelementEnd()();
|
|
135
|
+
} if (rf & 2) {
|
|
136
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
137
|
+
i0.ɵɵadvance(3);
|
|
138
|
+
i0.ɵɵproperty("Data", ctx_r2.DayOfMonthOptions)("ValuePrimitive", true);
|
|
139
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.ScheduleDayOfMonth);
|
|
140
|
+
i0.ɵɵadvance(3);
|
|
141
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.ScheduleTime);
|
|
142
|
+
} }
|
|
143
|
+
function NewRoutineComponent_Conditional_1_Case_32_Template(rf, ctx) { if (rf & 1) {
|
|
144
|
+
const _r11 = i0.ɵɵgetCurrentView();
|
|
145
|
+
i0.ɵɵelementStart(0, "div", 5)(1, "label", 34);
|
|
146
|
+
i0.ɵɵtext(2, "Cron expression");
|
|
147
|
+
i0.ɵɵelementEnd();
|
|
148
|
+
i0.ɵɵelementStart(3, "input", 35);
|
|
149
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Case_32_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.RawCron, $event) || (ctx_r2.RawCron = $event); return i0.ɵɵresetView($event); });
|
|
150
|
+
i0.ɵɵelementEnd()();
|
|
151
|
+
} if (rf & 2) {
|
|
152
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
153
|
+
i0.ɵɵadvance(3);
|
|
154
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.RawCron);
|
|
155
|
+
} }
|
|
156
|
+
function NewRoutineComponent_Conditional_1_Conditional_41_Conditional_40_For_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
157
|
+
i0.ɵɵelement(0, "i", 63);
|
|
158
|
+
} }
|
|
159
|
+
function NewRoutineComponent_Conditional_1_Conditional_41_Conditional_40_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
160
|
+
const _r13 = i0.ɵɵgetCurrentView();
|
|
161
|
+
i0.ɵɵelementStart(0, "button", 62);
|
|
162
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Conditional_41_Conditional_40_For_5_Template_button_click_0_listener() { const skill_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.ToggleSkill(skill_r14.ID)); });
|
|
163
|
+
i0.ɵɵelement(1, "i");
|
|
164
|
+
i0.ɵɵtext(2);
|
|
165
|
+
i0.ɵɵconditionalCreate(3, NewRoutineComponent_Conditional_1_Conditional_41_Conditional_40_For_5_Conditional_3_Template, 1, 0, "i", 63);
|
|
166
|
+
i0.ɵɵelementEnd();
|
|
167
|
+
} if (rf & 2) {
|
|
168
|
+
const skill_r14 = ctx.$implicit;
|
|
169
|
+
const ctx_r2 = i0.ɵɵnextContext(4);
|
|
170
|
+
i0.ɵɵclassProp("editor-skill-chip--selected", ctx_r2.IsSkillSelected(skill_r14.ID));
|
|
171
|
+
i0.ɵɵproperty("title", skill_r14.Description ?? skill_r14.Name);
|
|
172
|
+
i0.ɵɵadvance();
|
|
173
|
+
i0.ɵɵclassMap(skill_r14.IconClass || "fa-solid fa-wand-magic-sparkles");
|
|
174
|
+
i0.ɵɵadvance();
|
|
175
|
+
i0.ɵɵtextInterpolate1(" ", skill_r14.Name, " ");
|
|
176
|
+
i0.ɵɵadvance();
|
|
177
|
+
i0.ɵɵconditional(ctx_r2.IsSkillSelected(skill_r14.ID) ? 3 : -1);
|
|
178
|
+
} }
|
|
179
|
+
function NewRoutineComponent_Conditional_1_Conditional_41_Conditional_40_Template(rf, ctx) { if (rf & 1) {
|
|
180
|
+
i0.ɵɵelementStart(0, "div", 5)(1, "label", 9);
|
|
181
|
+
i0.ɵɵtext(2, "Pre-activate skills (optional)");
|
|
182
|
+
i0.ɵɵelementEnd();
|
|
183
|
+
i0.ɵɵelementStart(3, "div", 60);
|
|
184
|
+
i0.ɵɵrepeaterCreate(4, NewRoutineComponent_Conditional_1_Conditional_41_Conditional_40_For_5_Template, 4, 7, "button", 61, _forTrack1);
|
|
185
|
+
i0.ɵɵelementEnd();
|
|
186
|
+
i0.ɵɵelementStart(6, "div", 11);
|
|
187
|
+
i0.ɵɵtext(7, "Selected skills start every run with their instructions and tools in effect (subject to the agent's skill gates).");
|
|
188
|
+
i0.ɵɵelementEnd()();
|
|
189
|
+
} if (rf & 2) {
|
|
190
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
191
|
+
i0.ɵɵadvance(4);
|
|
192
|
+
i0.ɵɵrepeater(ctx_r2.SkillOptions);
|
|
193
|
+
} }
|
|
194
|
+
function NewRoutineComponent_Conditional_1_Conditional_41_Conditional_59_Template(rf, ctx) { if (rf & 1) {
|
|
195
|
+
i0.ɵɵelementStart(0, "div", 11);
|
|
196
|
+
i0.ɵɵtext(1, "Only you (the owner) will be notified.");
|
|
197
|
+
i0.ɵɵelementEnd();
|
|
198
|
+
} }
|
|
199
|
+
function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
200
|
+
const _r18 = i0.ɵɵgetCurrentView();
|
|
201
|
+
i0.ɵɵelementStart(0, "mj-combobox", 75);
|
|
202
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Conditional_7_Template_mj_combobox_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r18); const row_r17 = i0.ɵɵnextContext().$implicit; i0.ɵɵtwoWayBindingSet(row_r17.UserID, $event) || (row_r17.UserID = $event); return i0.ɵɵresetView($event); });
|
|
203
|
+
i0.ɵɵelementEnd();
|
|
204
|
+
} if (rf & 2) {
|
|
205
|
+
const row_r17 = i0.ɵɵnextContext().$implicit;
|
|
206
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
207
|
+
i0.ɵɵproperty("Data", ctx_r2.UserOptions)("ValuePrimitive", true);
|
|
208
|
+
i0.ɵɵtwoWayProperty("ngModel", row_r17.UserID);
|
|
209
|
+
} }
|
|
210
|
+
function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
211
|
+
const _r19 = i0.ɵɵgetCurrentView();
|
|
212
|
+
i0.ɵɵelementStart(0, "input", 76);
|
|
213
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Conditional_8_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r19); const row_r17 = i0.ɵɵnextContext().$implicit; i0.ɵɵtwoWayBindingSet(row_r17.Email, $event) || (row_r17.Email = $event); return i0.ɵɵresetView($event); });
|
|
214
|
+
i0.ɵɵelementEnd();
|
|
215
|
+
} if (rf & 2) {
|
|
216
|
+
const row_r17 = i0.ɵɵnextContext().$implicit;
|
|
217
|
+
i0.ɵɵtwoWayProperty("ngModel", row_r17.Email);
|
|
218
|
+
} }
|
|
219
|
+
function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Template(rf, ctx) { if (rf & 1) {
|
|
220
|
+
const _r15 = i0.ɵɵgetCurrentView();
|
|
221
|
+
i0.ɵɵelementStart(0, "div", 59)(1, "div", 64)(2, "button", 65);
|
|
222
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Template_button_click_2_listener() { const ɵ$index_259_r16 = i0.ɵɵrestoreView(_r15).$index; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.MoveRecipient(ɵ$index_259_r16, -1)); });
|
|
223
|
+
i0.ɵɵelement(3, "i", 66);
|
|
224
|
+
i0.ɵɵelementEnd();
|
|
225
|
+
i0.ɵɵelementStart(4, "button", 67);
|
|
226
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Template_button_click_4_listener() { const ɵ$index_259_r16 = i0.ɵɵrestoreView(_r15).$index; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.MoveRecipient(ɵ$index_259_r16, 1)); });
|
|
227
|
+
i0.ɵɵelement(5, "i", 68);
|
|
228
|
+
i0.ɵɵelementEnd()();
|
|
229
|
+
i0.ɵɵelementStart(6, "mj-dropdown", 69);
|
|
230
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Template_mj_dropdown_ngModelChange_6_listener($event) { const row_r17 = i0.ɵɵrestoreView(_r15).$implicit; i0.ɵɵtwoWayBindingSet(row_r17.Mode, $event) || (row_r17.Mode = $event); return i0.ɵɵresetView($event); });
|
|
231
|
+
i0.ɵɵlistener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Template_mj_dropdown_ngModelChange_6_listener() { const row_r17 = i0.ɵɵrestoreView(_r15).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.OnRecipientModeChange(row_r17)); });
|
|
232
|
+
i0.ɵɵelementEnd();
|
|
233
|
+
i0.ɵɵconditionalCreate(7, NewRoutineComponent_Conditional_1_Conditional_41_For_61_Conditional_7_Template, 1, 3, "mj-combobox", 70)(8, NewRoutineComponent_Conditional_1_Conditional_41_For_61_Conditional_8_Template, 1, 1, "input", 71);
|
|
234
|
+
i0.ɵɵelementStart(9, "mj-dropdown", 72);
|
|
235
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Template_mj_dropdown_ngModelChange_9_listener($event) { const row_r17 = i0.ɵɵrestoreView(_r15).$implicit; i0.ɵɵtwoWayBindingSet(row_r17.Channel, $event) || (row_r17.Channel = $event); return i0.ɵɵresetView($event); });
|
|
236
|
+
i0.ɵɵelementEnd();
|
|
237
|
+
i0.ɵɵelementStart(10, "button", 73);
|
|
238
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Conditional_41_For_61_Template_button_click_10_listener() { const ɵ$index_259_r16 = i0.ɵɵrestoreView(_r15).$index; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.RemoveRecipient(ɵ$index_259_r16)); });
|
|
239
|
+
i0.ɵɵelement(11, "i", 74);
|
|
240
|
+
i0.ɵɵelementEnd()();
|
|
241
|
+
} if (rf & 2) {
|
|
242
|
+
const row_r17 = ctx.$implicit;
|
|
243
|
+
const ɵ$index_259_r16 = ctx.$index;
|
|
244
|
+
const ɵ$count_259_r20 = ctx.$count;
|
|
245
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
246
|
+
i0.ɵɵadvance(2);
|
|
247
|
+
i0.ɵɵproperty("disabled", ɵ$index_259_r16 === 0);
|
|
248
|
+
i0.ɵɵadvance(2);
|
|
249
|
+
i0.ɵɵproperty("disabled", ɵ$index_259_r16 === ɵ$count_259_r20 - 1);
|
|
250
|
+
i0.ɵɵadvance(2);
|
|
251
|
+
i0.ɵɵproperty("Data", ctx_r2.RecipientModeOptions)("ValuePrimitive", true);
|
|
252
|
+
i0.ɵɵtwoWayProperty("ngModel", row_r17.Mode);
|
|
253
|
+
i0.ɵɵadvance();
|
|
254
|
+
i0.ɵɵconditional(row_r17.Mode === "user" ? 7 : 8);
|
|
255
|
+
i0.ɵɵadvance(2);
|
|
256
|
+
i0.ɵɵproperty("Data", ctx_r2.ChannelOptions)("ValuePrimitive", true);
|
|
257
|
+
i0.ɵɵtwoWayProperty("ngModel", row_r17.Channel);
|
|
258
|
+
} }
|
|
259
|
+
function NewRoutineComponent_Conditional_1_Conditional_41_Template(rf, ctx) { if (rf & 1) {
|
|
260
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
261
|
+
i0.ɵɵelementStart(0, "section", 4)(1, "h3", 36);
|
|
262
|
+
i0.ɵɵelement(2, "i", 37);
|
|
263
|
+
i0.ɵɵtext(3, " Details");
|
|
264
|
+
i0.ɵɵelementEnd();
|
|
265
|
+
i0.ɵɵelementStart(4, "div", 5)(5, "label", 38);
|
|
266
|
+
i0.ɵɵtext(6, "Description");
|
|
267
|
+
i0.ɵɵelementEnd();
|
|
268
|
+
i0.ɵɵelementStart(7, "textarea", 39);
|
|
269
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_Template_textarea_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.Description, $event) || (ctx_r2.Description = $event); return i0.ɵɵresetView($event); });
|
|
270
|
+
i0.ɵɵelementEnd()();
|
|
271
|
+
i0.ɵɵelementStart(8, "div", 5)(9, "label", 9);
|
|
272
|
+
i0.ɵɵtext(10, "Routine type");
|
|
273
|
+
i0.ɵɵelementEnd();
|
|
274
|
+
i0.ɵɵelementStart(11, "div", 40)(12, "button", 30);
|
|
275
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Conditional_41_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.RoutineType = "Scheduled"); });
|
|
276
|
+
i0.ɵɵelement(13, "i", 41);
|
|
277
|
+
i0.ɵɵtext(14, " Scheduled ");
|
|
278
|
+
i0.ɵɵelementEnd();
|
|
279
|
+
i0.ɵɵelementStart(15, "button", 30);
|
|
280
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Conditional_41_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.RoutineType = "Monitoring"); });
|
|
281
|
+
i0.ɵɵelement(16, "i", 42);
|
|
282
|
+
i0.ɵɵtext(17, " Monitoring ");
|
|
283
|
+
i0.ɵɵelementEnd()();
|
|
284
|
+
i0.ɵɵelementStart(18, "div", 11);
|
|
285
|
+
i0.ɵɵtext(19);
|
|
286
|
+
i0.ɵɵelementEnd()();
|
|
287
|
+
i0.ɵɵelementStart(20, "div", 5)(21, "label", 9);
|
|
288
|
+
i0.ɵɵtext(22, "Timezone");
|
|
289
|
+
i0.ɵɵelementEnd();
|
|
290
|
+
i0.ɵɵelementStart(23, "mj-combobox", 43);
|
|
291
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_Template_mj_combobox_ngModelChange_23_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.Timezone, $event) || (ctx_r2.Timezone = $event); return i0.ɵɵresetView($event); });
|
|
292
|
+
i0.ɵɵelementEnd()();
|
|
293
|
+
i0.ɵɵelementStart(24, "div", 44)(25, "div", 5)(26, "label", 45);
|
|
294
|
+
i0.ɵɵtext(27, "Active from (optional)");
|
|
295
|
+
i0.ɵɵelementEnd();
|
|
296
|
+
i0.ɵɵelementStart(28, "input", 46);
|
|
297
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_Template_input_ngModelChange_28_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.StartAtLocal, $event) || (ctx_r2.StartAtLocal = $event); return i0.ɵɵresetView($event); });
|
|
298
|
+
i0.ɵɵelementEnd()();
|
|
299
|
+
i0.ɵɵelementStart(29, "div", 5)(30, "label", 47);
|
|
300
|
+
i0.ɵɵtext(31, "Active until (optional)");
|
|
301
|
+
i0.ɵɵelementEnd();
|
|
302
|
+
i0.ɵɵelementStart(32, "input", 48);
|
|
303
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_Template_input_ngModelChange_32_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.EndAtLocal, $event) || (ctx_r2.EndAtLocal = $event); return i0.ɵɵresetView($event); });
|
|
304
|
+
i0.ɵɵelementEnd()()();
|
|
305
|
+
i0.ɵɵelementStart(33, "div", 5)(34, "label", 9);
|
|
306
|
+
i0.ɵɵtext(35, "Starting payload (JSON, optional)");
|
|
307
|
+
i0.ɵɵelementEnd();
|
|
308
|
+
i0.ɵɵelementStart(36, "div", 49)(37, "mj-code-editor", 50);
|
|
309
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_Template_mj_code_editor_ngModelChange_37_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.StartingPayloadText, $event) || (ctx_r2.StartingPayloadText = $event); return i0.ɵɵresetView($event); });
|
|
310
|
+
i0.ɵɵelementEnd()();
|
|
311
|
+
i0.ɵɵelementStart(38, "div", 11);
|
|
312
|
+
i0.ɵɵtext(39, "Passed to the agent on each run. Leave blank for none.");
|
|
313
|
+
i0.ɵɵelementEnd()();
|
|
314
|
+
i0.ɵɵconditionalCreate(40, NewRoutineComponent_Conditional_1_Conditional_41_Conditional_40_Template, 8, 0, "div", 5);
|
|
315
|
+
i0.ɵɵelementEnd();
|
|
316
|
+
i0.ɵɵelementStart(41, "section", 4)(42, "h3", 36);
|
|
317
|
+
i0.ɵɵelement(43, "i", 51);
|
|
318
|
+
i0.ɵɵtext(44, " Notifications");
|
|
319
|
+
i0.ɵɵelementEnd();
|
|
320
|
+
i0.ɵɵelementStart(45, "div", 5)(46, "label", 9);
|
|
321
|
+
i0.ɵɵtext(47, "Notify me");
|
|
322
|
+
i0.ɵɵelementEnd();
|
|
323
|
+
i0.ɵɵelementStart(48, "mj-dropdown", 52);
|
|
324
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_Template_mj_dropdown_ngModelChange_48_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.NotifyCondition, $event) || (ctx_r2.NotifyCondition = $event); return i0.ɵɵresetView($event); });
|
|
325
|
+
i0.ɵɵelementEnd()();
|
|
326
|
+
i0.ɵɵelementStart(49, "div", 53)(50, "mj-switch", 54);
|
|
327
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_Template_mj_switch_ngModelChange_50_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.NotifyViaInApp, $event) || (ctx_r2.NotifyViaInApp = $event); return i0.ɵɵresetView($event); });
|
|
328
|
+
i0.ɵɵelementEnd();
|
|
329
|
+
i0.ɵɵelementStart(51, "mj-switch", 55);
|
|
330
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Conditional_41_Template_mj_switch_ngModelChange_51_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.NotifyViaEmail, $event) || (ctx_r2.NotifyViaEmail = $event); return i0.ɵɵresetView($event); });
|
|
331
|
+
i0.ɵɵelementEnd()();
|
|
332
|
+
i0.ɵɵelementStart(52, "div", 5)(53, "div", 56)(54, "label", 9);
|
|
333
|
+
i0.ɵɵtext(55, "Additional recipients");
|
|
334
|
+
i0.ɵɵelementEnd();
|
|
335
|
+
i0.ɵɵelementStart(56, "button", 57);
|
|
336
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Conditional_41_Template_button_click_56_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.AddRecipient()); });
|
|
337
|
+
i0.ɵɵelement(57, "i", 58);
|
|
338
|
+
i0.ɵɵtext(58, " Add recipient ");
|
|
339
|
+
i0.ɵɵelementEnd()();
|
|
340
|
+
i0.ɵɵconditionalCreate(59, NewRoutineComponent_Conditional_1_Conditional_41_Conditional_59_Template, 2, 0, "div", 11);
|
|
341
|
+
i0.ɵɵrepeaterCreate(60, NewRoutineComponent_Conditional_1_Conditional_41_For_61_Template, 12, 9, "div", 59, i0.ɵɵrepeaterTrackByIndex);
|
|
342
|
+
i0.ɵɵelementEnd()();
|
|
343
|
+
} if (rf & 2) {
|
|
344
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
345
|
+
i0.ɵɵadvance(7);
|
|
346
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.Description);
|
|
347
|
+
i0.ɵɵadvance(5);
|
|
348
|
+
i0.ɵɵclassProp("editor-segment--active", ctx_r2.RoutineType === "Scheduled");
|
|
349
|
+
i0.ɵɵadvance(3);
|
|
350
|
+
i0.ɵɵclassProp("editor-segment--active", ctx_r2.RoutineType === "Monitoring");
|
|
351
|
+
i0.ɵɵadvance(4);
|
|
352
|
+
i0.ɵɵtextInterpolate(ctx_r2.RoutineTypeHelp);
|
|
353
|
+
i0.ɵɵadvance(4);
|
|
354
|
+
i0.ɵɵproperty("Data", ctx_r2.TimezoneOptions)("ValuePrimitive", true);
|
|
355
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.Timezone);
|
|
356
|
+
i0.ɵɵadvance(5);
|
|
357
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.StartAtLocal);
|
|
358
|
+
i0.ɵɵadvance(4);
|
|
359
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.EndAtLocal);
|
|
360
|
+
i0.ɵɵadvance(5);
|
|
361
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.StartingPayloadText);
|
|
362
|
+
i0.ɵɵadvance(3);
|
|
363
|
+
i0.ɵɵconditional(ctx_r2.SkillOptions.length > 0 ? 40 : -1);
|
|
364
|
+
i0.ɵɵadvance(8);
|
|
365
|
+
i0.ɵɵproperty("Data", ctx_r2.NotifyConditionOptions)("ValuePrimitive", true);
|
|
366
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.NotifyCondition);
|
|
367
|
+
i0.ɵɵadvance(2);
|
|
368
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.NotifyViaInApp);
|
|
369
|
+
i0.ɵɵadvance();
|
|
370
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.NotifyViaEmail);
|
|
371
|
+
i0.ɵɵadvance(8);
|
|
372
|
+
i0.ɵɵconditional(ctx_r2.Recipients.length === 0 ? 59 : -1);
|
|
373
|
+
i0.ɵɵadvance();
|
|
374
|
+
i0.ɵɵrepeater(ctx_r2.Recipients);
|
|
375
|
+
} }
|
|
376
|
+
function NewRoutineComponent_Conditional_1_Conditional_44_Template(rf, ctx) { if (rf & 1) {
|
|
377
|
+
i0.ɵɵelement(0, "i", 25);
|
|
378
|
+
} }
|
|
379
|
+
function NewRoutineComponent_Conditional_1_Conditional_45_Template(rf, ctx) { if (rf & 1) {
|
|
380
|
+
i0.ɵɵelement(0, "i", 26);
|
|
381
|
+
} }
|
|
382
|
+
function NewRoutineComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
383
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
384
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
385
|
+
i0.ɵɵconditionalCreate(1, NewRoutineComponent_Conditional_1_Conditional_1_Template, 4, 0, "mj-alert", 3);
|
|
386
|
+
i0.ɵɵelementStart(2, "section", 4)(3, "div", 5)(4, "label", 6);
|
|
387
|
+
i0.ɵɵtext(5, "Name ");
|
|
388
|
+
i0.ɵɵelementStart(6, "span", 7);
|
|
389
|
+
i0.ɵɵtext(7, "*");
|
|
390
|
+
i0.ɵɵelementEnd()();
|
|
391
|
+
i0.ɵɵelementStart(8, "input", 8);
|
|
392
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Template_input_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.Name, $event) || (ctx_r2.Name = $event); return i0.ɵɵresetView($event); });
|
|
393
|
+
i0.ɵɵelementEnd()();
|
|
394
|
+
i0.ɵɵelementStart(9, "div", 5)(10, "label", 9);
|
|
395
|
+
i0.ɵɵtext(11, "Which agent should this routine run? ");
|
|
396
|
+
i0.ɵɵelementStart(12, "span", 7);
|
|
397
|
+
i0.ɵɵtext(13, "*");
|
|
398
|
+
i0.ɵɵelementEnd()();
|
|
399
|
+
i0.ɵɵconditionalCreate(14, NewRoutineComponent_Conditional_1_Conditional_14_Template, 1, 4, "mj-tree-dropdown", 10);
|
|
400
|
+
i0.ɵɵelementStart(15, "div", 11);
|
|
401
|
+
i0.ɵɵtext(16, "Active agents only, grouped by category \u2014 realtime (voice) agents are interactive-only and can't be scheduled.");
|
|
402
|
+
i0.ɵɵelementEnd()();
|
|
403
|
+
i0.ɵɵelementStart(17, "div", 5)(18, "label", 12);
|
|
404
|
+
i0.ɵɵtext(19, "Message sent on each run");
|
|
405
|
+
i0.ɵɵelementEnd();
|
|
406
|
+
i0.ɵɵelementStart(20, "mj-mention-editor", 13);
|
|
407
|
+
i0.ɵɵtwoWayListener("ngModelChange", function NewRoutineComponent_Conditional_1_Template_mj_mention_editor_ngModelChange_20_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.InitialMessage, $event) || (ctx_r2.InitialMessage = $event); return i0.ɵɵresetView($event); });
|
|
408
|
+
i0.ɵɵelementEnd()();
|
|
409
|
+
i0.ɵɵelementStart(21, "div", 5)(22, "label", 9);
|
|
410
|
+
i0.ɵɵtext(23, "Frequency");
|
|
411
|
+
i0.ɵɵelementEnd();
|
|
412
|
+
i0.ɵɵelementStart(24, "div", 14);
|
|
413
|
+
i0.ɵɵrepeaterCreate(25, NewRoutineComponent_Conditional_1_For_26_Template, 2, 3, "button", 15, _forTrack0);
|
|
414
|
+
i0.ɵɵelementEnd()();
|
|
415
|
+
i0.ɵɵelementStart(27, "div", 16);
|
|
416
|
+
i0.ɵɵconditionalCreate(28, NewRoutineComponent_Conditional_1_Case_28_Template, 6, 4, "div", 17)(29, NewRoutineComponent_Conditional_1_Case_29_Template, 6, 1, "div", 17)(30, NewRoutineComponent_Conditional_1_Case_30_Template, 7, 4, "div", 17)(31, NewRoutineComponent_Conditional_1_Case_31_Template, 7, 4, "div", 17)(32, NewRoutineComponent_Conditional_1_Case_32_Template, 4, 1, "div", 5);
|
|
417
|
+
i0.ɵɵelementStart(33, "div", 18);
|
|
418
|
+
i0.ɵɵelement(34, "i", 19);
|
|
419
|
+
i0.ɵɵtext(35);
|
|
420
|
+
i0.ɵɵelementEnd()()();
|
|
421
|
+
i0.ɵɵelementStart(36, "button", 20);
|
|
422
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Template_button_click_36_listener() { i0.ɵɵrestoreView(_r1); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.ShowAdvanced = !ctx_r2.ShowAdvanced); });
|
|
423
|
+
i0.ɵɵelement(37, "i", 21);
|
|
424
|
+
i0.ɵɵtext(38, " Advanced options ");
|
|
425
|
+
i0.ɵɵelementStart(39, "span", 22);
|
|
426
|
+
i0.ɵɵtext(40, "description \u00B7 monitoring \u00B7 timezone \u00B7 window \u00B7 payload \u00B7 skills \u00B7 notifications");
|
|
427
|
+
i0.ɵɵelementEnd()();
|
|
428
|
+
i0.ɵɵconditionalCreate(41, NewRoutineComponent_Conditional_1_Conditional_41_Template, 62, 19);
|
|
429
|
+
i0.ɵɵelementStart(42, "div", 23)(43, "button", 24);
|
|
430
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Template_button_click_43_listener() { i0.ɵɵrestoreView(_r1); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.Save()); });
|
|
431
|
+
i0.ɵɵconditionalCreate(44, NewRoutineComponent_Conditional_1_Conditional_44_Template, 1, 0, "i", 25)(45, NewRoutineComponent_Conditional_1_Conditional_45_Template, 1, 0, "i", 26);
|
|
432
|
+
i0.ɵɵtext(46);
|
|
433
|
+
i0.ɵɵelementEnd();
|
|
434
|
+
i0.ɵɵelementStart(47, "button", 27);
|
|
435
|
+
i0.ɵɵlistener("click", function NewRoutineComponent_Conditional_1_Template_button_click_47_listener() { i0.ɵɵrestoreView(_r1); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.Cancel()); });
|
|
436
|
+
i0.ɵɵtext(48, "Cancel");
|
|
437
|
+
i0.ɵɵelementEnd()()();
|
|
438
|
+
} if (rf & 2) {
|
|
439
|
+
let tmp_11_0;
|
|
440
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
441
|
+
i0.ɵɵadvance();
|
|
442
|
+
i0.ɵɵconditional(ctx_r2.ValidationErrors.length > 0 ? 1 : -1);
|
|
443
|
+
i0.ɵɵadvance(7);
|
|
444
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.Name);
|
|
445
|
+
i0.ɵɵadvance(6);
|
|
446
|
+
i0.ɵɵconditional(ctx_r2.AgentTreeLeafConfig ? 14 : -1);
|
|
447
|
+
i0.ɵɵadvance(6);
|
|
448
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.InitialMessage);
|
|
449
|
+
i0.ɵɵproperty("ExcludedTriggerKeys", i0.ɵɵpureFunction0(21, _c0))("Provider", ctx_r2.Provider)("enableAttachments", false)("autoFocus", false)("currentUser", ctx_r2.ProviderToUse.CurrentUser);
|
|
450
|
+
i0.ɵɵadvance(5);
|
|
451
|
+
i0.ɵɵrepeater(ctx_r2.ScheduleKindOptions);
|
|
452
|
+
i0.ɵɵadvance(3);
|
|
453
|
+
i0.ɵɵconditional((tmp_11_0 = ctx_r2.ScheduleKind) === "hourly" ? 28 : tmp_11_0 === "daily" ? 29 : tmp_11_0 === "weekly" ? 30 : tmp_11_0 === "monthly" ? 31 : tmp_11_0 === "advanced" ? 32 : -1);
|
|
454
|
+
i0.ɵɵadvance(7);
|
|
455
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.SchedulePreview || "No schedule yet", " ");
|
|
456
|
+
i0.ɵɵadvance();
|
|
457
|
+
i0.ɵɵattribute("aria-expanded", ctx_r2.ShowAdvanced);
|
|
458
|
+
i0.ɵɵadvance();
|
|
459
|
+
i0.ɵɵclassProp("fa-chevron-right", !ctx_r2.ShowAdvanced)("fa-chevron-down", ctx_r2.ShowAdvanced);
|
|
460
|
+
i0.ɵɵadvance(4);
|
|
461
|
+
i0.ɵɵconditional(ctx_r2.ShowAdvanced ? 41 : -1);
|
|
462
|
+
i0.ɵɵadvance(2);
|
|
463
|
+
i0.ɵɵproperty("disabled", ctx_r2.IsSaving);
|
|
464
|
+
i0.ɵɵadvance();
|
|
465
|
+
i0.ɵɵconditional(ctx_r2.IsSaving ? 44 : 45);
|
|
466
|
+
i0.ɵɵadvance(2);
|
|
467
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.IsEdit ? "Save Changes" : "Create Routine", " ");
|
|
468
|
+
i0.ɵɵadvance();
|
|
469
|
+
i0.ɵɵproperty("disabled", ctx_r2.IsSaving);
|
|
470
|
+
} }
|
|
471
|
+
/**
|
|
472
|
+
* Create/edit form for a User Routine. Routines run an AI AGENT on a schedule
|
|
473
|
+
* (TargetType is implicitly 'Agent') — the agent is chosen from a categorical tree
|
|
474
|
+
* grouped by Agent Category, showing each agent's own IconClass, with Realtime-type
|
|
475
|
+
* agents excluded (interactive-only). Also covers the initial message, optional JSON
|
|
476
|
+
* payload, AI Skills pre-activation, cron presets + advanced escape hatch, IANA
|
|
477
|
+
* timezone, activation window, notification settings, and the ordered recipients list.
|
|
478
|
+
*
|
|
479
|
+
* Reusable (Generic) component: no Router, no page chrome. The host mounts it
|
|
480
|
+
* (slide-in / dialog / inline), passes `RoutineID` (null = create), and reacts to
|
|
481
|
+
* `Saved` / `Cancelled` plus the cancelable `BeforeRoutineCreated` /
|
|
482
|
+
* `AfterRoutineCreated` pair for new routines. All persistence flows through MJ
|
|
483
|
+
* entity objects with explicit `Save()` boolean checks; failures surface
|
|
484
|
+
* `LatestResult.CompleteMessage`. Cached routine/recipient data comes from
|
|
485
|
+
* {@link UserRoutineEngine}.
|
|
486
|
+
*/
|
|
487
|
+
export class NewRoutineComponent extends BaseAngularComponent {
|
|
488
|
+
cdr = inject(ChangeDetectorRef);
|
|
489
|
+
notifications = inject(MJNotificationService);
|
|
490
|
+
// ---------------------------------------------------------------
|
|
491
|
+
// Inputs / Outputs
|
|
492
|
+
// ---------------------------------------------------------------
|
|
493
|
+
_routineID = null;
|
|
494
|
+
/** ID of the routine to edit, or null to create a new one. */
|
|
495
|
+
set RoutineID(value) {
|
|
496
|
+
if (value !== this._routineID) {
|
|
497
|
+
this._routineID = value;
|
|
498
|
+
if (this.initialized) {
|
|
499
|
+
void this.reload();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
get RoutineID() {
|
|
504
|
+
return this._routineID;
|
|
505
|
+
}
|
|
506
|
+
/** Emitted after a successful save (routine + recipients persisted) — create AND edit. */
|
|
507
|
+
Saved = new EventEmitter();
|
|
508
|
+
/** Emitted when the user cancels without saving. */
|
|
509
|
+
Cancelled = new EventEmitter();
|
|
510
|
+
/** Cancelable: fires before a NEW routine is saved for the first time. */
|
|
511
|
+
BeforeRoutineCreated = new EventEmitter();
|
|
512
|
+
/** Informational: fires after a new routine (and its recipients) was persisted. */
|
|
513
|
+
AfterRoutineCreated = new EventEmitter();
|
|
514
|
+
// ---------------------------------------------------------------
|
|
515
|
+
// Form state
|
|
516
|
+
// ---------------------------------------------------------------
|
|
517
|
+
Name = '';
|
|
518
|
+
Description = '';
|
|
519
|
+
/** The selected agent's ID (TargetType is implicitly 'Agent'). */
|
|
520
|
+
TargetID = null;
|
|
521
|
+
InitialMessage = '';
|
|
522
|
+
StartingPayloadText = '';
|
|
523
|
+
SelectedSkillIDs = [];
|
|
524
|
+
RoutineType = 'Scheduled';
|
|
525
|
+
ScheduleKind = 'daily';
|
|
526
|
+
/** Minute past each hour for the hourly preset. */
|
|
527
|
+
ScheduleMinute = 0;
|
|
528
|
+
/** "HH:MM" run time for daily/weekly/monthly presets. */
|
|
529
|
+
ScheduleTime = '09:00';
|
|
530
|
+
ScheduleDayOfWeek = 1;
|
|
531
|
+
ScheduleDayOfMonth = 1;
|
|
532
|
+
RawCron = '';
|
|
533
|
+
Timezone = GetLocalTimezone();
|
|
534
|
+
StartAtLocal = '';
|
|
535
|
+
EndAtLocal = '';
|
|
536
|
+
NotifyCondition = 'Always';
|
|
537
|
+
NotifyViaInApp = true;
|
|
538
|
+
NotifyViaEmail = false;
|
|
539
|
+
Recipients = [];
|
|
540
|
+
// ---------------------------------------------------------------
|
|
541
|
+
// Options / status
|
|
542
|
+
// ---------------------------------------------------------------
|
|
543
|
+
/**
|
|
544
|
+
* Progressive disclosure: the basic view (name / agent / message / frequency)
|
|
545
|
+
* covers the 80% path; everything else lives behind this toggle. Auto-expands
|
|
546
|
+
* when editing a routine that already uses advanced settings.
|
|
547
|
+
*/
|
|
548
|
+
ShowAdvanced = false;
|
|
549
|
+
Catalog = null;
|
|
550
|
+
UserOptions = [];
|
|
551
|
+
TimezoneOptions = GetTimezoneOptions();
|
|
552
|
+
IsLoading = true;
|
|
553
|
+
IsSaving = false;
|
|
554
|
+
ValidationErrors = [];
|
|
555
|
+
/** Tree config for the agent-category branches. */
|
|
556
|
+
AgentTreeBranchConfig = {
|
|
557
|
+
EntityName: 'MJ: AI Agent Categories',
|
|
558
|
+
DisplayField: 'Name',
|
|
559
|
+
ParentIDField: 'ParentID',
|
|
560
|
+
DefaultIcon: 'fa-solid fa-folder',
|
|
561
|
+
OrderBy: 'Name ASC',
|
|
562
|
+
};
|
|
563
|
+
/** Tree config for the pickable agents (built at load time — excludes Realtime types). */
|
|
564
|
+
AgentTreeLeafConfig;
|
|
565
|
+
/** Tree selection binding (single agent). */
|
|
566
|
+
SelectedAgentIDs = [];
|
|
567
|
+
DayNames = CRON_DAY_NAMES;
|
|
568
|
+
DayOfWeekOptions = CRON_DAY_NAMES.map((name, i) => ({ text: name, value: i }));
|
|
569
|
+
DayOfMonthOptions = Array.from({ length: 31 }, (_, i) => ({ text: `${i + 1}`, value: i + 1 }));
|
|
570
|
+
ScheduleKindOptions = [
|
|
571
|
+
{ Value: 'hourly', Label: 'Hourly' },
|
|
572
|
+
{ Value: 'daily', Label: 'Daily' },
|
|
573
|
+
{ Value: 'weekly', Label: 'Weekly' },
|
|
574
|
+
{ Value: 'monthly', Label: 'Monthly' },
|
|
575
|
+
{ Value: 'advanced', Label: 'Advanced (cron)' },
|
|
576
|
+
];
|
|
577
|
+
NotifyConditionOptions = [
|
|
578
|
+
{ text: 'Always — after every run', value: 'Always' },
|
|
579
|
+
{ text: 'On success only', value: 'OnSuccess' },
|
|
580
|
+
{ text: 'On failure only', value: 'OnFailure' },
|
|
581
|
+
{ text: 'On change — when the result differs from the prior run', value: 'OnChange' },
|
|
582
|
+
];
|
|
583
|
+
ChannelOptions = [
|
|
584
|
+
{ text: 'In-app', value: 'InApp' },
|
|
585
|
+
{ text: 'Email', value: 'Email' },
|
|
586
|
+
];
|
|
587
|
+
RecipientModeOptions = [
|
|
588
|
+
{ text: 'MJ user', value: 'user' },
|
|
589
|
+
{ text: 'External email', value: 'email' },
|
|
590
|
+
];
|
|
591
|
+
editingEntity = null;
|
|
592
|
+
deletedRecipients = [];
|
|
593
|
+
initialized = false;
|
|
594
|
+
async ngOnInit() {
|
|
595
|
+
this.initialized = true;
|
|
596
|
+
await this.reload();
|
|
597
|
+
}
|
|
598
|
+
/** True when editing an existing routine (vs. creating a new one). */
|
|
599
|
+
get IsEdit() {
|
|
600
|
+
return this._routineID != null;
|
|
601
|
+
}
|
|
602
|
+
/** Active skills available for pre-activation. */
|
|
603
|
+
get SkillOptions() {
|
|
604
|
+
return this.Catalog?.Skills ?? [];
|
|
605
|
+
}
|
|
606
|
+
/** Name of the currently selected agent (empty when none). */
|
|
607
|
+
get SelectedAgentName() {
|
|
608
|
+
if (!this.TargetID) {
|
|
609
|
+
return '';
|
|
610
|
+
}
|
|
611
|
+
return this.Catalog?.NameByID.get(NormalizeUUID(this.TargetID)) ?? '';
|
|
612
|
+
}
|
|
613
|
+
/** IconClass of the currently selected agent (robot fallback). */
|
|
614
|
+
get SelectedAgentIcon() {
|
|
615
|
+
if (!this.TargetID) {
|
|
616
|
+
return 'fa-solid fa-robot';
|
|
617
|
+
}
|
|
618
|
+
return this.Catalog?.IconByID.get(NormalizeUUID(this.TargetID)) ?? 'fa-solid fa-robot';
|
|
619
|
+
}
|
|
620
|
+
/** Live human-readable preview of the schedule being built. */
|
|
621
|
+
get SchedulePreview() {
|
|
622
|
+
return DescribeCronExpression(this.buildCron());
|
|
623
|
+
}
|
|
624
|
+
/** Helper text under the RoutineType toggle. */
|
|
625
|
+
get RoutineTypeHelp() {
|
|
626
|
+
return this.RoutineType === 'Scheduled'
|
|
627
|
+
? 'Runs on the schedule and notifies per the notification condition.'
|
|
628
|
+
: 'Runs on the schedule and hashes each result — pair with the "On change" condition to be notified only when the result changes.';
|
|
629
|
+
}
|
|
630
|
+
/** Handles agent selection from the category tree (leaf nodes only). */
|
|
631
|
+
/** The selected agent as a CompositeKey for the tree-dropdown's Value binding. */
|
|
632
|
+
get SelectedAgentKey() {
|
|
633
|
+
return this.TargetID ? CompositeKey.FromID(this.TargetID) : null;
|
|
634
|
+
}
|
|
635
|
+
OnAgentNodeSelected(args) {
|
|
636
|
+
if (args.Node.Type === 'leaf') {
|
|
637
|
+
this.TargetID = args.Node.ID;
|
|
638
|
+
this.SelectedAgentIDs = [args.Node.ID];
|
|
639
|
+
this.cdr.markForCheck();
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
SetScheduleKind(kind) {
|
|
643
|
+
if (kind === this.ScheduleKind) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (kind === 'advanced' && !this.RawCron.trim()) {
|
|
647
|
+
// Seed the advanced box from the current preset so nothing is lost
|
|
648
|
+
this.RawCron = this.buildCron();
|
|
649
|
+
}
|
|
650
|
+
this.ScheduleKind = kind;
|
|
651
|
+
this.cdr.markForCheck();
|
|
652
|
+
}
|
|
653
|
+
/** Toggles a skill in/out of the RequestedSkillIDs selection. */
|
|
654
|
+
ToggleSkill(skillID) {
|
|
655
|
+
const index = this.SelectedSkillIDs.indexOf(skillID);
|
|
656
|
+
if (index >= 0) {
|
|
657
|
+
this.SelectedSkillIDs = this.SelectedSkillIDs.filter((id) => id !== skillID);
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
660
|
+
this.SelectedSkillIDs = [...this.SelectedSkillIDs, skillID];
|
|
661
|
+
}
|
|
662
|
+
this.cdr.markForCheck();
|
|
663
|
+
}
|
|
664
|
+
IsSkillSelected(skillID) {
|
|
665
|
+
return this.SelectedSkillIDs.includes(skillID);
|
|
666
|
+
}
|
|
667
|
+
// ---------------------------------------------------------------
|
|
668
|
+
// Recipients
|
|
669
|
+
// ---------------------------------------------------------------
|
|
670
|
+
AddRecipient() {
|
|
671
|
+
this.Recipients = [
|
|
672
|
+
...this.Recipients,
|
|
673
|
+
{ Entity: null, Mode: 'user', UserID: null, Email: '', Channel: 'InApp' },
|
|
674
|
+
];
|
|
675
|
+
void this.ensureUserOptions();
|
|
676
|
+
}
|
|
677
|
+
RemoveRecipient(index) {
|
|
678
|
+
const row = this.Recipients[index];
|
|
679
|
+
if (row?.Entity) {
|
|
680
|
+
this.deletedRecipients.push(row.Entity);
|
|
681
|
+
}
|
|
682
|
+
this.Recipients = this.Recipients.filter((_, i) => i !== index);
|
|
683
|
+
}
|
|
684
|
+
/** Moves a recipient up/down — the saved Sequence is the row index. */
|
|
685
|
+
MoveRecipient(index, delta) {
|
|
686
|
+
const target = index + delta;
|
|
687
|
+
if (target < 0 || target >= this.Recipients.length) {
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const next = [...this.Recipients];
|
|
691
|
+
[next[index], next[target]] = [next[target], next[index]];
|
|
692
|
+
this.Recipients = next;
|
|
693
|
+
}
|
|
694
|
+
/** When the row's mode flips, clear the other identity field. */
|
|
695
|
+
OnRecipientModeChange(row) {
|
|
696
|
+
if (row.Mode === 'user') {
|
|
697
|
+
row.Email = '';
|
|
698
|
+
void this.ensureUserOptions();
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
row.UserID = null;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
// ---------------------------------------------------------------
|
|
705
|
+
// Save / cancel
|
|
706
|
+
// ---------------------------------------------------------------
|
|
707
|
+
Cancel() {
|
|
708
|
+
this.Cancelled.emit();
|
|
709
|
+
}
|
|
710
|
+
async Save() {
|
|
711
|
+
if (this.IsSaving) {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
this.ValidationErrors = this.validate();
|
|
715
|
+
if (this.ValidationErrors.length > 0) {
|
|
716
|
+
this.cdr.markForCheck();
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
this.IsSaving = true;
|
|
720
|
+
this.cdr.markForCheck();
|
|
721
|
+
try {
|
|
722
|
+
const p = this.ProviderToUse;
|
|
723
|
+
const isNew = !this.IsEdit;
|
|
724
|
+
const routine = this.editingEntity ??
|
|
725
|
+
(await p.GetEntityObject('MJ: User Routines', p.CurrentUser));
|
|
726
|
+
if (isNew) {
|
|
727
|
+
routine.UserID = p.CurrentUser.ID;
|
|
728
|
+
}
|
|
729
|
+
routine.Name = this.Name.trim();
|
|
730
|
+
routine.Description = this.Description.trim() || null;
|
|
731
|
+
routine.RoutineType = this.RoutineType;
|
|
732
|
+
routine.TargetType = 'Agent';
|
|
733
|
+
// Validated non-null in validate()
|
|
734
|
+
routine.TargetID = this.TargetID;
|
|
735
|
+
routine.InitialMessage = this.InitialMessage.trim() || null;
|
|
736
|
+
routine.StartingPayload = this.StartingPayloadText.trim() || null;
|
|
737
|
+
routine.RequestedSkillIDs = SerializeSkillIDs(this.SelectedSkillIDs);
|
|
738
|
+
routine.CronExpression = this.buildCron();
|
|
739
|
+
routine.Timezone = this.Timezone;
|
|
740
|
+
routine.StartAt = FromDateTimeLocal(this.StartAtLocal);
|
|
741
|
+
routine.EndAt = FromDateTimeLocal(this.EndAtLocal);
|
|
742
|
+
routine.NotifyCondition = this.NotifyCondition;
|
|
743
|
+
routine.NotifyViaInApp = this.NotifyViaInApp;
|
|
744
|
+
routine.NotifyViaEmail = this.NotifyViaEmail;
|
|
745
|
+
if (isNew) {
|
|
746
|
+
const beforeArgs = new BeforeRoutineCreatedEventArgs(routine);
|
|
747
|
+
this.BeforeRoutineCreated.emit(beforeArgs);
|
|
748
|
+
if (beforeArgs.Cancel) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
const saved = await routine.Save();
|
|
753
|
+
if (!saved) {
|
|
754
|
+
this.ValidationErrors = [
|
|
755
|
+
`Save failed: ${routine.LatestResult?.CompleteMessage ?? 'unknown error'}`,
|
|
756
|
+
];
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
const recipientErrors = await this.saveRecipients(routine);
|
|
760
|
+
if (recipientErrors.length > 0) {
|
|
761
|
+
this.ValidationErrors = recipientErrors;
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
if (isNew) {
|
|
765
|
+
// Re-scope the engine's dependent (recipients/runs) configs to include
|
|
766
|
+
// the new routine — their client-side filter is a Config-time snapshot.
|
|
767
|
+
await this.engine().Refresh(p.CurrentUser);
|
|
768
|
+
this.AfterRoutineCreated.emit(new AfterRoutineCreatedEventArgs(routine));
|
|
769
|
+
}
|
|
770
|
+
this.notifications.CreateSimpleNotification(isNew ? `'${routine.Name}' created` : `'${routine.Name}' updated`, 'success', 3000);
|
|
771
|
+
this.Saved.emit(routine);
|
|
772
|
+
}
|
|
773
|
+
finally {
|
|
774
|
+
this.IsSaving = false;
|
|
775
|
+
this.cdr.markForCheck();
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
// ---------------------------------------------------------------
|
|
779
|
+
// Internals
|
|
780
|
+
// ---------------------------------------------------------------
|
|
781
|
+
engine() {
|
|
782
|
+
return UserRoutineEngine.GetProviderInstance(this.ProviderToUse, UserRoutineEngine);
|
|
783
|
+
}
|
|
784
|
+
/** True when the loaded routine differs from the basic-path defaults in any advanced field. */
|
|
785
|
+
usesAdvancedSettings() {
|
|
786
|
+
return this.Description.trim().length > 0
|
|
787
|
+
|| this.RoutineType === 'Monitoring'
|
|
788
|
+
|| this.StartingPayloadText.trim().length > 0
|
|
789
|
+
|| this.SelectedSkillIDs.length > 0
|
|
790
|
+
|| this.Timezone !== GetLocalTimezone()
|
|
791
|
+
|| this.StartAtLocal.trim().length > 0
|
|
792
|
+
|| this.EndAtLocal.trim().length > 0
|
|
793
|
+
|| this.NotifyCondition !== 'Always'
|
|
794
|
+
|| !this.NotifyViaInApp
|
|
795
|
+
|| this.NotifyViaEmail
|
|
796
|
+
|| this.Recipients.length > 0;
|
|
797
|
+
}
|
|
798
|
+
async reload() {
|
|
799
|
+
this.IsLoading = true;
|
|
800
|
+
this.ValidationErrors = [];
|
|
801
|
+
this.deletedRecipients = [];
|
|
802
|
+
this.cdr.markForCheck();
|
|
803
|
+
try {
|
|
804
|
+
const p = this.ProviderToUse;
|
|
805
|
+
const [catalog] = await Promise.all([
|
|
806
|
+
LoadRoutineTargetCatalog(p),
|
|
807
|
+
this.engine().Config(false, p.CurrentUser, p),
|
|
808
|
+
]);
|
|
809
|
+
this.Catalog = catalog;
|
|
810
|
+
this.buildAgentTreeConfig(p);
|
|
811
|
+
if (this._routineID) {
|
|
812
|
+
await this.loadExisting(this._routineID);
|
|
813
|
+
this.ShowAdvanced = this.usesAdvancedSettings();
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
this.resetForNew();
|
|
817
|
+
this.ShowAdvanced = false;
|
|
818
|
+
}
|
|
819
|
+
if (this.Recipients.some((r) => r.Mode === 'user')) {
|
|
820
|
+
await this.ensureUserOptions();
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
catch (e) {
|
|
824
|
+
this.ValidationErrors = [
|
|
825
|
+
`Failed to load the editor: ${e instanceof Error ? e.message : 'unknown error'}`,
|
|
826
|
+
];
|
|
827
|
+
}
|
|
828
|
+
finally {
|
|
829
|
+
this.IsLoading = false;
|
|
830
|
+
this.cdr.markForCheck();
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Builds the agent tree leaf config: Active, root-level agents only, EXCLUDING
|
|
835
|
+
* agents whose type is the Realtime agent type. The exclusion is expressed as an
|
|
836
|
+
* inline NOT IN list of type IDs resolved from metadata BY NAME (never hardcoded).
|
|
837
|
+
*/
|
|
838
|
+
buildAgentTreeConfig(provider) {
|
|
839
|
+
const realtimeTypeIDs = this.resolveRealtimeTypeIDs(provider);
|
|
840
|
+
const filters = [`Status='Active'`, `ParentID IS NULL`];
|
|
841
|
+
if (realtimeTypeIDs.length > 0) {
|
|
842
|
+
const inList = realtimeTypeIDs.map((id) => `'${id}'`).join(',');
|
|
843
|
+
filters.push(`(TypeID IS NULL OR TypeID NOT IN (${inList}))`);
|
|
844
|
+
}
|
|
845
|
+
this.AgentTreeLeafConfig = {
|
|
846
|
+
EntityName: 'MJ: AI Agents',
|
|
847
|
+
ParentField: 'CategoryID',
|
|
848
|
+
DisplayField: 'Name',
|
|
849
|
+
IconField: 'IconClass',
|
|
850
|
+
DefaultIcon: 'fa-solid fa-robot',
|
|
851
|
+
ExtraFilter: filters.join(' AND '),
|
|
852
|
+
OrderBy: 'Name ASC',
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
/** Realtime agent-type IDs resolved from the cached AI metadata by type NAME. */
|
|
856
|
+
resolveRealtimeTypeIDs(provider) {
|
|
857
|
+
// The catalog load above already Config'd AIEngineBase for this provider —
|
|
858
|
+
// reuse its cached AgentTypes through the provider-scoped instance.
|
|
859
|
+
const engine = AIEngineBase.GetProviderInstance(provider, AIEngineBase);
|
|
860
|
+
return engine.AgentTypes
|
|
861
|
+
.filter((t) => t.Name?.trim().toLowerCase() === 'realtime')
|
|
862
|
+
.map((t) => t.ID);
|
|
863
|
+
}
|
|
864
|
+
resetForNew() {
|
|
865
|
+
this.editingEntity = null;
|
|
866
|
+
this.Name = '';
|
|
867
|
+
this.Description = '';
|
|
868
|
+
this.TargetID = null;
|
|
869
|
+
this.SelectedAgentIDs = [];
|
|
870
|
+
this.InitialMessage = '';
|
|
871
|
+
this.StartingPayloadText = '';
|
|
872
|
+
this.SelectedSkillIDs = [];
|
|
873
|
+
this.RoutineType = 'Scheduled';
|
|
874
|
+
this.ScheduleKind = 'daily';
|
|
875
|
+
this.ScheduleMinute = 0;
|
|
876
|
+
this.ScheduleTime = '09:00';
|
|
877
|
+
this.ScheduleDayOfWeek = 1;
|
|
878
|
+
this.ScheduleDayOfMonth = 1;
|
|
879
|
+
this.RawCron = '';
|
|
880
|
+
this.Timezone = GetLocalTimezone();
|
|
881
|
+
this.StartAtLocal = '';
|
|
882
|
+
this.EndAtLocal = '';
|
|
883
|
+
this.NotifyCondition = 'Always';
|
|
884
|
+
this.NotifyViaInApp = true;
|
|
885
|
+
this.NotifyViaEmail = false;
|
|
886
|
+
this.Recipients = [];
|
|
887
|
+
}
|
|
888
|
+
async loadExisting(routineID) {
|
|
889
|
+
const p = this.ProviderToUse;
|
|
890
|
+
// Prefer the engine's cached entity; fall back to a direct load (e.g., deep link
|
|
891
|
+
// into a routine saved elsewhere before the cache refreshed).
|
|
892
|
+
let routine = this.engine().GetRoutineByID(routineID) ?? null;
|
|
893
|
+
if (!routine) {
|
|
894
|
+
const loadedEntity = await p.GetEntityObject('MJ: User Routines', p.CurrentUser);
|
|
895
|
+
const loaded = await loadedEntity.Load(routineID);
|
|
896
|
+
routine = loaded ? loadedEntity : null;
|
|
897
|
+
}
|
|
898
|
+
if (!routine) {
|
|
899
|
+
this.ValidationErrors = [`Routine ${routineID} could not be loaded.`];
|
|
900
|
+
this.resetForNew();
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
this.editingEntity = routine;
|
|
904
|
+
this.Name = routine.Name;
|
|
905
|
+
this.Description = routine.Description ?? '';
|
|
906
|
+
this.TargetID = routine.TargetID;
|
|
907
|
+
this.SelectedAgentIDs = routine.TargetID ? [routine.TargetID] : [];
|
|
908
|
+
this.InitialMessage = routine.InitialMessage ?? '';
|
|
909
|
+
this.StartingPayloadText = routine.StartingPayload ?? '';
|
|
910
|
+
this.SelectedSkillIDs = ParseSkillIDs(routine.RequestedSkillIDs);
|
|
911
|
+
this.RoutineType = routine.RoutineType;
|
|
912
|
+
this.applyCron(ParseCronExpression(routine.CronExpression));
|
|
913
|
+
this.Timezone = routine.Timezone;
|
|
914
|
+
this.StartAtLocal = ToDateTimeLocal(routine.StartAt);
|
|
915
|
+
this.EndAtLocal = ToDateTimeLocal(routine.EndAt);
|
|
916
|
+
this.NotifyCondition = routine.NotifyCondition;
|
|
917
|
+
this.NotifyViaInApp = routine.NotifyViaInApp;
|
|
918
|
+
this.NotifyViaEmail = routine.NotifyViaEmail;
|
|
919
|
+
this.loadRecipientRows(routineID);
|
|
920
|
+
}
|
|
921
|
+
applyCron(schedule) {
|
|
922
|
+
this.ScheduleKind = schedule.Kind;
|
|
923
|
+
this.ScheduleMinute = schedule.Minute;
|
|
924
|
+
this.ScheduleTime = `${schedule.Hour.toString().padStart(2, '0')}:${schedule.Minute.toString().padStart(2, '0')}`;
|
|
925
|
+
this.ScheduleDayOfWeek = schedule.DayOfWeek;
|
|
926
|
+
this.ScheduleDayOfMonth = schedule.DayOfMonth;
|
|
927
|
+
this.RawCron = schedule.Raw;
|
|
928
|
+
}
|
|
929
|
+
buildCron() {
|
|
930
|
+
const { hour, minute } = this.parseScheduleTime();
|
|
931
|
+
const schedule = {
|
|
932
|
+
Kind: this.ScheduleKind,
|
|
933
|
+
Minute: this.ScheduleKind === 'hourly' ? this.clampMinute(this.ScheduleMinute) : minute,
|
|
934
|
+
Hour: hour,
|
|
935
|
+
DayOfWeek: this.ScheduleDayOfWeek,
|
|
936
|
+
DayOfMonth: this.ScheduleDayOfMonth,
|
|
937
|
+
Raw: this.RawCron,
|
|
938
|
+
};
|
|
939
|
+
return BuildCronExpression(schedule);
|
|
940
|
+
}
|
|
941
|
+
parseScheduleTime() {
|
|
942
|
+
const match = /^(\d{1,2}):(\d{2})$/.exec(this.ScheduleTime.trim());
|
|
943
|
+
if (!match) {
|
|
944
|
+
return { hour: 9, minute: 0 };
|
|
945
|
+
}
|
|
946
|
+
return {
|
|
947
|
+
hour: Math.min(23, Math.max(0, parseInt(match[1], 10))),
|
|
948
|
+
minute: this.clampMinute(parseInt(match[2], 10)),
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
clampMinute(minute) {
|
|
952
|
+
return Math.min(59, Math.max(0, Math.round(minute ?? 0)));
|
|
953
|
+
}
|
|
954
|
+
/** Builds the editable recipient rows from the engine's cached recipients. */
|
|
955
|
+
loadRecipientRows(routineID) {
|
|
956
|
+
this.Recipients = this.engine()
|
|
957
|
+
.RecipientsForRoutine(routineID)
|
|
958
|
+
.map((entity) => ({
|
|
959
|
+
Entity: entity,
|
|
960
|
+
Mode: entity.UserID ? 'user' : 'email',
|
|
961
|
+
UserID: entity.UserID,
|
|
962
|
+
Email: entity.Email ?? '',
|
|
963
|
+
Channel: entity.Channel,
|
|
964
|
+
}));
|
|
965
|
+
}
|
|
966
|
+
/** Lazily loads the user picker options the first time a user-mode row exists. */
|
|
967
|
+
async ensureUserOptions() {
|
|
968
|
+
if (this.UserOptions.length > 0) {
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
const p = this.ProviderToUse;
|
|
972
|
+
const rv = RunView.FromMetadataProvider(p);
|
|
973
|
+
const result = await rv.RunView({
|
|
974
|
+
EntityName: 'MJ: Users',
|
|
975
|
+
Fields: ['ID', 'Name', 'Email'],
|
|
976
|
+
ExtraFilter: `IsActive=1`,
|
|
977
|
+
OrderBy: 'Name ASC',
|
|
978
|
+
ResultType: 'simple',
|
|
979
|
+
}, p.CurrentUser);
|
|
980
|
+
if (result.Success) {
|
|
981
|
+
this.UserOptions = result.Results ?? [];
|
|
982
|
+
this.cdr.markForCheck();
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
validate() {
|
|
986
|
+
const errors = [];
|
|
987
|
+
if (!this.Name.trim()) {
|
|
988
|
+
errors.push('Name is required.');
|
|
989
|
+
}
|
|
990
|
+
if (!this.TargetID) {
|
|
991
|
+
errors.push('Select the agent this routine should run.');
|
|
992
|
+
}
|
|
993
|
+
if (this.ScheduleKind === 'advanced' && !IsPlausibleCronExpression(this.RawCron)) {
|
|
994
|
+
errors.push('The advanced cron expression must have 5 (or 6) space-separated fields.');
|
|
995
|
+
}
|
|
996
|
+
if (!this.Timezone?.trim()) {
|
|
997
|
+
errors.push('Timezone is required.');
|
|
998
|
+
}
|
|
999
|
+
const payloadCheck = ValidateOptionalJson(this.StartingPayloadText);
|
|
1000
|
+
if (!payloadCheck.Valid) {
|
|
1001
|
+
errors.push(`Starting payload is not valid JSON: ${payloadCheck.Error}`);
|
|
1002
|
+
}
|
|
1003
|
+
const startAt = FromDateTimeLocal(this.StartAtLocal);
|
|
1004
|
+
const endAt = FromDateTimeLocal(this.EndAtLocal);
|
|
1005
|
+
if (startAt && endAt && endAt.getTime() <= startAt.getTime()) {
|
|
1006
|
+
errors.push('End of the activation window must be after its start.');
|
|
1007
|
+
}
|
|
1008
|
+
this.Recipients.forEach((row, i) => {
|
|
1009
|
+
if (row.Mode === 'user' && !row.UserID) {
|
|
1010
|
+
errors.push(`Recipient ${i + 1}: choose a user (or switch the row to an external email).`);
|
|
1011
|
+
}
|
|
1012
|
+
if (row.Mode === 'email' && !IsPlausibleEmail(row.Email)) {
|
|
1013
|
+
errors.push(`Recipient ${i + 1}: enter a valid email address.`);
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
return errors;
|
|
1017
|
+
}
|
|
1018
|
+
/** Persists recipient rows in order (Sequence = index) and deletes removed rows. */
|
|
1019
|
+
async saveRecipients(routine) {
|
|
1020
|
+
const p = this.ProviderToUse;
|
|
1021
|
+
const errors = [];
|
|
1022
|
+
for (const entity of this.deletedRecipients) {
|
|
1023
|
+
const deleted = await entity.Delete();
|
|
1024
|
+
if (!deleted) {
|
|
1025
|
+
errors.push(`Failed to remove a recipient: ${entity.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
this.deletedRecipients = [];
|
|
1029
|
+
for (let i = 0; i < this.Recipients.length; i++) {
|
|
1030
|
+
const row = this.Recipients[i];
|
|
1031
|
+
const entity = row.Entity ??
|
|
1032
|
+
(await p.GetEntityObject('MJ: User Routine Recipients', p.CurrentUser));
|
|
1033
|
+
entity.RoutineID = routine.ID;
|
|
1034
|
+
entity.UserID = row.Mode === 'user' ? row.UserID : null;
|
|
1035
|
+
entity.Email = row.Mode === 'email' ? row.Email.trim() : null;
|
|
1036
|
+
entity.Channel = row.Channel;
|
|
1037
|
+
entity.Sequence = i;
|
|
1038
|
+
const saved = await entity.Save();
|
|
1039
|
+
if (saved) {
|
|
1040
|
+
row.Entity = entity;
|
|
1041
|
+
}
|
|
1042
|
+
else {
|
|
1043
|
+
errors.push(`Failed to save recipient ${i + 1}: ${entity.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return errors;
|
|
1047
|
+
}
|
|
1048
|
+
static ɵfac = /*@__PURE__*/ (() => { let ɵNewRoutineComponent_BaseFactory; return function NewRoutineComponent_Factory(__ngFactoryType__) { return (ɵNewRoutineComponent_BaseFactory || (ɵNewRoutineComponent_BaseFactory = i0.ɵɵgetInheritedFactory(NewRoutineComponent)))(__ngFactoryType__ || NewRoutineComponent); }; })();
|
|
1049
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: NewRoutineComponent, selectors: [["mj-new-routine"]], inputs: { RoutineID: "RoutineID" }, outputs: { Saved: "Saved", Cancelled: "Cancelled", BeforeRoutineCreated: "BeforeRoutineCreated", AfterRoutineCreated: "AfterRoutineCreated" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 1, consts: [[1, "editor-loading"], [1, "routine-editor"], ["text", "Loading editor...", "size", "medium"], ["Variant", "error"], [1, "editor-section"], [1, "editor-field"], ["for", "routine-name", 1, "editor-label"], [1, "editor-required"], ["id", "routine-name", "type", "text", "placeholder", "e.g. Morning membership digest", 1, "mj-input", 3, "ngModelChange", "ngModel"], [1, "editor-label"], ["DefaultExpansion", "all", "SelectionMode", "single", "SelectableTypes", "leaf", "Placeholder", "Select an agent...", 3, "BranchConfig", "LeafConfig", "Value", "Clearable"], [1, "editor-hint"], ["for", "routine-message", 1, "editor-label"], ["id", "routine-message", "placeholder", "The message the routine sends to the agent each time it runs", 3, "ngModelChange", "ngModel", "ExcludedTriggerKeys", "Provider", "enableAttachments", "autoFocus", "currentUser"], ["role", "radiogroup", "aria-label", "Schedule frequency", 1, "editor-segmented", "editor-segmented--wrap"], ["type", "button", 1, "editor-segment", 3, "editor-segment--active"], [1, "editor-schedule-detail"], [1, "editor-field", "editor-field--inline"], [1, "editor-schedule-preview"], [1, "fa-solid", "fa-calendar-check"], ["type", "button", 1, "editor-advanced-toggle", 3, "click"], [1, "fa-solid"], [1, "editor-hint-inline"], [1, "editor-footer"], ["mjButton", "", "variant", "primary", "size", "md", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-check"], ["mjButton", "", "variant", "secondary", "size", "md", 3, "click", "disabled"], [1, "editor-errors"], ["DefaultExpansion", "all", "SelectionMode", "single", "SelectableTypes", "leaf", "Placeholder", "Select an agent...", 3, "AfterNodeSelect", "BranchConfig", "LeafConfig", "Value", "Clearable"], ["type", "button", 1, "editor-segment", 3, "click"], [3, "ngModelChange", "ngModel", "Min", "Max", "Step"], ["type", "time", 1, "mj-input", "editor-time-input", 3, "ngModelChange", "ngModel"], ["TextField", "text", "ValueField", "value", 1, "editor-inline-dropdown", 3, "ngModelChange", "Data", "ValuePrimitive", "ngModel"], ["for", "routine-cron", 1, "editor-label"], ["id", "routine-cron", "type", "text", "placeholder", "minute hour day-of-month month day-of-week", 1, "mj-input", "editor-mono", 3, "ngModelChange", "ngModel"], [1, "editor-section-title"], [1, "fa-solid", "fa-circle-info"], ["for", "routine-description", 1, "editor-label"], ["id", "routine-description", "rows", "2", "placeholder", "What does this routine do?", 1, "mj-textarea", 3, "ngModelChange", "ngModel"], ["role", "radiogroup", "aria-label", "Routine type", 1, "editor-segmented"], [1, "fa-solid", "fa-clock"], [1, "fa-solid", "fa-eye"], ["Placeholder", "Select an IANA timezone...", 3, "ngModelChange", "Data", "ValuePrimitive", "ngModel"], [1, "editor-field-row"], ["for", "routine-startat", 1, "editor-label"], ["id", "routine-startat", "type", "datetime-local", 1, "mj-input", 3, "ngModelChange", "ngModel"], ["for", "routine-endat", 1, "editor-label"], ["id", "routine-endat", "type", "datetime-local", 1, "mj-input", 3, "ngModelChange", "ngModel"], [1, "editor-code"], ["language", "json", "placeholder", "{ \"example\": true }", 3, "ngModelChange", "ngModel"], [1, "fa-solid", "fa-bell"], ["TextField", "text", "ValueField", "value", 3, "ngModelChange", "Data", "ValuePrimitive", "ngModel"], [1, "editor-field", "editor-field--inline", "editor-switches"], ["OnLabel", "In-app", "OffLabel", "In-app", 3, "ngModelChange", "ngModel"], ["OnLabel", "Email", "OffLabel", "Email", 3, "ngModelChange", "ngModel"], [1, "editor-recipients-header"], ["mjButton", "", "variant", "outline", "size", "sm", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "editor-recipient-row"], [1, "editor-skills"], ["type", "button", 1, "editor-skill-chip", 3, "editor-skill-chip--selected", "title"], ["type", "button", 1, "editor-skill-chip", 3, "click", "title"], [1, "fa-solid", "fa-check", "editor-skill-check"], [1, "editor-recipient-order"], ["mjButton", "", "variant", "icon", "size", "sm", "title", "Move up", 3, "click", "disabled"], [1, "fa-solid", "fa-chevron-up"], ["mjButton", "", "variant", "icon", "size", "sm", "title", "Move down", 3, "click", "disabled"], [1, "fa-solid", "fa-chevron-down"], ["TextField", "text", "ValueField", "value", 1, "editor-recipient-mode", 3, "ngModelChange", "Data", "ValuePrimitive", "ngModel"], ["TextField", "Name", "ValueField", "ID", "Placeholder", "Select a user...", 1, "editor-recipient-target", 3, "Data", "ValuePrimitive", "ngModel"], ["type", "email", "placeholder", "name@example.com", 1, "mj-input", "editor-recipient-target", 3, "ngModel"], ["TextField", "text", "ValueField", "value", 1, "editor-recipient-channel", 3, "ngModelChange", "Data", "ValuePrimitive", "ngModel"], ["mjButton", "", "variant", "icon", "size", "sm", "title", "Remove recipient", 3, "click"], [1, "fa-solid", "fa-trash-can"], ["TextField", "Name", "ValueField", "ID", "Placeholder", "Select a user...", 1, "editor-recipient-target", 3, "ngModelChange", "Data", "ValuePrimitive", "ngModel"], ["type", "email", "placeholder", "name@example.com", 1, "mj-input", "editor-recipient-target", 3, "ngModelChange", "ngModel"]], template: function NewRoutineComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1050
|
+
i0.ɵɵconditionalCreate(0, NewRoutineComponent_Conditional_0_Template, 2, 0, "div", 0)(1, NewRoutineComponent_Conditional_1_Template, 49, 22, "div", 1);
|
|
1051
|
+
} if (rf & 2) {
|
|
1052
|
+
i0.ɵɵconditional(ctx.IsLoading ? 0 : 1);
|
|
1053
|
+
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJAlertComponent, i2.MJButtonDirective, i2.MJComboboxComponent, i2.MJDropdownComponent, i2.MJNumericInputComponent, i2.MJSwitchComponent, i3.LoadingComponent, i4.CodeEditorComponent, i5.TreeDropdownComponent, i6.MentionEditorComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n}\n\n.editor-loading[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n padding: 48px 0;\n}\n\n.routine-editor[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 4px 2px 0 2px;\n}\n\n.editor-errors[_ngcontent-%COMP%] {\n margin: 0;\n padding-left: 18px;\n}\n\n.editor-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-lg, 10px);\n}\n\n.editor-section-title[_ngcontent-%COMP%] {\n margin: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.editor-section-title[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.editor-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.editor-field--inline[_ngcontent-%COMP%] {\n flex-direction: row;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.editor-field-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.editor-field-row[_ngcontent-%COMP%] > .editor-field[_ngcontent-%COMP%] {\n flex: 1 1 220px;\n}\n\n.editor-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.editor-required[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.editor-hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.editor-hint-inline[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n\n\n.editor-segmented[_ngcontent-%COMP%] {\n display: inline-flex;\n gap: 0;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n overflow: hidden;\n width: fit-content;\n}\n\n.editor-segmented--wrap[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n}\n\n.editor-segment[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 14px;\n font-size: 13px;\n border: none;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.editor-segment[_ngcontent-%COMP%] + .editor-segment[_ngcontent-%COMP%] {\n border-left: 1px solid var(--mj-border-default);\n}\n\n.editor-segment[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.editor-segment--active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n\n\n.editor-schedule-detail[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-md, 8px);\n}\n\n.editor-schedule-preview[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.editor-schedule-preview[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.editor-time-input[_ngcontent-%COMP%] {\n width: 130px;\n}\n\n.editor-inline-dropdown[_ngcontent-%COMP%] {\n min-width: 140px;\n}\n\n.editor-mono[_ngcontent-%COMP%] {\n font-family: var(--mj-font-mono, monospace);\n}\n\n\n\n.editor-code[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n overflow: hidden;\n min-height: 90px;\n}\n\n\n\n.editor-skills[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.editor-skill-chip[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n font-size: 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 999px);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;\n}\n\n.editor-skill-chip[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n}\n\n.editor-skill-chip--selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.editor-skill-check[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n\n.editor-switches[_ngcontent-%COMP%] {\n gap: 24px;\n}\n\n.editor-recipients-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n\n.editor-recipient-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface);\n}\n\n.editor-recipient-order[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.editor-recipient-mode[_ngcontent-%COMP%] {\n flex: 0 0 150px;\n}\n\n.editor-recipient-target[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.editor-recipient-channel[_ngcontent-%COMP%] {\n flex: 0 0 120px;\n}\n\n\n\n.editor-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 0 4px 0;\n border-top: 1px solid var(--mj-border-default);\n position: sticky;\n bottom: 0;\n background: var(--mj-bg-surface);\n}\n\n\n\n.editor-selected-agent[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md, 8px);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 13px;\n font-weight: 600;\n width: fit-content;\n}\n\n.editor-selected-agent-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 400;\n color: var(--mj-text-muted);\n}\n\n.editor-agent-tree[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n max-height: 280px;\n overflow: auto;\n background: var(--mj-bg-surface);\n}\n\n\n\n.editor-advanced-toggle[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 12px;\n border: 1px dashed var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n text-align: left;\n}\n\n.editor-advanced-toggle[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.editor-advanced-toggle[_ngcontent-%COMP%] .editor-hint-inline[_ngcontent-%COMP%] {\n font-weight: 400;\n font-size: 11px;\n color: var(--mj-text-muted);\n}"] });
|
|
1054
|
+
}
|
|
1055
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NewRoutineComponent, [{
|
|
1056
|
+
type: Component,
|
|
1057
|
+
args: [{ standalone: false, selector: 'mj-new-routine', template: "@if (IsLoading) {\n <div class=\"editor-loading\">\n <mj-loading text=\"Loading editor...\" size=\"medium\"></mj-loading>\n </div>\n} @else {\n <div class=\"routine-editor\">\n\n @if (ValidationErrors.length > 0) {\n <mj-alert Variant=\"error\">\n <ul class=\"editor-errors\">\n @for (error of ValidationErrors; track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </mj-alert>\n }\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 BASICS (the 80% path: name, agent, message, schedule) \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <section class=\"editor-section\">\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-name\">Name <span class=\"editor-required\">*</span></label>\n <input id=\"routine-name\" class=\"mj-input\" type=\"text\" [(ngModel)]=\"Name\" placeholder=\"e.g. Morning membership digest\" />\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Which agent should this routine run? <span class=\"editor-required\">*</span></label>\n @if (AgentTreeLeafConfig) {\n <mj-tree-dropdown\n [BranchConfig]=\"AgentTreeBranchConfig\"\n [LeafConfig]=\"AgentTreeLeafConfig\"\n DefaultExpansion=\"all\"\n SelectionMode=\"single\"\n SelectableTypes=\"leaf\"\n [Value]=\"SelectedAgentKey\"\n [Clearable]=\"false\"\n Placeholder=\"Select an agent...\"\n (AfterNodeSelect)=\"OnAgentNodeSelected($event)\">\n </mj-tree-dropdown>\n }\n <div class=\"editor-hint\">Active agents only, grouped by category \u2014 realtime (voice) agents are interactive-only and can't be scheduled.</div>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-message\">Message sent on each run</label>\n <!-- Composer mention editor in DISCOVERY mode: trigger providers are ClassFactory-\n discovered (ng-conversations registers '@' agent / '#' record / '/' skill plugins\n when loaded). '@' agent mentions are excluded \u2014 the routine's agent is fixed by\n the picker above. With no providers registered this degrades gracefully to a\n plain text editor. -->\n <mj-mention-editor id=\"routine-message\"\n [(ngModel)]=\"InitialMessage\"\n placeholder=\"The message the routine sends to the agent each time it runs\"\n [ExcludedTriggerKeys]=\"['agent-mentions']\"\n [Provider]=\"Provider\"\n [enableAttachments]=\"false\"\n [autoFocus]=\"false\"\n [currentUser]=\"ProviderToUse.CurrentUser\"></mj-mention-editor>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Frequency</label>\n <div class=\"editor-segmented editor-segmented--wrap\" role=\"radiogroup\" aria-label=\"Schedule frequency\">\n @for (option of ScheduleKindOptions; track option.Value) {\n <button type=\"button\" class=\"editor-segment\"\n [class.editor-segment--active]=\"ScheduleKind === option.Value\"\n (click)=\"SetScheduleKind(option.Value)\">\n {{ option.Label }}\n </button>\n }\n </div>\n </div>\n\n <div class=\"editor-schedule-detail\">\n @switch (ScheduleKind) {\n @case ('hourly') {\n <div class=\"editor-field editor-field--inline\">\n <label class=\"editor-label\">At minute</label>\n <mj-numeric-input [(ngModel)]=\"ScheduleMinute\" [Min]=\"0\" [Max]=\"59\" [Step]=\"5\"></mj-numeric-input>\n <span class=\"editor-hint-inline\">past every hour</span>\n </div>\n }\n @case ('daily') {\n <div class=\"editor-field editor-field--inline\">\n <label class=\"editor-label\">At</label>\n <input class=\"mj-input editor-time-input\" type=\"time\" [(ngModel)]=\"ScheduleTime\" />\n <span class=\"editor-hint-inline\">every day</span>\n </div>\n }\n @case ('weekly') {\n <div class=\"editor-field editor-field--inline\">\n <label class=\"editor-label\">Every</label>\n <mj-dropdown class=\"editor-inline-dropdown\" [Data]=\"DayOfWeekOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"ScheduleDayOfWeek\"></mj-dropdown>\n <label class=\"editor-label\">at</label>\n <input class=\"mj-input editor-time-input\" type=\"time\" [(ngModel)]=\"ScheduleTime\" />\n </div>\n }\n @case ('monthly') {\n <div class=\"editor-field editor-field--inline\">\n <label class=\"editor-label\">On day</label>\n <mj-dropdown class=\"editor-inline-dropdown\" [Data]=\"DayOfMonthOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"ScheduleDayOfMonth\"></mj-dropdown>\n <label class=\"editor-label\">at</label>\n <input class=\"mj-input editor-time-input\" type=\"time\" [(ngModel)]=\"ScheduleTime\" />\n </div>\n }\n @case ('advanced') {\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-cron\">Cron expression</label>\n <input id=\"routine-cron\" class=\"mj-input editor-mono\" type=\"text\" [(ngModel)]=\"RawCron\"\n placeholder=\"minute hour day-of-month month day-of-week\" />\n </div>\n }\n }\n <div class=\"editor-schedule-preview\">\n <i class=\"fa-solid fa-calendar-check\"></i> {{ SchedulePreview || 'No schedule yet' }}\n </div>\n </div>\n </section>\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ADVANCED (progressive disclosure \u2014 collapsed by default) \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <button type=\"button\" class=\"editor-advanced-toggle\" (click)=\"ShowAdvanced = !ShowAdvanced\"\n [attr.aria-expanded]=\"ShowAdvanced\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"!ShowAdvanced\" [class.fa-chevron-down]=\"ShowAdvanced\"></i>\n Advanced options\n <span class=\"editor-hint-inline\">description \u00B7 monitoring \u00B7 timezone \u00B7 window \u00B7 payload \u00B7 skills \u00B7 notifications</span>\n </button>\n\n @if (ShowAdvanced) {\n <section class=\"editor-section\">\n <h3 class=\"editor-section-title\"><i class=\"fa-solid fa-circle-info\"></i> Details</h3>\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-description\">Description</label>\n <textarea id=\"routine-description\" class=\"mj-textarea\" rows=\"2\" [(ngModel)]=\"Description\"\n placeholder=\"What does this routine do?\"></textarea>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Routine type</label>\n <div class=\"editor-segmented\" role=\"radiogroup\" aria-label=\"Routine type\">\n <button type=\"button\" class=\"editor-segment\"\n [class.editor-segment--active]=\"RoutineType === 'Scheduled'\"\n (click)=\"RoutineType = 'Scheduled'\">\n <i class=\"fa-solid fa-clock\"></i> Scheduled\n </button>\n <button type=\"button\" class=\"editor-segment\"\n [class.editor-segment--active]=\"RoutineType === 'Monitoring'\"\n (click)=\"RoutineType = 'Monitoring'\">\n <i class=\"fa-solid fa-eye\"></i> Monitoring\n </button>\n </div>\n <div class=\"editor-hint\">{{ RoutineTypeHelp }}</div>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Timezone</label>\n <mj-combobox\n [Data]=\"TimezoneOptions\"\n [ValuePrimitive]=\"true\"\n Placeholder=\"Select an IANA timezone...\"\n [(ngModel)]=\"Timezone\">\n </mj-combobox>\n </div>\n\n <div class=\"editor-field-row\">\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-startat\">Active from (optional)</label>\n <input id=\"routine-startat\" class=\"mj-input\" type=\"datetime-local\" [(ngModel)]=\"StartAtLocal\" />\n </div>\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-endat\">Active until (optional)</label>\n <input id=\"routine-endat\" class=\"mj-input\" type=\"datetime-local\" [(ngModel)]=\"EndAtLocal\" />\n </div>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Starting payload (JSON, optional)</label>\n <div class=\"editor-code\">\n <mj-code-editor [(ngModel)]=\"StartingPayloadText\" language=\"json\"\n placeholder='{ \"example\": true }'></mj-code-editor>\n </div>\n <div class=\"editor-hint\">Passed to the agent on each run. Leave blank for none.</div>\n </div>\n\n @if (SkillOptions.length > 0) {\n <div class=\"editor-field\">\n <label class=\"editor-label\">Pre-activate skills (optional)</label>\n <div class=\"editor-skills\">\n @for (skill of SkillOptions; track skill.ID) {\n <button type=\"button\" class=\"editor-skill-chip\"\n [class.editor-skill-chip--selected]=\"IsSkillSelected(skill.ID)\"\n [title]=\"skill.Description ?? skill.Name\"\n (click)=\"ToggleSkill(skill.ID)\">\n <i [class]=\"skill.IconClass || 'fa-solid fa-wand-magic-sparkles'\"></i>\n {{ skill.Name }}\n @if (IsSkillSelected(skill.ID)) {\n <i class=\"fa-solid fa-check editor-skill-check\"></i>\n }\n </button>\n }\n </div>\n <div class=\"editor-hint\">Selected skills start every run with their instructions and tools in effect (subject to the agent's skill gates).</div>\n </div>\n }\n </section>\n\n <section class=\"editor-section\">\n <h3 class=\"editor-section-title\"><i class=\"fa-solid fa-bell\"></i> Notifications</h3>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Notify me</label>\n <mj-dropdown [Data]=\"NotifyConditionOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"NotifyCondition\"></mj-dropdown>\n </div>\n\n <div class=\"editor-field editor-field--inline editor-switches\">\n <mj-switch [(ngModel)]=\"NotifyViaInApp\" OnLabel=\"In-app\" OffLabel=\"In-app\"></mj-switch>\n <mj-switch [(ngModel)]=\"NotifyViaEmail\" OnLabel=\"Email\" OffLabel=\"Email\"></mj-switch>\n </div>\n\n <div class=\"editor-field\">\n <div class=\"editor-recipients-header\">\n <label class=\"editor-label\">Additional recipients</label>\n <button mjButton variant=\"outline\" size=\"sm\" (click)=\"AddRecipient()\">\n <i class=\"fa-solid fa-plus\"></i> Add recipient\n </button>\n </div>\n @if (Recipients.length === 0) {\n <div class=\"editor-hint\">Only you (the owner) will be notified.</div>\n }\n @for (row of Recipients; track $index; let i = $index; let first = $first; let last = $last) {\n <div class=\"editor-recipient-row\">\n <div class=\"editor-recipient-order\">\n <button mjButton variant=\"icon\" size=\"sm\" title=\"Move up\" [disabled]=\"first\" (click)=\"MoveRecipient(i, -1)\">\n <i class=\"fa-solid fa-chevron-up\"></i>\n </button>\n <button mjButton variant=\"icon\" size=\"sm\" title=\"Move down\" [disabled]=\"last\" (click)=\"MoveRecipient(i, 1)\">\n <i class=\"fa-solid fa-chevron-down\"></i>\n </button>\n </div>\n <mj-dropdown class=\"editor-recipient-mode\" [Data]=\"RecipientModeOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"row.Mode\" (ngModelChange)=\"OnRecipientModeChange(row)\"></mj-dropdown>\n @if (row.Mode === 'user') {\n <mj-combobox class=\"editor-recipient-target\" [Data]=\"UserOptions\" TextField=\"Name\" ValueField=\"ID\"\n [ValuePrimitive]=\"true\" Placeholder=\"Select a user...\" [(ngModel)]=\"row.UserID\"></mj-combobox>\n } @else {\n <input class=\"mj-input editor-recipient-target\" type=\"email\" placeholder=\"name@example.com\" [(ngModel)]=\"row.Email\" />\n }\n <mj-dropdown class=\"editor-recipient-channel\" [Data]=\"ChannelOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"row.Channel\"></mj-dropdown>\n <button mjButton variant=\"icon\" size=\"sm\" title=\"Remove recipient\" (click)=\"RemoveRecipient(i)\">\n <i class=\"fa-solid fa-trash-can\"></i>\n </button>\n </div>\n }\n </div>\n </section>\n }\n\n <!-- ======================= Footer (confirm LEFT, cancel RIGHT) ======================= -->\n <div class=\"editor-footer\">\n <button mjButton variant=\"primary\" size=\"md\" [disabled]=\"IsSaving\" (click)=\"Save()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n }\n {{ IsEdit ? 'Save Changes' : 'Create Routine' }}\n </button>\n <button mjButton variant=\"secondary\" size=\"md\" [disabled]=\"IsSaving\" (click)=\"Cancel()\">Cancel</button>\n </div>\n </div>\n}\n", styles: [":host {\n display: block;\n height: 100%;\n}\n\n.editor-loading {\n display: flex;\n justify-content: center;\n padding: 48px 0;\n}\n\n.routine-editor {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 4px 2px 0 2px;\n}\n\n.editor-errors {\n margin: 0;\n padding-left: 18px;\n}\n\n.editor-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-lg, 10px);\n}\n\n.editor-section-title {\n margin: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.editor-section-title > i {\n color: var(--mj-brand-primary);\n}\n\n.editor-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.editor-field--inline {\n flex-direction: row;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.editor-field-row {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.editor-field-row > .editor-field {\n flex: 1 1 220px;\n}\n\n.editor-label {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.editor-required {\n color: var(--mj-status-error);\n}\n\n.editor-hint {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.editor-hint-inline {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n/* Segmented pickers (target type / routine type / frequency) */\n.editor-segmented {\n display: inline-flex;\n gap: 0;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n overflow: hidden;\n width: fit-content;\n}\n\n.editor-segmented--wrap {\n flex-wrap: wrap;\n}\n\n.editor-segment {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 14px;\n font-size: 13px;\n border: none;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.editor-segment + .editor-segment {\n border-left: 1px solid var(--mj-border-default);\n}\n\n.editor-segment:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.editor-segment--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* Schedule */\n.editor-schedule-detail {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-md, 8px);\n}\n\n.editor-schedule-preview {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.editor-schedule-preview > i {\n color: var(--mj-status-success);\n}\n\n.editor-time-input {\n width: 130px;\n}\n\n.editor-inline-dropdown {\n min-width: 140px;\n}\n\n.editor-mono {\n font-family: var(--mj-font-mono, monospace);\n}\n\n/* Code editor container */\n.editor-code {\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n overflow: hidden;\n min-height: 90px;\n}\n\n/* Skills */\n.editor-skills {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.editor-skill-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n font-size: 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 999px);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;\n}\n\n.editor-skill-chip:hover {\n border-color: var(--mj-border-strong);\n}\n\n.editor-skill-chip--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.editor-skill-check {\n font-size: 10px;\n}\n\n/* Notifications */\n.editor-switches {\n gap: 24px;\n}\n\n.editor-recipients-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n\n.editor-recipient-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface);\n}\n\n.editor-recipient-order {\n display: flex;\n flex-direction: column;\n}\n\n.editor-recipient-mode {\n flex: 0 0 150px;\n}\n\n.editor-recipient-target {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.editor-recipient-channel {\n flex: 0 0 120px;\n}\n\n/* Footer \u2014 confirm on the LEFT, cancel on the RIGHT (MJ convention) */\n.editor-footer {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 0 4px 0;\n border-top: 1px solid var(--mj-border-default);\n position: sticky;\n bottom: 0;\n background: var(--mj-bg-surface);\n}\n\n/* Agent tree picker */\n.editor-selected-agent {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md, 8px);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 13px;\n font-weight: 600;\n width: fit-content;\n}\n\n.editor-selected-agent-hint {\n font-size: 11px;\n font-weight: 400;\n color: var(--mj-text-muted);\n}\n\n.editor-agent-tree {\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n max-height: 280px;\n overflow: auto;\n background: var(--mj-bg-surface);\n}\n\n/* Progressive-disclosure toggle between the basic path and the advanced sections */\n.editor-advanced-toggle {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 12px;\n border: 1px dashed var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n text-align: left;\n}\n\n.editor-advanced-toggle:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.editor-advanced-toggle .editor-hint-inline {\n font-weight: 400;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n"] }]
|
|
1058
|
+
}], null, { RoutineID: [{
|
|
1059
|
+
type: Input
|
|
1060
|
+
}], Saved: [{
|
|
1061
|
+
type: Output
|
|
1062
|
+
}], Cancelled: [{
|
|
1063
|
+
type: Output
|
|
1064
|
+
}], BeforeRoutineCreated: [{
|
|
1065
|
+
type: Output
|
|
1066
|
+
}], AfterRoutineCreated: [{
|
|
1067
|
+
type: Output
|
|
1068
|
+
}] }); })();
|
|
1069
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(NewRoutineComponent, { className: "NewRoutineComponent", filePath: "src/lib/new-routine.component.ts", lineNumber: 69 }); })();
|
|
1070
|
+
//# sourceMappingURL=new-routine.component.js.map
|