@memberjunction/ng-conversations 5.41.0 → 5.42.0
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/__tests__/remote-browser-channel.test.js +163 -1
- package/dist/__tests__/remote-browser-channel.test.js.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.d.ts +105 -2
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.js +1378 -489
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +4 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +13 -8
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.d.ts +98 -5
- package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.js +1102 -401
- package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.js +1 -1
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.d.ts +5 -1
- package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -1
- package/dist/lib/components/project/project-form-modal.component.js +104 -85
- package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +22 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +40 -0
- package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +12 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +97 -19
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +33 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +164 -7
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +35 -2
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +67 -4
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts +1 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-tools.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js +13 -0
- package/dist/lib/components/realtime/remote-browser/remote-browser-tools.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +4 -0
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +13 -8
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/services/artifact-state.service.d.ts +1 -1
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +7 -2
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/realtime-pairing.d.ts +8 -7
- package/dist/lib/services/realtime-pairing.d.ts.map +1 -1
- package/dist/lib/services/realtime-pairing.js +19 -9
- package/dist/lib/services/realtime-pairing.js.map +1 -1
- package/package.json +26 -26
|
@@ -16,12 +16,16 @@ export declare class ProjectFormModalComponent extends BaseAngularComponent impl
|
|
|
16
16
|
project: MJProjectEntity | null;
|
|
17
17
|
environmentId: string;
|
|
18
18
|
currentUser: UserInfo;
|
|
19
|
+
/** When creating a new folder, the parent folder ID for nesting (null = top level). */
|
|
20
|
+
parentId: string | null;
|
|
19
21
|
projectSaved: EventEmitter<MJProjectEntity>;
|
|
20
22
|
formData: ProjectFormData;
|
|
21
23
|
showNameError: boolean;
|
|
22
24
|
isEditMode: boolean;
|
|
23
25
|
availableColors: string[];
|
|
24
26
|
availableIcons: string[];
|
|
27
|
+
/** Translucent tint of the selected color, used behind the preview/icon glyph. */
|
|
28
|
+
get chipBackground(): string;
|
|
25
29
|
constructor(cdr: ChangeDetectorRef);
|
|
26
30
|
ngOnInit(): void;
|
|
27
31
|
private loadProjectData;
|
|
@@ -30,6 +34,6 @@ export declare class ProjectFormModalComponent extends BaseAngularComponent impl
|
|
|
30
34
|
onSave(): Promise<void>;
|
|
31
35
|
onCancel(): void;
|
|
32
36
|
static ɵfac: i0.ɵɵFactoryDeclaration<ProjectFormModalComponent, never>;
|
|
33
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<ProjectFormModalComponent, "mj-project-form-modal", never, { "dialogRef": { "alias": "dialogRef"; "required": false; }; "project": { "alias": "project"; "required": false; }; "environmentId": { "alias": "environmentId"; "required": false; }; "currentUser": { "alias": "currentUser"; "required": false; }; }, { "projectSaved": "projectSaved"; }, never, never, false, never>;
|
|
37
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ProjectFormModalComponent, "mj-project-form-modal", never, { "dialogRef": { "alias": "dialogRef"; "required": false; }; "project": { "alias": "project"; "required": false; }; "environmentId": { "alias": "environmentId"; "required": false; }; "currentUser": { "alias": "currentUser"; "required": false; }; "parentId": { "alias": "parentId"; "required": false; }; }, { "projectSaved": "projectSaved"; }, never, never, false, never>;
|
|
34
38
|
}
|
|
35
39
|
//# sourceMappingURL=project-form-modal.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-form-modal.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/project/project-form-modal.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAa,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAY,MAAM,sBAAsB,CAAC;;AAE1D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAgDD,
|
|
1
|
+
{"version":3,"file":"project-form-modal.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/project/project-form-modal.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAa,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAY,MAAM,sBAAsB,CAAC;;AAE1D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAgDD,qBAkSa,yBAA0B,SAAQ,oBAAqB,YAAW,MAAM;IA6BvE,OAAO,CAAC,GAAG;IA5Bd,SAAS,EAAG,WAAW,CAAC;IACxB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAQ;IACvC,aAAa,EAAG,MAAM,CAAC;IACvB,WAAW,EAAG,QAAQ,CAAC;IAChC,uFAAuF;IAC9E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE9B,YAAY,gCAAuC;IAEtD,QAAQ,EAAE,eAAe,CAK9B;IAEK,aAAa,UAAS;IACtB,UAAU,UAAS;IACnB,eAAe,WAA0B;IACzC,cAAc,WAAyB;IAE9C,kFAAkF;IAClF,IAAW,cAAc,IAAI,MAAM,CAIlC;gBAEmB,GAAG,EAAE,iBAAiB;IAG1C,QAAQ,IAAI,IAAI;IAQhB,OAAO,CAAC,eAAe;IAWvB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKhC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC7B,QAAQ,IAAI,IAAI;yCArGL,yBAAyB;2CAAzB,yBAAyB;CAwGrC"}
|
|
@@ -3,15 +3,15 @@ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
import * as i1 from "@angular/forms";
|
|
5
5
|
import * as i2 from "@memberjunction/ng-ui-components";
|
|
6
|
-
function
|
|
7
|
-
i0.ɵɵelementStart(0, "div",
|
|
8
|
-
i0.ɵɵtext(1, "
|
|
6
|
+
function ProjectFormModalComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
7
|
+
i0.ɵɵelementStart(0, "div", 8);
|
|
8
|
+
i0.ɵɵtext(1, "Folder name is required");
|
|
9
9
|
i0.ɵɵelementEnd();
|
|
10
10
|
} }
|
|
11
|
-
function
|
|
11
|
+
function ProjectFormModalComponent_For_22_Template(rf, ctx) { if (rf & 1) {
|
|
12
12
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
13
|
-
i0.ɵɵelementStart(0, "button",
|
|
14
|
-
i0.ɵɵlistener("click", function
|
|
13
|
+
i0.ɵɵelementStart(0, "button", 22);
|
|
14
|
+
i0.ɵɵlistener("click", function ProjectFormModalComponent_For_22_Template_button_click_0_listener() { const color_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.selectColor(color_r2)); });
|
|
15
15
|
i0.ɵɵelementEnd();
|
|
16
16
|
} if (rf & 2) {
|
|
17
17
|
const color_r2 = ctx.$implicit;
|
|
@@ -22,13 +22,14 @@ function ProjectFormModalComponent_For_17_Template(rf, ctx) { if (rf & 1) {
|
|
|
22
22
|
} }
|
|
23
23
|
function ProjectFormModalComponent_For_34_Template(rf, ctx) { if (rf & 1) {
|
|
24
24
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
25
|
-
i0.ɵɵelementStart(0, "button",
|
|
25
|
+
i0.ɵɵelementStart(0, "button", 23);
|
|
26
26
|
i0.ɵɵlistener("click", function ProjectFormModalComponent_For_34_Template_button_click_0_listener() { const icon_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.selectIcon(icon_r5)); });
|
|
27
27
|
i0.ɵɵelement(1, "i");
|
|
28
28
|
i0.ɵɵelementEnd();
|
|
29
29
|
} if (rf & 2) {
|
|
30
30
|
const icon_r5 = ctx.$implicit;
|
|
31
31
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
32
|
+
i0.ɵɵstyleProp("color", ctx_r2.formData.icon === icon_r5 ? ctx_r2.formData.color : null);
|
|
32
33
|
i0.ɵɵclassProp("selected", ctx_r2.formData.icon === icon_r5);
|
|
33
34
|
i0.ɵɵproperty("title", icon_r5);
|
|
34
35
|
i0.ɵɵadvance();
|
|
@@ -84,6 +85,8 @@ export class ProjectFormModalComponent extends BaseAngularComponent {
|
|
|
84
85
|
project = null;
|
|
85
86
|
environmentId;
|
|
86
87
|
currentUser;
|
|
88
|
+
/** When creating a new folder, the parent folder ID for nesting (null = top level). */
|
|
89
|
+
parentId = null;
|
|
87
90
|
projectSaved = new EventEmitter();
|
|
88
91
|
formData = {
|
|
89
92
|
name: '',
|
|
@@ -95,6 +98,12 @@ export class ProjectFormModalComponent extends BaseAngularComponent {
|
|
|
95
98
|
isEditMode = false;
|
|
96
99
|
availableColors = DEFAULT_PROJECT_COLORS;
|
|
97
100
|
availableIcons = DEFAULT_PROJECT_ICONS;
|
|
101
|
+
/** Translucent tint of the selected color, used behind the preview/icon glyph. */
|
|
102
|
+
get chipBackground() {
|
|
103
|
+
const hex = this.formData.color || '#0076B6';
|
|
104
|
+
// 8-digit hex (#RRGGBBAA) — ~14% alpha tint of the chosen color
|
|
105
|
+
return /^#[0-9a-fA-F]{6}$/.test(hex) ? `${hex}24` : hex;
|
|
106
|
+
}
|
|
98
107
|
constructor(cdr) {
|
|
99
108
|
super();
|
|
100
109
|
this.cdr = cdr;
|
|
@@ -141,6 +150,9 @@ export class ProjectFormModalComponent extends BaseAngularComponent {
|
|
|
141
150
|
if (!this.isEditMode) {
|
|
142
151
|
project.EnvironmentID = this.environmentId;
|
|
143
152
|
project.IsArchived = false;
|
|
153
|
+
if (this.parentId) {
|
|
154
|
+
project.ParentID = this.parentId;
|
|
155
|
+
}
|
|
144
156
|
}
|
|
145
157
|
const saved = await project.Save();
|
|
146
158
|
if (saved) {
|
|
@@ -160,64 +172,71 @@ export class ProjectFormModalComponent extends BaseAngularComponent {
|
|
|
160
172
|
this.dialogRef.Close();
|
|
161
173
|
}
|
|
162
174
|
static ɵfac = function ProjectFormModalComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ProjectFormModalComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
163
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ProjectFormModalComponent, selectors: [["mj-project-form-modal"]], inputs: { dialogRef: "dialogRef", project: "project", environmentId: "environmentId", currentUser: "currentUser" }, outputs: { projectSaved: "projectSaved" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 40, vars:
|
|
175
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ProjectFormModalComponent, selectors: [["mj-project-form-modal"]], inputs: { dialogRef: "dialogRef", project: "project", environmentId: "environmentId", currentUser: "currentUser", parentId: "parentId" }, outputs: { projectSaved: "projectSaved" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 40, vars: 18, consts: [[3, "Close", "Title", "Width", "MinWidth", "Visible"], [1, "project-form"], [1, "folder-preview"], [1, "folder-preview-chip"], [1, "folder-preview-name"], [1, "form-field"], ["for", "projectName", 1, "required"], ["id", "projectName", "type", "text", "placeholder", "e.g. Client work, Research, Ideas", "autofocus", "", 1, "mj-input", "full-width", 3, "ngModelChange", "keydown.enter", "ngModel"], [1, "error-message"], ["for", "projectDescription"], ["id", "projectDescription", "placeholder", "What goes in this folder? (optional)", "rows", "2", 1, "mj-textarea", "full-width", 3, "ngModelChange", "ngModel"], [1, "color-picker-section"], [1, "color-palette"], ["type", "button", 1, "color-swatch", 3, "selected", "backgroundColor", "title"], [1, "custom-color-input"], ["for", "customColor"], ["id", "customColor", "type", "color", 1, "custom-color-picker", 3, "ngModelChange", "ngModel"], [1, "color-value"], [1, "icon-grid"], ["type", "button", 1, "icon-option", 3, "selected", "color", "title"], ["mjButton", "", "variant", "primary", 3, "click"], ["mjButton", "", 3, "click"], ["type", "button", 1, "color-swatch", 3, "click", "title"], ["type", "button", 1, "icon-option", 3, "click", "title"]], template: function ProjectFormModalComponent_Template(rf, ctx) { if (rf & 1) {
|
|
164
176
|
i0.ɵɵelementStart(0, "mj-dialog", 0);
|
|
165
177
|
i0.ɵɵlistener("Close", function ProjectFormModalComponent_Template_mj_dialog_Close_0_listener() { return ctx.onCancel(); });
|
|
166
|
-
i0.ɵɵelementStart(1, "div", 1)(2, "div", 2)(3, "
|
|
167
|
-
i0.ɵɵ
|
|
178
|
+
i0.ɵɵelementStart(1, "div", 1)(2, "div", 2)(3, "span", 3);
|
|
179
|
+
i0.ɵɵelement(4, "i");
|
|
180
|
+
i0.ɵɵelementEnd();
|
|
181
|
+
i0.ɵɵelementStart(5, "span", 4);
|
|
182
|
+
i0.ɵɵtext(6);
|
|
183
|
+
i0.ɵɵelementEnd()();
|
|
184
|
+
i0.ɵɵelementStart(7, "div", 5)(8, "label", 6);
|
|
185
|
+
i0.ɵɵtext(9, " Folder Name ");
|
|
168
186
|
i0.ɵɵelementEnd();
|
|
169
|
-
i0.ɵɵelementStart(
|
|
170
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
171
|
-
i0.ɵɵlistener("keydown.enter", function
|
|
187
|
+
i0.ɵɵelementStart(10, "input", 7);
|
|
188
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ProjectFormModalComponent_Template_input_ngModelChange_10_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.formData.name, $event) || (ctx.formData.name = $event); return $event; });
|
|
189
|
+
i0.ɵɵlistener("keydown.enter", function ProjectFormModalComponent_Template_input_keydown_enter_10_listener() { return ctx.onSave(); });
|
|
172
190
|
i0.ɵɵelementEnd();
|
|
173
|
-
i0.ɵɵconditionalCreate(
|
|
191
|
+
i0.ɵɵconditionalCreate(11, ProjectFormModalComponent_Conditional_11_Template, 2, 0, "div", 8);
|
|
174
192
|
i0.ɵɵelementEnd();
|
|
175
|
-
i0.ɵɵelementStart(
|
|
176
|
-
i0.ɵɵtext(
|
|
193
|
+
i0.ɵɵelementStart(12, "div", 5)(13, "label", 9);
|
|
194
|
+
i0.ɵɵtext(14, " Description ");
|
|
177
195
|
i0.ɵɵelementEnd();
|
|
178
|
-
i0.ɵɵelementStart(
|
|
179
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
196
|
+
i0.ɵɵelementStart(15, "textarea", 10);
|
|
197
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ProjectFormModalComponent_Template_textarea_ngModelChange_15_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.formData.description, $event) || (ctx.formData.description = $event); return $event; });
|
|
180
198
|
i0.ɵɵelementEnd()();
|
|
181
|
-
i0.ɵɵelementStart(
|
|
182
|
-
i0.ɵɵtext(
|
|
199
|
+
i0.ɵɵelementStart(16, "div", 5)(17, "label");
|
|
200
|
+
i0.ɵɵtext(18, "Color");
|
|
183
201
|
i0.ɵɵelementEnd();
|
|
184
|
-
i0.ɵɵelementStart(
|
|
185
|
-
i0.ɵɵrepeaterCreate(
|
|
202
|
+
i0.ɵɵelementStart(19, "div", 11)(20, "div", 12);
|
|
203
|
+
i0.ɵɵrepeaterCreate(21, ProjectFormModalComponent_For_22_Template, 1, 5, "button", 13, i0.ɵɵrepeaterTrackByIdentity);
|
|
186
204
|
i0.ɵɵelementEnd();
|
|
187
|
-
i0.ɵɵelementStart(
|
|
188
|
-
i0.ɵɵtext(
|
|
205
|
+
i0.ɵɵelementStart(23, "div", 14)(24, "label", 15);
|
|
206
|
+
i0.ɵɵtext(25, "Custom:");
|
|
189
207
|
i0.ɵɵelementEnd();
|
|
190
|
-
i0.ɵɵelementStart(
|
|
191
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
208
|
+
i0.ɵɵelementStart(26, "input", 16);
|
|
209
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ProjectFormModalComponent_Template_input_ngModelChange_26_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.formData.color, $event) || (ctx.formData.color = $event); return $event; });
|
|
192
210
|
i0.ɵɵelementEnd();
|
|
193
|
-
i0.ɵɵelementStart(
|
|
194
|
-
i0.ɵɵtext(
|
|
211
|
+
i0.ɵɵelementStart(27, "span", 17);
|
|
212
|
+
i0.ɵɵtext(28);
|
|
195
213
|
i0.ɵɵelementEnd()()()();
|
|
196
|
-
i0.ɵɵelementStart(
|
|
197
|
-
i0.ɵɵtext(
|
|
214
|
+
i0.ɵɵelementStart(29, "div", 5)(30, "label");
|
|
215
|
+
i0.ɵɵtext(31, "Icon");
|
|
198
216
|
i0.ɵɵelementEnd();
|
|
199
|
-
i0.ɵɵelementStart(
|
|
200
|
-
i0.ɵɵ
|
|
201
|
-
i0.ɵɵ
|
|
202
|
-
i0.ɵɵ
|
|
203
|
-
i0.ɵɵ
|
|
204
|
-
i0.ɵɵ
|
|
205
|
-
i0.ɵɵrepeaterCreate(33, ProjectFormModalComponent_For_34_Template, 2, 6, "button", 18, i0.ɵɵrepeaterTrackByIdentity);
|
|
206
|
-
i0.ɵɵelementEnd()()()();
|
|
207
|
-
i0.ɵɵelementStart(35, "mj-dialog-actions")(36, "button", 19);
|
|
208
|
-
i0.ɵɵlistener("click", function ProjectFormModalComponent_Template_button_click_36_listener() { return ctx.onCancel(); });
|
|
209
|
-
i0.ɵɵtext(37, "Cancel");
|
|
217
|
+
i0.ɵɵelementStart(32, "div", 18);
|
|
218
|
+
i0.ɵɵrepeaterCreate(33, ProjectFormModalComponent_For_34_Template, 2, 8, "button", 19, i0.ɵɵrepeaterTrackByIdentity);
|
|
219
|
+
i0.ɵɵelementEnd()()();
|
|
220
|
+
i0.ɵɵelementStart(35, "mj-dialog-actions")(36, "button", 20);
|
|
221
|
+
i0.ɵɵlistener("click", function ProjectFormModalComponent_Template_button_click_36_listener() { return ctx.onSave(); });
|
|
222
|
+
i0.ɵɵtext(37);
|
|
210
223
|
i0.ɵɵelementEnd();
|
|
211
|
-
i0.ɵɵelementStart(38, "button",
|
|
212
|
-
i0.ɵɵlistener("click", function ProjectFormModalComponent_Template_button_click_38_listener() { return ctx.
|
|
213
|
-
i0.ɵɵtext(39);
|
|
224
|
+
i0.ɵɵelementStart(38, "button", 21);
|
|
225
|
+
i0.ɵɵlistener("click", function ProjectFormModalComponent_Template_button_click_38_listener() { return ctx.onCancel(); });
|
|
226
|
+
i0.ɵɵtext(39, "Cancel");
|
|
214
227
|
i0.ɵɵelementEnd()()();
|
|
215
228
|
} if (rf & 2) {
|
|
216
|
-
i0.ɵɵproperty("Title", ctx.isEditMode ? "Edit
|
|
217
|
-
i0.ɵɵadvance(
|
|
229
|
+
i0.ɵɵproperty("Title", ctx.isEditMode ? "Edit Folder" : "New Folder")("Width", 560)("MinWidth", 400)("Visible", true);
|
|
230
|
+
i0.ɵɵadvance(3);
|
|
231
|
+
i0.ɵɵstyleProp("background-color", ctx.chipBackground)("color", ctx.formData.color);
|
|
232
|
+
i0.ɵɵadvance();
|
|
233
|
+
i0.ɵɵclassMap(i0.ɵɵinterpolate1("fa-solid ", ctx.formData.icon));
|
|
234
|
+
i0.ɵɵadvance(2);
|
|
235
|
+
i0.ɵɵtextInterpolate(ctx.formData.name.trim() || "Untitled folder");
|
|
236
|
+
i0.ɵɵadvance(4);
|
|
218
237
|
i0.ɵɵtwoWayProperty("ngModel", ctx.formData.name);
|
|
219
238
|
i0.ɵɵadvance();
|
|
220
|
-
i0.ɵɵconditional(ctx.showNameError ?
|
|
239
|
+
i0.ɵɵconditional(ctx.showNameError ? 11 : -1);
|
|
221
240
|
i0.ɵɵadvance(4);
|
|
222
241
|
i0.ɵɵtwoWayProperty("ngModel", ctx.formData.description);
|
|
223
242
|
i0.ɵɵadvance(6);
|
|
@@ -226,43 +245,46 @@ export class ProjectFormModalComponent extends BaseAngularComponent {
|
|
|
226
245
|
i0.ɵɵtwoWayProperty("ngModel", ctx.formData.color);
|
|
227
246
|
i0.ɵɵadvance(2);
|
|
228
247
|
i0.ɵɵtextInterpolate(ctx.formData.color);
|
|
229
|
-
i0.ɵɵadvance(
|
|
230
|
-
i0.ɵɵclassMap(i0.ɵɵinterpolate1("fa-solid ", ctx.formData.icon));
|
|
231
|
-
i0.ɵɵstyleProp("color", ctx.formData.color);
|
|
232
|
-
i0.ɵɵadvance(2);
|
|
233
|
-
i0.ɵɵtextInterpolate(ctx.formData.icon);
|
|
234
|
-
i0.ɵɵadvance(2);
|
|
248
|
+
i0.ɵɵadvance(5);
|
|
235
249
|
i0.ɵɵrepeater(ctx.availableIcons);
|
|
236
|
-
i0.ɵɵadvance(
|
|
237
|
-
i0.ɵɵtextInterpolate1(" ", ctx.isEditMode ? "Save" : "Create", " ");
|
|
238
|
-
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJButtonDirective, i2.MJDialogComponent, i2.MJDialogActionsComponent], styles: [".project-form[_ngcontent-%COMP%] {\n padding:
|
|
250
|
+
i0.ɵɵadvance(4);
|
|
251
|
+
i0.ɵɵtextInterpolate1(" ", ctx.isEditMode ? "Save Changes" : "Create Folder", " ");
|
|
252
|
+
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJButtonDirective, i2.MJDialogComponent, i2.MJDialogActionsComponent], styles: [".project-form[_ngcontent-%COMP%] {\n padding: 20px 24px 8px;\n display: flex;\n flex-direction: column;\n gap: 22px;\n }\n\n \n\n .folder-preview[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n }\n .folder-preview-chip[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n transition: background-color 150ms ease, color 150ms ease;\n }\n .folder-preview-name[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .form-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .form-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 13px;\n letter-spacing: 0.01em;\n color: var(--mj-text-secondary);\n }\n\n .form-field[_ngcontent-%COMP%] label.required[_ngcontent-%COMP%]::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 4px;\n }\n\n .full-width[_ngcontent-%COMP%] { width: 100%; }\n\n .error-message[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-size: 12px;\n }\n\n \n\n .color-picker-section[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 14px;\n background: var(--mj-bg-surface);\n }\n\n .color-palette[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .color-swatch[_ngcontent-%COMP%] {\n width: 100%;\n aspect-ratio: 1;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n padding: 0;\n transition: transform 120ms ease, box-shadow 120ms ease;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n }\n\n .color-swatch[_ngcontent-%COMP%]:hover {\n transform: scale(1.12);\n }\n\n .color-swatch.selected[_ngcontent-%COMP%] {\n box-shadow: 0 0 0 2px var(--mj-bg-surface), 0 0 0 4px var(--mj-brand-primary);\n }\n\n .custom-color-input[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding-top: 14px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .custom-color-input[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n }\n\n .custom-color-picker[_ngcontent-%COMP%] {\n width: 44px;\n height: 30px;\n padding: 2px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n background: var(--mj-bg-surface);\n }\n\n .color-value[_ngcontent-%COMP%] {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 13px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n }\n\n \n\n .icon-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n max-height: 184px;\n overflow-y: auto;\n padding: 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n }\n\n .icon-option[_ngcontent-%COMP%] {\n aspect-ratio: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;\n }\n\n .icon-option[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n transform: translateY(-1px);\n }\n\n .icon-option.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 box-shadow: 0 0 0 1px var(--mj-brand-primary);\n }\n\n .icon-option[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 17px; }\n\n \n\n .icon-grid[_ngcontent-%COMP%]::-webkit-scrollbar { width: 8px; }\n .icon-grid[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: transparent;\n }\n .icon-grid[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n }\n .icon-grid[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n }"] });
|
|
239
253
|
}
|
|
240
254
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ProjectFormModalComponent, [{
|
|
241
255
|
type: Component,
|
|
242
256
|
args: [{ standalone: false, selector: 'mj-project-form-modal', template: `
|
|
243
257
|
<mj-dialog
|
|
244
|
-
[Title]="isEditMode ? 'Edit
|
|
245
|
-
[Width]="
|
|
258
|
+
[Title]="isEditMode ? 'Edit Folder' : 'New Folder'"
|
|
259
|
+
[Width]="560"
|
|
246
260
|
[MinWidth]="400"
|
|
247
261
|
[Visible]="true"
|
|
248
262
|
(Close)="onCancel()">
|
|
249
263
|
|
|
250
264
|
<div class="project-form">
|
|
265
|
+
<!-- Live preview chip -->
|
|
266
|
+
<div class="folder-preview">
|
|
267
|
+
<span class="folder-preview-chip" [style.backgroundColor]="chipBackground" [style.color]="formData.color">
|
|
268
|
+
<i class="fa-solid {{ formData.icon }}"></i>
|
|
269
|
+
</span>
|
|
270
|
+
<span class="folder-preview-name">{{ formData.name.trim() || 'Untitled folder' }}</span>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
251
273
|
<!-- Name Input -->
|
|
252
274
|
<div class="form-field">
|
|
253
275
|
<label for="projectName" class="required">
|
|
254
|
-
|
|
276
|
+
Folder Name
|
|
255
277
|
</label>
|
|
256
278
|
<input
|
|
257
279
|
id="projectName"
|
|
258
280
|
type="text"
|
|
259
281
|
[(ngModel)]="formData.name"
|
|
260
|
-
placeholder="
|
|
261
|
-
class="mj-
|
|
282
|
+
placeholder="e.g. Client work, Research, Ideas"
|
|
283
|
+
class="mj-input full-width"
|
|
262
284
|
(keydown.enter)="onSave()"
|
|
263
285
|
autofocus />
|
|
264
286
|
@if (showNameError) {
|
|
265
|
-
<div class="error-message">
|
|
287
|
+
<div class="error-message">Folder name is required</div>
|
|
266
288
|
}
|
|
267
289
|
</div>
|
|
268
290
|
|
|
@@ -274,9 +296,9 @@ export class ProjectFormModalComponent extends BaseAngularComponent {
|
|
|
274
296
|
<textarea
|
|
275
297
|
id="projectDescription"
|
|
276
298
|
[(ngModel)]="formData.description"
|
|
277
|
-
placeholder="
|
|
299
|
+
placeholder="What goes in this folder? (optional)"
|
|
278
300
|
class="mj-textarea full-width"
|
|
279
|
-
rows="
|
|
301
|
+
rows="2"></textarea>
|
|
280
302
|
</div>
|
|
281
303
|
|
|
282
304
|
<!-- Color Picker -->
|
|
@@ -310,35 +332,30 @@ export class ProjectFormModalComponent extends BaseAngularComponent {
|
|
|
310
332
|
<!-- Icon Selector -->
|
|
311
333
|
<div class="form-field">
|
|
312
334
|
<label>Icon</label>
|
|
313
|
-
<div class="icon-
|
|
314
|
-
|
|
315
|
-
<
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
[title]="icon">
|
|
326
|
-
<i class="fa-solid {{ icon }}"></i>
|
|
327
|
-
</button>
|
|
328
|
-
}
|
|
329
|
-
</div>
|
|
335
|
+
<div class="icon-grid">
|
|
336
|
+
@for (icon of availableIcons; track icon) {
|
|
337
|
+
<button
|
|
338
|
+
type="button"
|
|
339
|
+
class="icon-option"
|
|
340
|
+
[class.selected]="formData.icon === icon"
|
|
341
|
+
[style.color]="formData.icon === icon ? formData.color : null"
|
|
342
|
+
(click)="selectIcon(icon)"
|
|
343
|
+
[title]="icon">
|
|
344
|
+
<i class="fa-solid {{ icon }}"></i>
|
|
345
|
+
</button>
|
|
346
|
+
}
|
|
330
347
|
</div>
|
|
331
348
|
</div>
|
|
332
349
|
</div>
|
|
333
350
|
|
|
334
351
|
<mj-dialog-actions>
|
|
335
|
-
<button mjButton (click)="onCancel()">Cancel</button>
|
|
336
352
|
<button mjButton variant="primary" (click)="onSave()">
|
|
337
|
-
{{ isEditMode ? 'Save' : 'Create' }}
|
|
353
|
+
{{ isEditMode ? 'Save Changes' : 'Create Folder' }}
|
|
338
354
|
</button>
|
|
355
|
+
<button mjButton (click)="onCancel()">Cancel</button>
|
|
339
356
|
</mj-dialog-actions>
|
|
340
357
|
</mj-dialog>
|
|
341
|
-
`, styles: ["\n .project-form {\n padding: 16px;\n }\n\n .
|
|
358
|
+
`, styles: ["\n .project-form {\n padding: 20px 24px 8px;\n display: flex;\n flex-direction: column;\n gap: 22px;\n }\n\n /* Live preview chip */\n .folder-preview {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n }\n .folder-preview-chip {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n transition: background-color 150ms ease, color 150ms ease;\n }\n .folder-preview-name {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .form-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .form-field label {\n font-weight: 600;\n font-size: 13px;\n letter-spacing: 0.01em;\n color: var(--mj-text-secondary);\n }\n\n .form-field label.required::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 4px;\n }\n\n .full-width { width: 100%; }\n\n .error-message {\n color: var(--mj-status-error);\n font-size: 12px;\n }\n\n /* Color Picker */\n .color-picker-section {\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 14px;\n background: var(--mj-bg-surface);\n }\n\n .color-palette {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .color-swatch {\n width: 100%;\n aspect-ratio: 1;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n padding: 0;\n transition: transform 120ms ease, box-shadow 120ms ease;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n }\n\n .color-swatch:hover {\n transform: scale(1.12);\n }\n\n .color-swatch.selected {\n box-shadow: 0 0 0 2px var(--mj-bg-surface), 0 0 0 4px var(--mj-brand-primary);\n }\n\n .custom-color-input {\n display: flex;\n align-items: center;\n gap: 10px;\n padding-top: 14px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .custom-color-input label {\n margin: 0;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n }\n\n .custom-color-picker {\n width: 44px;\n height: 30px;\n padding: 2px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n background: var(--mj-bg-surface);\n }\n\n .color-value {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 13px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n }\n\n /* Icon Selector */\n .icon-grid {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n max-height: 184px;\n overflow-y: auto;\n padding: 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n }\n\n .icon-option {\n aspect-ratio: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;\n }\n\n .icon-option:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n transform: translateY(-1px);\n }\n\n .icon-option.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 1px var(--mj-brand-primary);\n }\n\n .icon-option i { font-size: 17px; }\n\n /* Scrollbar */\n .icon-grid::-webkit-scrollbar { width: 8px; }\n .icon-grid::-webkit-scrollbar-track {\n background: transparent;\n }\n .icon-grid::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n }\n .icon-grid::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n }\n "] }]
|
|
342
359
|
}], () => [{ type: i0.ChangeDetectorRef }], { dialogRef: [{
|
|
343
360
|
type: Input
|
|
344
361
|
}], project: [{
|
|
@@ -347,8 +364,10 @@ export class ProjectFormModalComponent extends BaseAngularComponent {
|
|
|
347
364
|
type: Input
|
|
348
365
|
}], currentUser: [{
|
|
349
366
|
type: Input
|
|
367
|
+
}], parentId: [{
|
|
368
|
+
type: Input
|
|
350
369
|
}], projectSaved: [{
|
|
351
370
|
type: Output
|
|
352
371
|
}] }); })();
|
|
353
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ProjectFormModalComponent, { className: "ProjectFormModalComponent", filePath: "src/lib/components/project/project-form-modal.component.ts", lineNumber:
|
|
372
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ProjectFormModalComponent, { className: "ProjectFormModalComponent", filePath: "src/lib/components/project/project-form-modal.component.ts", lineNumber: 350 }); })();
|
|
354
373
|
//# sourceMappingURL=project-form-modal.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-form-modal.component.js","sourceRoot":"","sources":["../../../../src/lib/components/project/project-form-modal.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MJDialogRef } from '@memberjunction/ng-ui-components';\nimport { MJProjectEntity } from '@memberjunction/core-entities';\nimport { UserInfo, Metadata } from '@memberjunction/core';\n\nexport interface ProjectFormData {\n name: string;\n description: string;\n color: string;\n icon: string;\n}\n\nconst DEFAULT_PROJECT_COLORS = [\n '#0076B6', // MJ Blue\n '#F44336', // Red\n '#E91E63', // Pink\n '#9C27B0', // Purple\n '#673AB7', // Deep Purple\n '#3F51B5', // Indigo\n '#2196F3', // Blue\n '#03A9F4', // Light Blue\n '#00BCD4', // Cyan\n '#009688', // Teal\n '#4CAF50', // Green\n '#8BC34A', // Light Green\n '#CDDC39', // Lime\n '#FFEB3B', // Yellow\n '#FFC107', // Amber\n '#FF9800', // Orange\n '#FF5722', // Deep Orange\n '#795548', // Brown\n '#607D8B', // Blue Grey\n '#9E9E9E' // Grey\n];\n\nconst DEFAULT_PROJECT_ICONS = [\n 'fa-folder',\n 'fa-folder-open',\n 'fa-briefcase',\n 'fa-project-diagram',\n 'fa-chart-line',\n 'fa-tasks',\n 'fa-clipboard-list',\n 'fa-bullseye',\n 'fa-rocket',\n 'fa-lightbulb',\n 'fa-brain',\n 'fa-cogs',\n 'fa-code',\n 'fa-database',\n 'fa-server',\n 'fa-cloud',\n 'fa-mobile-alt',\n 'fa-desktop',\n 'fa-globe',\n 'fa-users'\n];\n\n@Component({\n standalone: false,\n selector: 'mj-project-form-modal',\n template: `\n <mj-dialog\n [Title]=\"isEditMode ? 'Edit Project' : 'New Project'\"\n [Width]=\"600\"\n [MinWidth]=\"400\"\n [Visible]=\"true\"\n (Close)=\"onCancel()\">\n\n <div class=\"project-form\">\n <!-- Name Input -->\n <div class=\"form-field\">\n <label for=\"projectName\" class=\"required\">\n Project Name\n </label>\n <input\n id=\"projectName\"\n type=\"text\"\n [(ngModel)]=\"formData.name\"\n placeholder=\"Enter project name\"\n class=\"mj-textbox full-width\"\n (keydown.enter)=\"onSave()\"\n autofocus />\n @if (showNameError) {\n <div class=\"error-message\">Project name is required</div>\n }\n </div>\n\n <!-- Description Textarea -->\n <div class=\"form-field\">\n <label for=\"projectDescription\">\n Description\n </label>\n <textarea\n id=\"projectDescription\"\n [(ngModel)]=\"formData.description\"\n placeholder=\"Enter project description (optional)\"\n class=\"mj-textarea full-width\"\n rows=\"3\"></textarea>\n </div>\n\n <!-- Color Picker -->\n <div class=\"form-field\">\n <label>Color</label>\n <div class=\"color-picker-section\">\n <div class=\"color-palette\">\n @for (color of availableColors; track color) {\n <button\n type=\"button\"\n class=\"color-swatch\"\n [class.selected]=\"formData.color === color\"\n [style.backgroundColor]=\"color\"\n (click)=\"selectColor(color)\"\n [title]=\"color\">\n </button>\n }\n </div>\n <div class=\"custom-color-input\">\n <label for=\"customColor\">Custom:</label>\n <input\n id=\"customColor\"\n type=\"color\"\n [(ngModel)]=\"formData.color\"\n class=\"custom-color-picker\" />\n <span class=\"color-value\">{{ formData.color }}</span>\n </div>\n </div>\n </div>\n\n <!-- Icon Selector -->\n <div class=\"form-field\">\n <label>Icon</label>\n <div class=\"icon-selector-section\">\n <div class=\"selected-icon-preview\">\n <i class=\"fa-solid {{ formData.icon }}\" [style.color]=\"formData.color\"></i>\n <span>{{ formData.icon }}</span>\n </div>\n <div class=\"icon-grid\">\n @for (icon of availableIcons; track icon) {\n <button\n type=\"button\"\n class=\"icon-option\"\n [class.selected]=\"formData.icon === icon\"\n (click)=\"selectIcon(icon)\"\n [title]=\"icon\">\n <i class=\"fa-solid {{ icon }}\"></i>\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n\n <mj-dialog-actions>\n <button mjButton (click)=\"onCancel()\">Cancel</button>\n <button mjButton variant=\"primary\" (click)=\"onSave()\">\n {{ isEditMode ? 'Save' : 'Create' }}\n </button>\n </mj-dialog-actions>\n </mj-dialog>\n `,\n styles: [`\n .project-form {\n padding: 16px;\n }\n\n .form-field {\n margin-bottom: 20px;\n }\n\n .form-field label {\n display: block;\n margin-bottom: 8px;\n font-weight: 500;\n font-size: 14px;\n color: #333;\n }\n\n .form-field label.required::after {\n content: '*';\n color: #F44336;\n margin-left: 4px;\n }\n\n .full-width {\n width: 100%;\n }\n\n .error-message {\n color: #F44336;\n font-size: 12px;\n margin-top: 4px;\n }\n\n /* Color Picker Styles */\n .color-picker-section {\n border: 1px solid #D9D9D9;\n border-radius: 4px;\n padding: 12px;\n background: #F9F9F9;\n }\n\n .color-palette {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .color-swatch {\n width: 100%;\n aspect-ratio: 1;\n border: 2px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n transition: all 150ms ease;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n\n .color-swatch:hover {\n transform: scale(1.1);\n box-shadow: 0 2px 6px rgba(0,0,0,0.2);\n }\n\n .color-swatch.selected {\n border-color: #0076B6;\n box-shadow: 0 0 0 2px #fff, 0 0 0 4px #0076B6;\n }\n\n .custom-color-input {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 12px;\n border-top: 1px solid #D9D9D9;\n }\n\n .custom-color-input label {\n margin: 0;\n font-size: 13px;\n }\n\n .custom-color-picker {\n width: 50px;\n height: 32px;\n border: 1px solid #D9D9D9;\n border-radius: 4px;\n cursor: pointer;\n }\n\n .color-value {\n font-family: monospace;\n font-size: 13px;\n color: #666;\n }\n\n /* Icon Selector Styles */\n .icon-selector-section {\n border: 1px solid #D9D9D9;\n border-radius: 4px;\n padding: 12px;\n background: #F9F9F9;\n }\n\n .selected-icon-preview {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: white;\n border: 1px solid #D9D9D9;\n border-radius: 4px;\n margin-bottom: 12px;\n }\n\n .selected-icon-preview i {\n font-size: 24px;\n }\n\n .selected-icon-preview span {\n font-family: monospace;\n font-size: 13px;\n color: #666;\n }\n\n .icon-grid {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 6px;\n max-height: 200px;\n overflow-y: auto;\n padding: 4px;\n }\n\n .icon-option {\n aspect-ratio: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid #D9D9D9;\n background: white;\n border-radius: 4px;\n cursor: pointer;\n transition: all 150ms ease;\n }\n\n .icon-option:hover {\n background: #F0F0F0;\n border-color: #0076B6;\n transform: scale(1.05);\n }\n\n .icon-option.selected {\n background: #E3F2FD;\n border-color: #0076B6;\n border-width: 2px;\n }\n\n .icon-option i {\n font-size: 18px;\n color: #333;\n }\n\n /* Scrollbar Styles */\n .icon-grid::-webkit-scrollbar {\n width: 8px;\n }\n\n .icon-grid::-webkit-scrollbar-track {\n background: #F0F0F0;\n border-radius: 4px;\n }\n\n .icon-grid::-webkit-scrollbar-thumb {\n background: #D9D9D9;\n border-radius: 4px;\n }\n\n .icon-grid::-webkit-scrollbar-thumb:hover {\n background: #BFBFBF;\n }\n `]\n})\nexport class ProjectFormModalComponent extends BaseAngularComponent implements OnInit {\n @Input() dialogRef!: MJDialogRef;\n @Input() project: MJProjectEntity | null = null;\n @Input() environmentId!: string;\n @Input() currentUser!: UserInfo;\n\n @Output() projectSaved = new EventEmitter<MJProjectEntity>();\n\n public formData: ProjectFormData = {\n name: '',\n description: '',\n color: '#0076B6',\n icon: 'fa-folder'\n };\n\n public showNameError = false;\n public isEditMode = false;\n public availableColors = DEFAULT_PROJECT_COLORS;\n public availableIcons = DEFAULT_PROJECT_ICONS;\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnInit(): void {\n this.isEditMode = this.project != null;\n\n if (this.project) {\n this.loadProjectData();\n }\n }\n\n private loadProjectData(): void {\n if (!this.project) return;\n\n this.formData = {\n name: this.project.Name || '',\n description: this.project.Description || '',\n color: this.project.Color || '#0076B6',\n icon: this.project.Icon || 'fa-folder'\n };\n }\n\n selectColor(color: string): void {\n this.formData.color = color;\n this.cdr.detectChanges();\n }\n\n selectIcon(icon: string): void {\n this.formData.icon = icon;\n this.cdr.detectChanges();\n }\n\n async onSave(): Promise<void> {\n // Validate\n if (!this.formData.name.trim()) {\n this.showNameError = true;\n this.cdr.detectChanges();\n return;\n }\n\n this.showNameError = false;\n\n try {\n const md = this.ProviderToUse;\n const project = this.project || await md.GetEntityObject<MJProjectEntity>('MJ: Projects', this.currentUser);\n\n project.Name = this.formData.name.trim();\n project.Description = this.formData.description.trim() || null;\n project.Color = this.formData.color;\n project.Icon = this.formData.icon;\n\n if (!this.isEditMode) {\n project.EnvironmentID = this.environmentId;\n project.IsArchived = false;\n }\n\n const saved = await project.Save();\n if (saved) {\n this.projectSaved.emit(project);\n this.dialogRef.Close();\n } else {\n throw new Error('Failed to save project');\n }\n } catch (error) {\n console.error('Error saving project:', error);\n alert('Failed to save project. Please try again.');\n }\n }\n\n onCancel(): void {\n this.dialogRef.Close();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"project-form-modal.component.js","sourceRoot":"","sources":["../../../../src/lib/components/project/project-form-modal.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MJDialogRef } from '@memberjunction/ng-ui-components';\nimport { MJProjectEntity } from '@memberjunction/core-entities';\nimport { UserInfo, Metadata } from '@memberjunction/core';\n\nexport interface ProjectFormData {\n name: string;\n description: string;\n color: string;\n icon: string;\n}\n\nconst DEFAULT_PROJECT_COLORS = [\n '#0076B6', // MJ Blue\n '#F44336', // Red\n '#E91E63', // Pink\n '#9C27B0', // Purple\n '#673AB7', // Deep Purple\n '#3F51B5', // Indigo\n '#2196F3', // Blue\n '#03A9F4', // Light Blue\n '#00BCD4', // Cyan\n '#009688', // Teal\n '#4CAF50', // Green\n '#8BC34A', // Light Green\n '#CDDC39', // Lime\n '#FFEB3B', // Yellow\n '#FFC107', // Amber\n '#FF9800', // Orange\n '#FF5722', // Deep Orange\n '#795548', // Brown\n '#607D8B', // Blue Grey\n '#9E9E9E' // Grey\n];\n\nconst DEFAULT_PROJECT_ICONS = [\n 'fa-folder',\n 'fa-folder-open',\n 'fa-briefcase',\n 'fa-project-diagram',\n 'fa-chart-line',\n 'fa-tasks',\n 'fa-clipboard-list',\n 'fa-bullseye',\n 'fa-rocket',\n 'fa-lightbulb',\n 'fa-brain',\n 'fa-cogs',\n 'fa-code',\n 'fa-database',\n 'fa-server',\n 'fa-cloud',\n 'fa-mobile-alt',\n 'fa-desktop',\n 'fa-globe',\n 'fa-users'\n];\n\n@Component({\n standalone: false,\n selector: 'mj-project-form-modal',\n template: `\n <mj-dialog\n [Title]=\"isEditMode ? 'Edit Folder' : 'New Folder'\"\n [Width]=\"560\"\n [MinWidth]=\"400\"\n [Visible]=\"true\"\n (Close)=\"onCancel()\">\n\n <div class=\"project-form\">\n <!-- Live preview chip -->\n <div class=\"folder-preview\">\n <span class=\"folder-preview-chip\" [style.backgroundColor]=\"chipBackground\" [style.color]=\"formData.color\">\n <i class=\"fa-solid {{ formData.icon }}\"></i>\n </span>\n <span class=\"folder-preview-name\">{{ formData.name.trim() || 'Untitled folder' }}</span>\n </div>\n\n <!-- Name Input -->\n <div class=\"form-field\">\n <label for=\"projectName\" class=\"required\">\n Folder Name\n </label>\n <input\n id=\"projectName\"\n type=\"text\"\n [(ngModel)]=\"formData.name\"\n placeholder=\"e.g. Client work, Research, Ideas\"\n class=\"mj-input full-width\"\n (keydown.enter)=\"onSave()\"\n autofocus />\n @if (showNameError) {\n <div class=\"error-message\">Folder name is required</div>\n }\n </div>\n\n <!-- Description Textarea -->\n <div class=\"form-field\">\n <label for=\"projectDescription\">\n Description\n </label>\n <textarea\n id=\"projectDescription\"\n [(ngModel)]=\"formData.description\"\n placeholder=\"What goes in this folder? (optional)\"\n class=\"mj-textarea full-width\"\n rows=\"2\"></textarea>\n </div>\n\n <!-- Color Picker -->\n <div class=\"form-field\">\n <label>Color</label>\n <div class=\"color-picker-section\">\n <div class=\"color-palette\">\n @for (color of availableColors; track color) {\n <button\n type=\"button\"\n class=\"color-swatch\"\n [class.selected]=\"formData.color === color\"\n [style.backgroundColor]=\"color\"\n (click)=\"selectColor(color)\"\n [title]=\"color\">\n </button>\n }\n </div>\n <div class=\"custom-color-input\">\n <label for=\"customColor\">Custom:</label>\n <input\n id=\"customColor\"\n type=\"color\"\n [(ngModel)]=\"formData.color\"\n class=\"custom-color-picker\" />\n <span class=\"color-value\">{{ formData.color }}</span>\n </div>\n </div>\n </div>\n\n <!-- Icon Selector -->\n <div class=\"form-field\">\n <label>Icon</label>\n <div class=\"icon-grid\">\n @for (icon of availableIcons; track icon) {\n <button\n type=\"button\"\n class=\"icon-option\"\n [class.selected]=\"formData.icon === icon\"\n [style.color]=\"formData.icon === icon ? formData.color : null\"\n (click)=\"selectIcon(icon)\"\n [title]=\"icon\">\n <i class=\"fa-solid {{ icon }}\"></i>\n </button>\n }\n </div>\n </div>\n </div>\n\n <mj-dialog-actions>\n <button mjButton variant=\"primary\" (click)=\"onSave()\">\n {{ isEditMode ? 'Save Changes' : 'Create Folder' }}\n </button>\n <button mjButton (click)=\"onCancel()\">Cancel</button>\n </mj-dialog-actions>\n </mj-dialog>\n `,\n styles: [`\n .project-form {\n padding: 20px 24px 8px;\n display: flex;\n flex-direction: column;\n gap: 22px;\n }\n\n /* Live preview chip */\n .folder-preview {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n }\n .folder-preview-chip {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n transition: background-color 150ms ease, color 150ms ease;\n }\n .folder-preview-name {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .form-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .form-field label {\n font-weight: 600;\n font-size: 13px;\n letter-spacing: 0.01em;\n color: var(--mj-text-secondary);\n }\n\n .form-field label.required::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 4px;\n }\n\n .full-width { width: 100%; }\n\n .error-message {\n color: var(--mj-status-error);\n font-size: 12px;\n }\n\n /* Color Picker */\n .color-picker-section {\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 14px;\n background: var(--mj-bg-surface);\n }\n\n .color-palette {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .color-swatch {\n width: 100%;\n aspect-ratio: 1;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n padding: 0;\n transition: transform 120ms ease, box-shadow 120ms ease;\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n }\n\n .color-swatch:hover {\n transform: scale(1.12);\n }\n\n .color-swatch.selected {\n box-shadow: 0 0 0 2px var(--mj-bg-surface), 0 0 0 4px var(--mj-brand-primary);\n }\n\n .custom-color-input {\n display: flex;\n align-items: center;\n gap: 10px;\n padding-top: 14px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n\n .custom-color-input label {\n margin: 0;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n }\n\n .custom-color-picker {\n width: 44px;\n height: 30px;\n padding: 2px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n cursor: pointer;\n background: var(--mj-bg-surface);\n }\n\n .color-value {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 13px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n }\n\n /* Icon Selector */\n .icon-grid {\n display: grid;\n grid-template-columns: repeat(10, 1fr);\n gap: 8px;\n max-height: 184px;\n overflow-y: auto;\n padding: 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n }\n\n .icon-option {\n aspect-ratio: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;\n }\n\n .icon-option:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n transform: translateY(-1px);\n }\n\n .icon-option.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 1px var(--mj-brand-primary);\n }\n\n .icon-option i { font-size: 17px; }\n\n /* Scrollbar */\n .icon-grid::-webkit-scrollbar { width: 8px; }\n .icon-grid::-webkit-scrollbar-track {\n background: transparent;\n }\n .icon-grid::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 4px;\n }\n .icon-grid::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n }\n `]\n})\nexport class ProjectFormModalComponent extends BaseAngularComponent implements OnInit {\n @Input() dialogRef!: MJDialogRef;\n @Input() project: MJProjectEntity | null = null;\n @Input() environmentId!: string;\n @Input() currentUser!: UserInfo;\n /** When creating a new folder, the parent folder ID for nesting (null = top level). */\n @Input() parentId: string | null = null;\n\n @Output() projectSaved = new EventEmitter<MJProjectEntity>();\n\n public formData: ProjectFormData = {\n name: '',\n description: '',\n color: '#0076B6',\n icon: 'fa-folder'\n };\n\n public showNameError = false;\n public isEditMode = false;\n public availableColors = DEFAULT_PROJECT_COLORS;\n public availableIcons = DEFAULT_PROJECT_ICONS;\n\n /** Translucent tint of the selected color, used behind the preview/icon glyph. */\n public get chipBackground(): string {\n const hex = this.formData.color || '#0076B6';\n // 8-digit hex (#RRGGBBAA) — ~14% alpha tint of the chosen color\n return /^#[0-9a-fA-F]{6}$/.test(hex) ? `${hex}24` : hex;\n }\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnInit(): void {\n this.isEditMode = this.project != null;\n\n if (this.project) {\n this.loadProjectData();\n }\n }\n\n private loadProjectData(): void {\n if (!this.project) return;\n\n this.formData = {\n name: this.project.Name || '',\n description: this.project.Description || '',\n color: this.project.Color || '#0076B6',\n icon: this.project.Icon || 'fa-folder'\n };\n }\n\n selectColor(color: string): void {\n this.formData.color = color;\n this.cdr.detectChanges();\n }\n\n selectIcon(icon: string): void {\n this.formData.icon = icon;\n this.cdr.detectChanges();\n }\n\n async onSave(): Promise<void> {\n // Validate\n if (!this.formData.name.trim()) {\n this.showNameError = true;\n this.cdr.detectChanges();\n return;\n }\n\n this.showNameError = false;\n\n try {\n const md = this.ProviderToUse;\n const project = this.project || await md.GetEntityObject<MJProjectEntity>('MJ: Projects', this.currentUser);\n\n project.Name = this.formData.name.trim();\n project.Description = this.formData.description.trim() || null;\n project.Color = this.formData.color;\n project.Icon = this.formData.icon;\n\n if (!this.isEditMode) {\n project.EnvironmentID = this.environmentId;\n project.IsArchived = false;\n if (this.parentId) {\n project.ParentID = this.parentId;\n }\n }\n\n const saved = await project.Save();\n if (saved) {\n this.projectSaved.emit(project);\n this.dialogRef.Close();\n } else {\n throw new Error('Failed to save project');\n }\n } catch (error) {\n console.error('Error saving project:', error);\n alert('Failed to save project. Please try again.');\n }\n }\n\n onCancel(): void {\n this.dialogRef.Close();\n }\n}\n"]}
|
|
@@ -246,6 +246,28 @@ export declare abstract class BaseRealtimeChannelClient<TSurface extends object
|
|
|
246
246
|
* Default: no-op.
|
|
247
247
|
*/
|
|
248
248
|
protected OnInitialize(): void;
|
|
249
|
+
/**
|
|
250
|
+
* Max time {@link ResolveAgentSessionId} waits for the session id to bind before giving up, and the
|
|
251
|
+
* poll interval it re-checks on. Protected so tests can shrink the wait; production keeps the
|
|
252
|
+
* defaults (the real mint race is sub-second, 8s is generous headroom).
|
|
253
|
+
*/
|
|
254
|
+
protected SessionIdWaitTimeoutMs: number;
|
|
255
|
+
protected SessionIdWaitIntervalMs: number;
|
|
256
|
+
/**
|
|
257
|
+
* Resolves the live {@link RealtimeChannelContext.AgentSessionID}, briefly WAITING for it when it
|
|
258
|
+
* isn't bound yet rather than giving up instantly. `AgentSessionID` is a live getter over the
|
|
259
|
+
* session service's current id: it reads `null` in the window BEFORE the session mints (the
|
|
260
|
+
* realtime model can fire a tool call the very first beat it connects, before `mintSession`
|
|
261
|
+
* resolves) and again AFTER teardown. Server-backed tool paths (e.g. the Remote Browser channel's
|
|
262
|
+
* `browser_*` tools) call this instead of reading `Context?.AgentSessionID` synchronously, so a tool
|
|
263
|
+
* invoked a beat early WAITS for the session to come live — defense-in-depth against the
|
|
264
|
+
* "session id missing" race — instead of returning a hard failure to the model.
|
|
265
|
+
*
|
|
266
|
+
* Returns the id as soon as it's non-null (the common path resolves immediately, no delay), or
|
|
267
|
+
* `null` if it's still unbound after {@link SessionIdWaitTimeoutMs} — or the channel was
|
|
268
|
+
* {@link Dispose}d in the meantime (`Context` goes null, so we stop waiting on a torn-down session).
|
|
269
|
+
*/
|
|
270
|
+
protected ResolveAgentSessionId(): Promise<string | null>;
|
|
249
271
|
/**
|
|
250
272
|
* Serializes the channel's current state of record (the payload persisted on the
|
|
251
273
|
* session's channel row), or `null` when the channel keeps no persistent state.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-realtime-channel-client.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/base-realtime-channel-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,sBAAsB;IACrC,iGAAiG;IACjG,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpC;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAErC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAEhC;;;;;;;OAOG;IACH,qBAAqB,CAAC,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnD;;;;;;;OAOG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE1E;;;;;;;OAOG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B;;;;;;;;;;;;;;;;OAgBG;IACH,mBAAmB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC5G;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,8BAAsB,yBAAyB,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM;IAC9E;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAQ;IAExD;;;;OAIG;IACH,aAAoB,WAAW,IAAI,MAAM,CAAC;IAE1C;;;;OAIG;IACH,aAAoB,cAAc,IAAI,MAAM,CAAC;IAE7C,wFAAwF;IACxF,aAAoB,QAAQ,IAAI,MAAM,CAAC;IAEvC,uFAAuF;IACvF,aAAoB,OAAO,IAAI,MAAM,CAAC;IAEtC;;;;OAIG;aACa,kBAAkB,IAAI,sBAAsB,EAAE;IAE9D;;;;;;;;OAQG;aACa,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAE5F;;;;;;;;;;;;;OAaG;IACI,mBAAmB,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI;IAInD;;;;;OAKG;IACI,UAAU,IAAI,OAAO;IAI5B;;;;;;;;;;OAUG;IACI,oBAAoB,IAAI,wBAAwB,GAAG,IAAI;IAI9D;;;;;;;OAOG;aACa,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAErD;;;;;OAKG;IACI,aAAa,IAAI,IAAI;IAI5B;;;;OAIG;IACI,UAAU,CAAC,GAAG,EAAE,sBAAsB,GAAG,IAAI;IAKpD;;;;OAIG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAI9B;;;;OAIG;IACI,cAAc,IAAI,MAAM,GAAG,IAAI;IAItC;;;;;;;;;;OAUG;IACI,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/C;;;;;OAKG;IACI,gBAAgB,IAAI,IAAI;IAI/B;;;;;OAKG;IACI,OAAO,IAAI,IAAI;CAIvB"}
|
|
1
|
+
{"version":3,"file":"base-realtime-channel-client.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/base-realtime-channel-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -113,6 +113,46 @@ export class BaseRealtimeChannelClient {
|
|
|
113
113
|
OnInitialize() {
|
|
114
114
|
// default: nothing to initialize
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Max time {@link ResolveAgentSessionId} waits for the session id to bind before giving up, and the
|
|
118
|
+
* poll interval it re-checks on. Protected so tests can shrink the wait; production keeps the
|
|
119
|
+
* defaults (the real mint race is sub-second, 8s is generous headroom).
|
|
120
|
+
*/
|
|
121
|
+
SessionIdWaitTimeoutMs = 8000;
|
|
122
|
+
SessionIdWaitIntervalMs = 200;
|
|
123
|
+
/**
|
|
124
|
+
* Resolves the live {@link RealtimeChannelContext.AgentSessionID}, briefly WAITING for it when it
|
|
125
|
+
* isn't bound yet rather than giving up instantly. `AgentSessionID` is a live getter over the
|
|
126
|
+
* session service's current id: it reads `null` in the window BEFORE the session mints (the
|
|
127
|
+
* realtime model can fire a tool call the very first beat it connects, before `mintSession`
|
|
128
|
+
* resolves) and again AFTER teardown. Server-backed tool paths (e.g. the Remote Browser channel's
|
|
129
|
+
* `browser_*` tools) call this instead of reading `Context?.AgentSessionID` synchronously, so a tool
|
|
130
|
+
* invoked a beat early WAITS for the session to come live — defense-in-depth against the
|
|
131
|
+
* "session id missing" race — instead of returning a hard failure to the model.
|
|
132
|
+
*
|
|
133
|
+
* Returns the id as soon as it's non-null (the common path resolves immediately, no delay), or
|
|
134
|
+
* `null` if it's still unbound after {@link SessionIdWaitTimeoutMs} — or the channel was
|
|
135
|
+
* {@link Dispose}d in the meantime (`Context` goes null, so we stop waiting on a torn-down session).
|
|
136
|
+
*/
|
|
137
|
+
async ResolveAgentSessionId() {
|
|
138
|
+
const immediate = this.Context?.AgentSessionID ?? null;
|
|
139
|
+
if (immediate) {
|
|
140
|
+
return immediate;
|
|
141
|
+
}
|
|
142
|
+
const intervalMs = Math.max(1, this.SessionIdWaitIntervalMs);
|
|
143
|
+
for (let waited = 0; waited < this.SessionIdWaitTimeoutMs; waited += intervalMs) {
|
|
144
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
145
|
+
// Context goes null on Dispose() — the session is gone, stop waiting.
|
|
146
|
+
if (!this.Context) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
const id = this.Context.AgentSessionID;
|
|
150
|
+
if (id) {
|
|
151
|
+
return id;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return this.Context?.AgentSessionID ?? null;
|
|
155
|
+
}
|
|
116
156
|
/**
|
|
117
157
|
* Serializes the channel's current state of record (the payload persisted on the
|
|
118
158
|
* session's channel row), or `null` when the channel keeps no persistent state.
|