@memberjunction/ng-agent-requests 5.51.0 → 6.1.0-edge.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/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2023 MemberJunction
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -6,9 +6,10 @@
6
6
  */
7
7
  import { EventEmitter, ChangeDetectorRef, OnInit, OnChanges, SimpleChanges } from '@angular/core';
8
8
  import { MJAIAgentRequestEntity, MJAIAgentRequestTypeEntity } from '@memberjunction/core-entities';
9
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
9
10
  import { AgentRequestPanelComponent, AgentRequestPanelResult } from '../panels/agent-request-panel/agent-request-panel.component';
10
11
  import * as i0 from "@angular/core";
11
- export declare class AgentRequestDialogComponent implements OnInit, OnChanges {
12
+ export declare class AgentRequestDialogComponent extends BaseAngularComponent implements OnInit, OnChanges {
12
13
  private cdr;
13
14
  requestPanel: AgentRequestPanelComponent;
14
15
  Visible: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-request-dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/dialogs/agent-request-dialog.component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACuB,YAAY,EAAE,iBAAiB,EACrB,MAAM,EAAE,SAAS,EAAE,aAAa,EACvE,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAEnG,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,6DAA6D,CAAC;;AAElI,qBAoCa,2BAA4B,YAAW,MAAM,EAAE,SAAS;IAWrD,OAAO,CAAC,GAAG;IAVI,YAAY,EAAG,0BAA0B,CAAC;IAE5D,OAAO,UAAS;IAChB,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAQ;IAE7C,KAAK,wCAA+C;IAEvD,SAAS,UAAS;IAClB,YAAY,EAAE,0BAA0B,EAAE,CAAM;gBAEnC,GAAG,EAAE,iBAAiB;IAE1C,QAAQ,IAAI,IAAI;IAMhB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;YAa3B,gBAAgB;IAyBvB,YAAY,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI;yCAzDjD,2BAA2B;2CAA3B,2BAA2B;CA8DvC"}
1
+ {"version":3,"file":"agent-request-dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/dialogs/agent-request-dialog.component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACuB,YAAY,EAAE,iBAAiB,EACrB,MAAM,EAAE,SAAS,EAAE,aAAa,EACvE,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AACnG,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,6DAA6D,CAAC;;AAElI,qBAoCa,2BAA4B,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS;IAWlF,OAAO,CAAC,GAAG;IAVI,YAAY,EAAG,0BAA0B,CAAC;IAE5D,OAAO,UAAS;IAChB,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAQ;IAE7C,KAAK,wCAA+C;IAEvD,SAAS,UAAS;IAClB,YAAY,EAAE,0BAA0B,EAAE,CAAM;gBAEnC,GAAG,EAAE,iBAAiB;IAG1C,QAAQ,IAAI,IAAI;IAMhB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;YAa3B,gBAAgB;IAyBvB,YAAY,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI;yCA1DjD,2BAA2B;2CAA3B,2BAA2B;CA+DvC"}
@@ -5,11 +5,12 @@
5
5
  * a convenient way to view and respond to agent requests in a modal context.
6
6
  */
7
7
  import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewChild } from '@angular/core';
8
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
8
9
  import { RunView } from '@memberjunction/core';
9
10
  import * as i0 from "@angular/core";
10
11
  import * as i1 from "@memberjunction/ng-shared-generic";
11
12
  import * as i2 from "../panels/agent-request-panel/agent-request-panel.component";
12
- export class AgentRequestDialogComponent {
13
+ export class AgentRequestDialogComponent extends BaseAngularComponent {
13
14
  cdr;
14
15
  requestPanel;
15
16
  Visible = false;
@@ -18,6 +19,7 @@ export class AgentRequestDialogComponent {
18
19
  IsLoading = false;
19
20
  requestTypes = [];
20
21
  constructor(cdr) {
22
+ super();
21
23
  this.cdr = cdr;
22
24
  }
23
25
  ngOnInit() {
@@ -43,7 +45,7 @@ export class AgentRequestDialogComponent {
43
45
  this.IsLoading = true;
44
46
  this.cdr.markForCheck();
45
47
  try {
46
- const rv = new RunView();
48
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
47
49
  const result = await rv.RunView({
48
50
  EntityName: 'MJ: AI Agent Request Types',
49
51
  OrderBy: 'Name',
@@ -67,7 +69,7 @@ export class AgentRequestDialogComponent {
67
69
  this.cdr.markForCheck();
68
70
  }
69
71
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AgentRequestDialogComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
70
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: AgentRequestDialogComponent, isStandalone: false, selector: "mj-agent-request-dialog", inputs: { Visible: "Visible", Request: "Request" }, outputs: { Close: "Close" }, viewQueries: [{ propertyName: "requestPanel", first: true, predicate: ["requestPanel"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
72
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: AgentRequestDialogComponent, isStandalone: false, selector: "mj-agent-request-dialog", inputs: { Visible: "Visible", Request: "Request" }, outputs: { Close: "Close" }, viewQueries: [{ propertyName: "requestPanel", first: true, predicate: ["requestPanel"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
71
73
  @if (Visible) {
72
74
  @if (IsLoading) {
73
75
  <div class="loading-backdrop">
@@ -1 +1 @@
1
- {"version":3,"file":"agent-request-dialog.component.js","sourceRoot":"","sources":["../../../src/lib/dialogs/agent-request-dialog.component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EACtC,uBAAuB,EAAE,SAAS,EACrC,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;;;;AAuC/C,MAAM,OAAO,2BAA2B;IAWhB;IAVO,YAAY,CAA8B;IAE5D,OAAO,GAAG,KAAK,CAAC;IAChB,OAAO,GAAkC,IAAI,CAAC;IAE7C,KAAK,GAAG,IAAI,YAAY,EAA2B,CAAC;IAEvD,SAAS,GAAG,KAAK,CAAC;IAClB,YAAY,GAAiC,EAAE,CAAC;IAEvD,YAAoB,GAAsB;QAAtB,QAAG,GAAH,GAAG,CAAmB;IAAG,CAAC;IAE9C,QAAQ;QACJ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC5B,CAAC;IACL,CAAC;IAED,WAAW,CAAC,OAAsB;QAC9B,IAAI,OAAO,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YACjE,IAAI,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC9B,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACzB,UAAU,CAAC,GAAG,EAAE;oBACZ,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;wBACpC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACzC,CAAC;gBACL,CAAC,EAAE,CAAC,CAAC,CAAC;YACV,CAAC,CAAC,CAAC;QACP,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC1B,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO;QAEzC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAExB,IAAI,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAA6B;gBACxD,UAAU,EAAE,4BAA4B;gBACxC,OAAO,EAAE,MAAM;gBACf,UAAU,EAAE,eAAe;aAC9B,CAAC,CAAC;YAEH,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC;YACvC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC5B,CAAC;IACL,CAAC;IAEM,YAAY,CAAC,MAA+B;QAC/C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;uGA7DQ,2BAA2B;2FAA3B,2BAA2B,wSAjC1B;;;;;;;;;;;;;;;;KAgBT;;2FAiBQ,2BAA2B;kBApCvC,SAAS;iCACM,KAAK,YACP,yBAAyB,YACzB;;;;;;;;;;;;;;;;KAgBT,mBAegB,uBAAuB,CAAC,MAAM;;sBAG9C,SAAS;uBAAC,cAAc;;sBAExB,KAAK;;sBACL,KAAK;;sBAEL,MAAM","sourcesContent":["/**\n * @fileoverview Agent Request Dialog Component\n *\n * A dialog wrapper for the AgentRequestPanelComponent that provides\n * a convenient way to view and respond to agent requests in a modal context.\n */\n\nimport {\n Component, Input, Output, EventEmitter, ChangeDetectorRef,\n ChangeDetectionStrategy, ViewChild, OnInit, OnChanges, SimpleChanges\n} from '@angular/core';\nimport { MJAIAgentRequestEntity, MJAIAgentRequestTypeEntity } from '@memberjunction/core-entities';\nimport { RunView } from '@memberjunction/core';\nimport { AgentRequestPanelComponent, AgentRequestPanelResult } from '../panels/agent-request-panel/agent-request-panel.component';\n\n@Component({\n standalone: false,\n selector: 'mj-agent-request-dialog',\n template: `\n @if (Visible) {\n @if (IsLoading) {\n <div class=\"loading-backdrop\">\n <mj-loading text=\"Loading request types...\"></mj-loading>\n </div>\n } @else {\n <mj-agent-request-panel\n #requestPanel\n [Request]=\"Request\"\n [RequestTypes]=\"requestTypes\"\n [IsOpen]=\"Visible\"\n (Close)=\"OnPanelClose($event)\">\n </mj-agent-request-panel>\n }\n }\n `,\n styles: [`\n .loading-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AgentRequestDialogComponent implements OnInit, OnChanges {\n @ViewChild('requestPanel') requestPanel!: AgentRequestPanelComponent;\n\n @Input() Visible = false;\n @Input() Request: MJAIAgentRequestEntity | null = null;\n\n @Output() Close = new EventEmitter<AgentRequestPanelResult>();\n\n public IsLoading = false;\n public requestTypes: MJAIAgentRequestTypeEntity[] = [];\n\n constructor(private cdr: ChangeDetectorRef) {}\n\n ngOnInit(): void {\n if (this.Visible) {\n this.loadRequestTypes();\n }\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Visible'] && changes['Visible'].currentValue === true) {\n this.loadRequestTypes().then(() => {\n this.cdr.detectChanges();\n setTimeout(() => {\n if (this.requestPanel && this.Request) {\n this.requestPanel.Open(this.Request);\n }\n }, 0);\n });\n }\n }\n\n private async loadRequestTypes(): Promise<void> {\n if (this.requestTypes.length > 0) return;\n\n this.IsLoading = true;\n this.cdr.markForCheck();\n\n try {\n const rv = new RunView();\n const result = await rv.RunView<MJAIAgentRequestTypeEntity>({\n EntityName: 'MJ: AI Agent Request Types',\n OrderBy: 'Name',\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n this.requestTypes = result.Results;\n }\n } catch (error) {\n console.error('Error loading request types:', error);\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n public OnPanelClose(result: AgentRequestPanelResult): void {\n this.Visible = false;\n this.Close.emit(result);\n this.cdr.markForCheck();\n }\n}\n"]}
1
+ {"version":3,"file":"agent-request-dialog.component.js","sourceRoot":"","sources":["../../../src/lib/dialogs/agent-request-dialog.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Agent Request Dialog Component\n *\n * A dialog wrapper for the AgentRequestPanelComponent that provides\n * a convenient way to view and respond to agent requests in a modal context.\n */\n\nimport {\n Component, Input, Output, EventEmitter, ChangeDetectorRef,\n ChangeDetectionStrategy, ViewChild, OnInit, OnChanges, SimpleChanges\n} from '@angular/core';\nimport { MJAIAgentRequestEntity, MJAIAgentRequestTypeEntity } from '@memberjunction/core-entities';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { RunView } from '@memberjunction/core';\nimport { AgentRequestPanelComponent, AgentRequestPanelResult } from '../panels/agent-request-panel/agent-request-panel.component';\n\n@Component({\n standalone: false,\n selector: 'mj-agent-request-dialog',\n template: `\n @if (Visible) {\n @if (IsLoading) {\n <div class=\"loading-backdrop\">\n <mj-loading text=\"Loading request types...\"></mj-loading>\n </div>\n } @else {\n <mj-agent-request-panel\n #requestPanel\n [Request]=\"Request\"\n [RequestTypes]=\"requestTypes\"\n [IsOpen]=\"Visible\"\n (Close)=\"OnPanelClose($event)\">\n </mj-agent-request-panel>\n }\n }\n `,\n styles: [`\n .loading-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AgentRequestDialogComponent extends BaseAngularComponent implements OnInit, OnChanges {\n @ViewChild('requestPanel') requestPanel!: AgentRequestPanelComponent;\n\n @Input() Visible = false;\n @Input() Request: MJAIAgentRequestEntity | null = null;\n\n @Output() Close = new EventEmitter<AgentRequestPanelResult>();\n\n public IsLoading = false;\n public requestTypes: MJAIAgentRequestTypeEntity[] = [];\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnInit(): void {\n if (this.Visible) {\n this.loadRequestTypes();\n }\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Visible'] && changes['Visible'].currentValue === true) {\n this.loadRequestTypes().then(() => {\n this.cdr.detectChanges();\n setTimeout(() => {\n if (this.requestPanel && this.Request) {\n this.requestPanel.Open(this.Request);\n }\n }, 0);\n });\n }\n }\n\n private async loadRequestTypes(): Promise<void> {\n if (this.requestTypes.length > 0) return;\n\n this.IsLoading = true;\n this.cdr.markForCheck();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const result = await rv.RunView<MJAIAgentRequestTypeEntity>({\n EntityName: 'MJ: AI Agent Request Types',\n OrderBy: 'Name',\n ResultType: 'entity_object'\n });\n\n if (result.Success) {\n this.requestTypes = result.Results;\n }\n } catch (error) {\n console.error('Error loading request types:', error);\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n public OnPanelClose(result: AgentRequestPanelResult): void {\n this.Visible = false;\n this.Close.emit(result);\n this.cdr.markForCheck();\n }\n}\n"]}
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { EventEmitter, ChangeDetectorRef, OnInit, OnDestroy, ElementRef } from '@angular/core';
9
9
  import { MJAIAgentRequestEntity, MJAIAgentRequestTypeEntity } from '@memberjunction/core-entities';
10
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
10
11
  import { MJNotificationService } from '@memberjunction/ng-notifications';
11
12
  import { AgentResponseForm } from '@memberjunction/ai-core-plus';
12
13
  import { DynamicFormComponent } from '@memberjunction/ng-forms';
@@ -22,7 +23,7 @@ export interface AgentRequestPanelResult {
22
23
  /** The action that was taken */
23
24
  Action: 'responded' | 'approved' | 'rejected' | 'cancelled';
24
25
  }
25
- export declare class AgentRequestPanelComponent implements OnInit, OnDestroy {
26
+ export declare class AgentRequestPanelComponent extends BaseAngularComponent implements OnInit, OnDestroy {
26
27
  private cdr;
27
28
  private notificationService;
28
29
  Request: MJAIAgentRequestEntity | null;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-request-panel.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/panels/agent-request-panel/agent-request-panel.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-request-panel.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/panels/agent-request-panel/agent-request-panel.component.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@
6
6
  * and submits ResponseData back to the request entity.
7
7
  */
8
8
  import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, HostListener, ViewChild } from '@angular/core';
9
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
9
10
  import { RunView } from '@memberjunction/core';
10
11
  import { UserInfoEngine } from '@memberjunction/core-entities';
11
12
  import { UUIDsEqual } from '@memberjunction/global';
@@ -18,7 +19,7 @@ const PANEL_WIDTH_SETTING_KEY = 'Explorer.AgentRequestPanelWidth';
18
19
  const DEFAULT_PANEL_WIDTH = 520;
19
20
  const MIN_PANEL_WIDTH = 360;
20
21
  const MAX_PANEL_WIDTH = 900;
21
- export class AgentRequestPanelComponent {
22
+ export class AgentRequestPanelComponent extends BaseAngularComponent {
22
23
  cdr;
23
24
  notificationService;
24
25
  Request = null;
@@ -50,6 +51,7 @@ export class AgentRequestPanelComponent {
50
51
  IsReassigning = false;
51
52
  reassignSearchTimeout = null;
52
53
  constructor(cdr, notificationService) {
54
+ super();
53
55
  this.cdr = cdr;
54
56
  this.notificationService = notificationService;
55
57
  }
@@ -235,7 +237,7 @@ export class AgentRequestPanelComponent {
235
237
  this.IsSearchingUsers = true;
236
238
  this.cdr.markForCheck();
237
239
  try {
238
- const rv = new RunView();
240
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
239
241
  const result = await rv.RunView({
240
242
  EntityName: 'Users',
241
243
  ExtraFilter: `(Name LIKE '%${term.replace(/'/g, "''")}%' OR Email LIKE '%${term.replace(/'/g, "''")}%')`,
@@ -388,7 +390,7 @@ export class AgentRequestPanelComponent {
388
390
  }
389
391
  }
390
392
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AgentRequestPanelComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.MJNotificationService }], target: i0.ɵɵFactoryTarget.Component });
391
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: AgentRequestPanelComponent, isStandalone: false, selector: "mj-agent-request-panel", inputs: { Request: "Request", RequestTypes: "RequestTypes", IsOpen: "IsOpen" }, outputs: { Close: "Close" }, host: { listeners: { "document:keydown.escape": "OnEscapeKey()" } }, viewQueries: [{ propertyName: "dynamicForm", first: true, predicate: ["dynamicForm"], descendants: true }, { propertyName: "panelElement", first: true, predicate: ["panelElement"], descendants: true }], ngImport: i0, template: "@if (IsOpen && Request) {\n <div class=\"panel-backdrop\" (click)=\"OnBackdropClick()\">\n <div class=\"request-panel\" #panelElement [class.open]=\"IsOpen\" [class.resizing]=\"IsResizing\" [style.width.px]=\"PanelWidth\" (click)=\"$event.stopPropagation()\">\n <!-- Resize Handle (left edge) -->\n <div class=\"resize-handle\" (mousedown)=\"OnResizeStart($event)\">\n <div class=\"resize-grip\"></div>\n </div>\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-content\">\n <div class=\"header-title-row\">\n @if (RequestType?.Icon) {\n <i class=\"{{ RequestType!.Icon }} header-icon\"></i>\n }\n <h3 class=\"panel-title\">{{ RequestType?.Name || 'Agent Request' }}</h3>\n <span class=\"priority-badge\" [class]=\"PriorityClass\">{{ PriorityLabel }}</span>\n <span class=\"status-badge status-{{ Request.Status.toLowerCase() }}\">{{ Request.Status }}</span>\n </div>\n @if (Request.Agent) {\n <span class=\"agent-name\">\n <i class=\"fa-solid fa-robot\"></i> {{ Request.Agent }}\n </span>\n }\n </div>\n <button class=\"close-btn\" (click)=\"OnCancel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"panel-body\">\n <!-- Request Details -->\n <div class=\"section\">\n <h4 class=\"section-title\">Request</h4>\n <p class=\"request-text\">{{ Request.Request }}</p>\n </div>\n\n <!-- Metadata -->\n <div class=\"section metadata-section\">\n <div class=\"metadata-grid\">\n @if (Request.ExpiresAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Expires</span>\n <span class=\"metadata-value\" [class.expired]=\"IsExpired\">\n {{ Request.ExpiresAt | date:'medium' }}\n @if (IsExpired) {\n <span class=\"expired-tag\">Expired</span>\n }\n </span>\n </div>\n }\n @if (Request.__mj_CreatedAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Created</span>\n <span class=\"metadata-value\">{{ Request.__mj_CreatedAt | date:'medium' }}</span>\n </div>\n }\n @if (Request.RespondedAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Responded</span>\n <span class=\"metadata-value\">{{ Request.RespondedAt | date:'medium' }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Dynamic Response Form (from ResponseSchema) -->\n @if (HasResponseForm && IsActionable && ResponseFormDefinition) {\n <div class=\"section\">\n <mj-dynamic-form #dynamicForm\n [FormDefinition]=\"ResponseFormDefinition\"\n [Disabled]=\"IsSaving\">\n </mj-dynamic-form>\n </div>\n }\n\n <!-- Free-text response (always available for actionable requests) -->\n @if (IsActionable) {\n <div class=\"section\">\n <h4 class=\"section-title\">\n @if (HasResponseForm) {\n Additional Comments\n } @else {\n Response\n }\n </h4>\n <textarea\n class=\"response-textarea\"\n [(ngModel)]=\"ResponseText\"\n placeholder=\"Type your response here...\"\n rows=\"4\">\n </textarea>\n </div>\n }\n\n <!-- Show existing response for already-handled requests -->\n @if (!IsActionable && (Request.Response || Request.ResponseData)) {\n @if (Request.ResponseData) {\n <div class=\"section\">\n <mj-dynamic-form-response\n [FormDefinition]=\"ResponseFormDefinition\"\n [ResponseData]=\"Request.ResponseData\"\n DisplayMode=\"card\">\n </mj-dynamic-form-response>\n </div>\n }\n @if (Request.Response) {\n <div class=\"section\">\n <h4 class=\"section-title\">\n @if (Request.ResponseData) {\n Additional Comments\n } @else {\n Response\n }\n </h4>\n <p class=\"response-text\">{{ Request.Response }}</p>\n </div>\n }\n }\n </div>\n\n <!-- Footer (action buttons) -->\n @if (IsActionable && !IsExpired) {\n <div class=\"panel-footer\">\n @if (IsApprovalType) {\n <button\n class=\"btn btn-approve\"\n (click)=\"OnApprove()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-check\"></i> Approve\n </button>\n <button\n class=\"btn btn-reject\"\n (click)=\"OnReject()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-times\"></i> Reject\n </button>\n } @else {\n <button\n class=\"btn btn-respond\"\n (click)=\"OnRespond()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-paper-plane\"></i> Submit Response\n </button>\n }\n <button\n class=\"btn btn-reassign\"\n (click)=\"OnReassignClick()\"\n [disabled]=\"IsSaving\"\n title=\"Reassign to another user\">\n <i class=\"fa-solid fa-user-plus\"></i> Reassign\n </button>\n <button\n class=\"btn btn-cancel\"\n (click)=\"OnCancel()\"\n [disabled]=\"IsSaving\">\n Cancel\n </button>\n </div>\n } @else if (IsExpired) {\n <div class=\"panel-footer\">\n <div class=\"expired-notice\">\n <i class=\"fa-solid fa-clock\"></i> This request has expired and can no longer be responded to.\n </div>\n <button class=\"btn btn-cancel\" (click)=\"OnCancel()\">Close</button>\n </div>\n } @else {\n <div class=\"panel-footer\">\n <button class=\"btn btn-cancel\" (click)=\"OnCancel()\">Close</button>\n </div>\n }\n </div>\n </div>\n\n <!-- Reassign Dialog Overlay -->\n @if (ShowReassignDialog) {\n <div class=\"reassign-overlay\" (click)=\"OnReassignCancel()\">\n <div class=\"reassign-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"reassign-header\">\n <h4 class=\"reassign-title\">\n <i class=\"fa-solid fa-user-plus\"></i> Reassign Request\n </h4>\n <button class=\"close-btn\" (click)=\"OnReassignCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"reassign-body\">\n <!-- User Search -->\n <div class=\"reassign-field\">\n <label class=\"field-label\">Search User</label>\n <div class=\"search-input-wrapper\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"field-input search-input\"\n placeholder=\"Type a name or email...\"\n [value]=\"ReassignSearchTerm\"\n (input)=\"OnReassignSearchChange($any($event.target).value)\">\n </div>\n </div>\n\n <!-- Search Results -->\n @if (IsSearchingUsers) {\n <div class=\"search-status\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Searching...\n </div>\n }\n @if (ReassignUsers.length > 0) {\n <div class=\"user-results\">\n @for (user of ReassignUsers; track user.ID) {\n <button\n class=\"user-result-item\"\n [class.selected]=\"SelectedReassignUser?.ID === user.ID\"\n (click)=\"OnSelectReassignUser(user)\">\n <i class=\"fa-solid fa-user user-avatar\"></i>\n <div class=\"user-info\">\n <span class=\"user-name\">{{ user.Name }}</span>\n <span class=\"user-email\">{{ user.Email }}</span>\n </div>\n @if (SelectedReassignUser?.ID === user.ID) {\n <i class=\"fa-solid fa-check selected-check\"></i>\n }\n </button>\n }\n </div>\n } @else if (ReassignSearchTerm.length >= 2 && !IsSearchingUsers) {\n <div class=\"search-status\">No users found</div>\n }\n\n <!-- Note -->\n <div class=\"reassign-field\">\n <label class=\"field-label\">Note (optional)</label>\n <textarea\n class=\"field-textarea\"\n [(ngModel)]=\"ReassignNote\"\n placeholder=\"Add a reason for reassignment...\"\n rows=\"2\">\n </textarea>\n </div>\n </div>\n\n <div class=\"reassign-footer\">\n <button\n class=\"btn btn-respond\"\n (click)=\"OnReassignSubmit()\"\n [disabled]=\"!SelectedReassignUser || IsReassigning\">\n @if (IsReassigning) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Reassigning...\n } @else {\n <i class=\"fa-solid fa-user-plus\"></i> Reassign\n }\n </button>\n <button\n class=\"btn btn-cancel\"\n (click)=\"OnReassignCancel()\"\n [disabled]=\"IsReassigning\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n}\n", styles: ["/* Panel Backdrop */\n.panel-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n justify-content: flex-end;\n z-index: 10000;\n}\n\n/* Slide-in Panel */\n.request-panel {\n max-width: 90vw;\n min-width: 360px;\n height: 100%;\n background: var(--mj-bg-surface);\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);\n transform: translateX(100%);\n transition: transform 0.25s ease-out;\n position: relative;\n}\n\n.request-panel.open {\n transform: translateX(0);\n}\n\n.request-panel.resizing {\n transition: none;\n}\n\n/* Resize Handle */\n.resize-handle {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: col-resize;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.resize-handle:hover,\n.resize-handle:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.resize-grip {\n width: 2px;\n height: 32px;\n border-radius: 1px;\n background: var(--mj-border-strong);\n opacity: 0;\n transition: opacity 0.15s;\n}\n\n.resize-handle:hover .resize-grip,\n.resize-handle:active .resize-grip {\n opacity: 1;\n}\n\n/* Header */\n.panel-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.header-content {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n min-width: 0;\n}\n\n.header-title-row {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.header-icon {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.panel-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.agent-name {\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.close-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px 8px;\n color: var(--mj-text-muted);\n font-size: 16px;\n border-radius: 4px;\n}\n\n.close-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Status Badge */\n.status-badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.status-requested {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n border: 1px solid var(--mj-status-info-border);\n}\n\n.status-approved {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.status-rejected,\n.status-canceled {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.status-responded {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.status-expired {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n/* Priority Badge */\n.priority-badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.priority-low {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.priority-normal {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.priority-high {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.priority-critical {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n/* Body */\n.panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n.section {\n margin-bottom: 20px;\n}\n\n.section-title {\n margin: 0 0 8px 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.request-text {\n margin: 0;\n font-size: 14px;\n line-height: 1.6;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n}\n\n.response-text {\n margin: 0;\n font-size: 14px;\n line-height: 1.6;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n background: var(--mj-bg-surface-sunken);\n padding: 12px;\n border-radius: 6px;\n}\n\n/* Metadata */\n.metadata-section {\n background: var(--mj-bg-surface-card);\n padding: 12px;\n border-radius: 6px;\n}\n\n.metadata-grid {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.metadata-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.metadata-label {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: 500;\n}\n\n.metadata-value {\n font-size: 12px;\n color: var(--mj-text-primary);\n}\n\n.metadata-value.expired {\n color: var(--mj-status-error-text);\n}\n\n.expired-tag {\n display: inline-block;\n margin-left: 6px;\n padding: 1px 6px;\n border-radius: 8px;\n font-size: 10px;\n font-weight: 600;\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n/* Shared field styles (used by reassign dialog and free-text response) */\n.field-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.field-input,\n.field-textarea {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: border-color 0.15s;\n}\n\n.field-input:focus,\n.field-textarea:focus {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.field-textarea {\n resize: vertical;\n min-height: 60px;\n}\n\n.response-textarea {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n resize: vertical;\n box-sizing: border-box;\n}\n\n.response-textarea:focus {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n/* Footer */\n.panel-footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 20px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.btn {\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: background-color 0.15s;\n}\n\n.btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-approve {\n background: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.btn-approve:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 85%, black);\n}\n\n.btn-reject {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n}\n\n.btn-reject:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 85%, black);\n}\n\n.btn-respond {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.btn-respond:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-cancel {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n margin-left: auto;\n}\n\n.btn-cancel:hover:not(:disabled) {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n.btn-reassign {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.btn-reassign:hover:not(:disabled) {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n\n.expired-notice {\n font-size: 13px;\n color: var(--mj-status-warning-text);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n/* Reassign Dialog */\n.reassign-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10001;\n}\n\n.reassign-dialog {\n width: 420px;\n max-width: 90vw;\n max-height: 80vh;\n background: var(--mj-bg-surface);\n border-radius: 10px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.reassign-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.reassign-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.reassign-body {\n padding: 16px 20px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n.reassign-field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.search-input-wrapper {\n position: relative;\n}\n\n.search-icon {\n position: absolute;\n left: 10px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.search-input {\n padding-left: 32px;\n}\n\n.search-status {\n font-size: 13px;\n color: var(--mj-text-muted);\n padding: 8px 0;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.user-results {\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-height: 200px;\n overflow-y: auto;\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n}\n\n.user-result-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n background: none;\n border: none;\n cursor: pointer;\n text-align: left;\n width: 100%;\n transition: background-color 0.1s;\n}\n\n.user-result-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-result-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.user-avatar {\n color: var(--mj-text-muted);\n font-size: 14px;\n width: 20px;\n text-align: center;\n}\n\n.user-info {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n}\n\n.user-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.user-email {\n font-size: 12px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.selected-check {\n color: var(--mj-brand-primary);\n font-size: 13px;\n}\n\n.reassign-footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 20px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n"], dependencies: [{ kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.DynamicFormComponent, selector: "mj-dynamic-form", inputs: ["FormDefinition", "Disabled", "Visible"], outputs: ["FormSubmitted"] }, { kind: "component", type: i3.DynamicFormResponseComponent, selector: "mj-dynamic-form-response", inputs: ["FormDefinition", "ResponseData", "Title", "DisplayMode"] }, { kind: "pipe", type: i4.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
393
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: AgentRequestPanelComponent, isStandalone: false, selector: "mj-agent-request-panel", inputs: { Request: "Request", RequestTypes: "RequestTypes", IsOpen: "IsOpen" }, outputs: { Close: "Close" }, host: { listeners: { "document:keydown.escape": "OnEscapeKey()" } }, viewQueries: [{ propertyName: "dynamicForm", first: true, predicate: ["dynamicForm"], descendants: true }, { propertyName: "panelElement", first: true, predicate: ["panelElement"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (IsOpen && Request) {\n <div class=\"panel-backdrop\" (click)=\"OnBackdropClick()\">\n <div class=\"request-panel\" #panelElement [class.open]=\"IsOpen\" [class.resizing]=\"IsResizing\" [style.width.px]=\"PanelWidth\" (click)=\"$event.stopPropagation()\">\n <!-- Resize Handle (left edge) -->\n <div class=\"resize-handle\" (mousedown)=\"OnResizeStart($event)\">\n <div class=\"resize-grip\"></div>\n </div>\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-content\">\n <div class=\"header-title-row\">\n @if (RequestType?.Icon) {\n <i class=\"{{ RequestType!.Icon }} header-icon\"></i>\n }\n <h3 class=\"panel-title\">{{ RequestType?.Name || 'Agent Request' }}</h3>\n <span class=\"priority-badge\" [class]=\"PriorityClass\">{{ PriorityLabel }}</span>\n <span class=\"status-badge status-{{ Request.Status.toLowerCase() }}\">{{ Request.Status }}</span>\n </div>\n @if (Request.Agent) {\n <span class=\"agent-name\">\n <i class=\"fa-solid fa-robot\"></i> {{ Request.Agent }}\n </span>\n }\n </div>\n <button class=\"close-btn\" (click)=\"OnCancel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"panel-body\">\n <!-- Request Details -->\n <div class=\"section\">\n <h4 class=\"section-title\">Request</h4>\n <p class=\"request-text\">{{ Request.Request }}</p>\n </div>\n\n <!-- Metadata -->\n <div class=\"section metadata-section\">\n <div class=\"metadata-grid\">\n @if (Request.ExpiresAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Expires</span>\n <span class=\"metadata-value\" [class.expired]=\"IsExpired\">\n {{ Request.ExpiresAt | date:'medium' }}\n @if (IsExpired) {\n <span class=\"expired-tag\">Expired</span>\n }\n </span>\n </div>\n }\n @if (Request.__mj_CreatedAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Created</span>\n <span class=\"metadata-value\">{{ Request.__mj_CreatedAt | date:'medium' }}</span>\n </div>\n }\n @if (Request.RespondedAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Responded</span>\n <span class=\"metadata-value\">{{ Request.RespondedAt | date:'medium' }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Dynamic Response Form (from ResponseSchema) -->\n @if (HasResponseForm && IsActionable && ResponseFormDefinition) {\n <div class=\"section\">\n <mj-dynamic-form #dynamicForm\n [FormDefinition]=\"ResponseFormDefinition\"\n [Disabled]=\"IsSaving\">\n </mj-dynamic-form>\n </div>\n }\n\n <!-- Free-text response (always available for actionable requests) -->\n @if (IsActionable) {\n <div class=\"section\">\n <h4 class=\"section-title\">\n @if (HasResponseForm) {\n Additional Comments\n } @else {\n Response\n }\n </h4>\n <textarea\n class=\"response-textarea\"\n [(ngModel)]=\"ResponseText\"\n placeholder=\"Type your response here...\"\n rows=\"4\">\n </textarea>\n </div>\n }\n\n <!-- Show existing response for already-handled requests -->\n @if (!IsActionable && (Request.Response || Request.ResponseData)) {\n @if (Request.ResponseData) {\n <div class=\"section\">\n <mj-dynamic-form-response\n [FormDefinition]=\"ResponseFormDefinition\"\n [ResponseData]=\"Request.ResponseData\"\n DisplayMode=\"card\">\n </mj-dynamic-form-response>\n </div>\n }\n @if (Request.Response) {\n <div class=\"section\">\n <h4 class=\"section-title\">\n @if (Request.ResponseData) {\n Additional Comments\n } @else {\n Response\n }\n </h4>\n <p class=\"response-text\">{{ Request.Response }}</p>\n </div>\n }\n }\n </div>\n\n <!-- Footer (action buttons) -->\n @if (IsActionable && !IsExpired) {\n <div class=\"panel-footer\">\n @if (IsApprovalType) {\n <button\n class=\"btn btn-approve\"\n (click)=\"OnApprove()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-check\"></i> Approve\n </button>\n <button\n class=\"btn btn-reject\"\n (click)=\"OnReject()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-times\"></i> Reject\n </button>\n } @else {\n <button\n class=\"btn btn-respond\"\n (click)=\"OnRespond()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-paper-plane\"></i> Submit Response\n </button>\n }\n <button\n class=\"btn btn-reassign\"\n (click)=\"OnReassignClick()\"\n [disabled]=\"IsSaving\"\n title=\"Reassign to another user\">\n <i class=\"fa-solid fa-user-plus\"></i> Reassign\n </button>\n <button\n class=\"btn btn-cancel\"\n (click)=\"OnCancel()\"\n [disabled]=\"IsSaving\">\n Cancel\n </button>\n </div>\n } @else if (IsExpired) {\n <div class=\"panel-footer\">\n <div class=\"expired-notice\">\n <i class=\"fa-solid fa-clock\"></i> This request has expired and can no longer be responded to.\n </div>\n <button class=\"btn btn-cancel\" (click)=\"OnCancel()\">Close</button>\n </div>\n } @else {\n <div class=\"panel-footer\">\n <button class=\"btn btn-cancel\" (click)=\"OnCancel()\">Close</button>\n </div>\n }\n </div>\n </div>\n\n <!-- Reassign Dialog Overlay -->\n @if (ShowReassignDialog) {\n <div class=\"reassign-overlay\" (click)=\"OnReassignCancel()\">\n <div class=\"reassign-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"reassign-header\">\n <h4 class=\"reassign-title\">\n <i class=\"fa-solid fa-user-plus\"></i> Reassign Request\n </h4>\n <button class=\"close-btn\" (click)=\"OnReassignCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"reassign-body\">\n <!-- User Search -->\n <div class=\"reassign-field\">\n <label class=\"field-label\">Search User</label>\n <div class=\"search-input-wrapper\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"field-input search-input\"\n placeholder=\"Type a name or email...\"\n [value]=\"ReassignSearchTerm\"\n (input)=\"OnReassignSearchChange($any($event.target).value)\">\n </div>\n </div>\n\n <!-- Search Results -->\n @if (IsSearchingUsers) {\n <div class=\"search-status\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Searching...\n </div>\n }\n @if (ReassignUsers.length > 0) {\n <div class=\"user-results\">\n @for (user of ReassignUsers; track user.ID) {\n <button\n class=\"user-result-item\"\n [class.selected]=\"SelectedReassignUser?.ID === user.ID\"\n (click)=\"OnSelectReassignUser(user)\">\n <i class=\"fa-solid fa-user user-avatar\"></i>\n <div class=\"user-info\">\n <span class=\"user-name\">{{ user.Name }}</span>\n <span class=\"user-email\">{{ user.Email }}</span>\n </div>\n @if (SelectedReassignUser?.ID === user.ID) {\n <i class=\"fa-solid fa-check selected-check\"></i>\n }\n </button>\n }\n </div>\n } @else if (ReassignSearchTerm.length >= 2 && !IsSearchingUsers) {\n <div class=\"search-status\">No users found</div>\n }\n\n <!-- Note -->\n <div class=\"reassign-field\">\n <label class=\"field-label\">Note (optional)</label>\n <textarea\n class=\"field-textarea\"\n [(ngModel)]=\"ReassignNote\"\n placeholder=\"Add a reason for reassignment...\"\n rows=\"2\">\n </textarea>\n </div>\n </div>\n\n <div class=\"reassign-footer\">\n <button\n class=\"btn btn-respond\"\n (click)=\"OnReassignSubmit()\"\n [disabled]=\"!SelectedReassignUser || IsReassigning\">\n @if (IsReassigning) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Reassigning...\n } @else {\n <i class=\"fa-solid fa-user-plus\"></i> Reassign\n }\n </button>\n <button\n class=\"btn btn-cancel\"\n (click)=\"OnReassignCancel()\"\n [disabled]=\"IsReassigning\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n}\n", styles: ["/* Panel Backdrop */\n.panel-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n justify-content: flex-end;\n z-index: 10000;\n}\n\n/* Slide-in Panel */\n.request-panel {\n max-width: 90vw;\n min-width: 360px;\n height: 100%;\n background: var(--mj-bg-surface);\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);\n transform: translateX(100%);\n transition: transform 0.25s ease-out;\n position: relative;\n}\n\n.request-panel.open {\n transform: translateX(0);\n}\n\n.request-panel.resizing {\n transition: none;\n}\n\n/* Resize Handle */\n.resize-handle {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: col-resize;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.resize-handle:hover,\n.resize-handle:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.resize-grip {\n width: 2px;\n height: 32px;\n border-radius: 1px;\n background: var(--mj-border-strong);\n opacity: 0;\n transition: opacity 0.15s;\n}\n\n.resize-handle:hover .resize-grip,\n.resize-handle:active .resize-grip {\n opacity: 1;\n}\n\n/* Header */\n.panel-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.header-content {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n min-width: 0;\n}\n\n.header-title-row {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.header-icon {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.panel-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.agent-name {\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.close-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px 8px;\n color: var(--mj-text-muted);\n font-size: 16px;\n border-radius: 4px;\n}\n\n.close-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Status Badge */\n.status-badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.status-requested {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n border: 1px solid var(--mj-status-info-border);\n}\n\n.status-approved {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.status-rejected,\n.status-canceled {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.status-responded {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.status-expired {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n/* Priority Badge */\n.priority-badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.priority-low {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.priority-normal {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n}\n\n.priority-high {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.priority-critical {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n/* Body */\n.panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n.section {\n margin-bottom: 20px;\n}\n\n.section-title {\n margin: 0 0 8px 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.request-text {\n margin: 0;\n font-size: 14px;\n line-height: 1.6;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n}\n\n.response-text {\n margin: 0;\n font-size: 14px;\n line-height: 1.6;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n background: var(--mj-bg-surface-sunken);\n padding: 12px;\n border-radius: 6px;\n}\n\n/* Metadata */\n.metadata-section {\n background: var(--mj-bg-surface-card);\n padding: 12px;\n border-radius: 6px;\n}\n\n.metadata-grid {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.metadata-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.metadata-label {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: 500;\n}\n\n.metadata-value {\n font-size: 12px;\n color: var(--mj-text-primary);\n}\n\n.metadata-value.expired {\n color: var(--mj-status-error-text);\n}\n\n.expired-tag {\n display: inline-block;\n margin-left: 6px;\n padding: 1px 6px;\n border-radius: 8px;\n font-size: 10px;\n font-weight: 600;\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n/* Shared field styles (used by reassign dialog and free-text response) */\n.field-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.field-input,\n.field-textarea {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: border-color 0.15s;\n}\n\n.field-input:focus,\n.field-textarea:focus {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.field-textarea {\n resize: vertical;\n min-height: 60px;\n}\n\n.response-textarea {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n font-family: inherit;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n resize: vertical;\n box-sizing: border-box;\n}\n\n.response-textarea:focus {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n/* Footer */\n.panel-footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 20px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.btn {\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: background-color 0.15s;\n}\n\n.btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-approve {\n background: var(--mj-status-success);\n color: var(--mj-text-inverse);\n}\n\n.btn-approve:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 85%, black);\n}\n\n.btn-reject {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n}\n\n.btn-reject:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 85%, black);\n}\n\n.btn-respond {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.btn-respond:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-cancel {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n margin-left: auto;\n}\n\n.btn-cancel:hover:not(:disabled) {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n.btn-reassign {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n.btn-reassign:hover:not(:disabled) {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n\n.expired-notice {\n font-size: 13px;\n color: var(--mj-status-warning-text);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n/* Reassign Dialog */\n.reassign-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10001;\n}\n\n.reassign-dialog {\n width: 420px;\n max-width: 90vw;\n max-height: 80vh;\n background: var(--mj-bg-surface);\n border-radius: 10px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.reassign-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.reassign-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.reassign-body {\n padding: 16px 20px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n.reassign-field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.search-input-wrapper {\n position: relative;\n}\n\n.search-icon {\n position: absolute;\n left: 10px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.search-input {\n padding-left: 32px;\n}\n\n.search-status {\n font-size: 13px;\n color: var(--mj-text-muted);\n padding: 8px 0;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.user-results {\n display: flex;\n flex-direction: column;\n gap: 2px;\n max-height: 200px;\n overflow-y: auto;\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n}\n\n.user-result-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n background: none;\n border: none;\n cursor: pointer;\n text-align: left;\n width: 100%;\n transition: background-color 0.1s;\n}\n\n.user-result-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-result-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.user-avatar {\n color: var(--mj-text-muted);\n font-size: 14px;\n width: 20px;\n text-align: center;\n}\n\n.user-info {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n}\n\n.user-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.user-email {\n font-size: 12px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.selected-check {\n color: var(--mj-brand-primary);\n font-size: 13px;\n}\n\n.reassign-footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 20px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n"], dependencies: [{ kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.DynamicFormComponent, selector: "mj-dynamic-form", inputs: ["FormDefinition", "Disabled", "Visible"], outputs: ["FormSubmitted"] }, { kind: "component", type: i3.DynamicFormResponseComponent, selector: "mj-dynamic-form-response", inputs: ["FormDefinition", "ResponseData", "Title", "DisplayMode"] }, { kind: "pipe", type: i4.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
392
394
  }
393
395
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AgentRequestPanelComponent, decorators: [{
394
396
  type: Component,
@@ -1 +1 @@
1
- {"version":3,"file":"agent-request-panel.component.js","sourceRoot":"","sources":["../../../../src/lib/panels/agent-request-panel/agent-request-panel.component.ts","../../../../src/lib/panels/agent-request-panel/agent-request-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Agent Request Panel Component\n *\n * Slide-in panel for viewing and responding to AI agent feedback requests.\n * Displays request details, renders ResponseSchema as a dynamic form,\n * and submits ResponseData back to the request entity.\n */\n\nimport {\n Component, Input, Output, EventEmitter, ChangeDetectorRef,\n ChangeDetectionStrategy, OnInit, OnDestroy, HostListener, ViewChild, ElementRef\n} from '@angular/core';\nimport { MJAIAgentRequestEntity, MJAIAgentRequestTypeEntity } from '@memberjunction/core-entities';\nimport { RunView } from '@memberjunction/core';\nimport { UserInfoEngine } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { AgentResponseForm } from '@memberjunction/ai-core-plus';\nimport { DynamicFormComponent } from '@memberjunction/ng-forms';\n\nconst PANEL_WIDTH_SETTING_KEY = 'Explorer.AgentRequestPanelWidth';\nconst DEFAULT_PANEL_WIDTH = 520;\nconst MIN_PANEL_WIDTH = 360;\nconst MAX_PANEL_WIDTH = 900;\n\n/**\n * Result returned when the panel closes after an action\n */\nexport interface AgentRequestPanelResult {\n /** Whether an action was taken (responded, approved, rejected) */\n Success: boolean;\n /** The updated request entity */\n Request?: MJAIAgentRequestEntity;\n /** The action that was taken */\n Action: 'responded' | 'approved' | 'rejected' | 'cancelled';\n}\n\n@Component({\n standalone: false,\n selector: 'mj-agent-request-panel',\n templateUrl: './agent-request-panel.component.html',\n styleUrls: ['./agent-request-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AgentRequestPanelComponent implements OnInit, OnDestroy {\n @Input() Request: MJAIAgentRequestEntity | null = null;\n @Input() RequestTypes: MJAIAgentRequestTypeEntity[] = [];\n @Input() IsOpen = false;\n\n @Output() Close = new EventEmitter<AgentRequestPanelResult>();\n\n @ViewChild('dynamicForm') dynamicForm: DynamicFormComponent | undefined;\n @ViewChild('panelElement') panelElement: ElementRef<HTMLDivElement> | undefined;\n\n public IsLoading = false;\n public IsSaving = false;\n public ResponseText = '';\n public ResponseFormDefinition: AgentResponseForm | null = null;\n public PanelWidth = DEFAULT_PANEL_WIDTH;\n\n /** Tracks whether a response was submitted so the Close event carries the right result */\n private completedAction: 'responded' | 'approved' | 'rejected' | null = null;\n\n // Resize state\n public IsResizing = false;\n private resizeStartX = 0;\n private resizeStartWidth = 0;\n private boundOnResizeMove: ((e: MouseEvent) => void) | null = null;\n private boundOnResizeEnd: (() => void) | null = null;\n\n // Reassign state\n public ShowReassignDialog = false;\n public ReassignSearchTerm = '';\n public ReassignNote = '';\n public ReassignUsers: Array<{ ID: string; Name: string; Email: string }> = [];\n public SelectedReassignUser: { ID: string; Name: string; Email: string } | null = null;\n public IsSearchingUsers = false;\n public IsReassigning = false;\n\n private reassignSearchTimeout: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n private cdr: ChangeDetectorRef,\n private notificationService: MJNotificationService\n ) {}\n\n ngOnInit(): void {\n this.loadPanelWidth();\n if (this.Request) {\n this.initializeForm();\n }\n }\n\n ngOnDestroy(): void {\n this.cleanupResizeListeners();\n }\n\n @HostListener('document:keydown.escape')\n public OnEscapeKey(): void {\n if (this.IsOpen) {\n this.OnCancel();\n }\n }\n\n /** The request type entity for the current request */\n public get RequestType(): MJAIAgentRequestTypeEntity | null {\n if (!this.Request?.RequestTypeID) return null;\n return this.RequestTypes.find(t => UUIDsEqual(t.ID, this.Request!.RequestTypeID!)) ?? null;\n }\n\n /** Whether this request is still actionable (status = Requested) */\n public get IsActionable(): boolean {\n return this.Request?.Status === 'Requested';\n }\n\n /** Whether this is an approval-type request (show approve/reject buttons) */\n public get IsApprovalType(): boolean {\n const typeName = this.RequestType?.Name;\n return typeName === 'Approval';\n }\n\n /** Whether the request has a structured response form */\n public get HasResponseForm(): boolean {\n return this.ResponseFormDefinition != null && (this.ResponseFormDefinition.questions?.length ?? 0) > 0;\n }\n\n /** Priority display label */\n public get PriorityLabel(): string {\n if (!this.Request) return '';\n const p = this.Request.Priority;\n if (p <= 25) return 'Low';\n if (p <= 50) return 'Normal';\n if (p <= 75) return 'High';\n return 'Critical';\n }\n\n /** Priority CSS class */\n public get PriorityClass(): string {\n if (!this.Request) return '';\n const p = this.Request.Priority;\n if (p <= 25) return 'priority-low';\n if (p <= 50) return 'priority-normal';\n if (p <= 75) return 'priority-high';\n return 'priority-critical';\n }\n\n /** Whether the request is expired */\n public get IsExpired(): boolean {\n if (!this.Request?.ExpiresAt) return false;\n return new Date(this.Request.ExpiresAt) < new Date();\n }\n\n /**\n * Opens the panel with a specific request\n */\n public Open(request: MJAIAgentRequestEntity): void {\n this.Request = request;\n this.IsOpen = true;\n this.ResponseText = '';\n this.completedAction = null;\n this.initializeForm();\n this.cdr.markForCheck();\n }\n\n /**\n * Approve the request\n */\n public async OnApprove(): Promise<void> {\n await this.submitResponse('Approved', 'approved');\n }\n\n /**\n * Reject the request\n */\n public async OnReject(): Promise<void> {\n await this.submitResponse('Rejected', 'rejected');\n }\n\n /**\n * Submit a response (for non-approval types)\n */\n public async OnRespond(): Promise<void> {\n await this.submitResponse('Responded', 'responded');\n }\n\n /**\n * Cancel / close the panel without action\n */\n public OnCancel(): void {\n this.IsOpen = false;\n if (this.completedAction) {\n // A response was submitted — tell the parent about the action taken\n this.Close.emit({ Success: true, Request: this.Request!, Action: this.completedAction });\n this.completedAction = null;\n } else {\n this.Close.emit({ Success: false, Action: 'cancelled' });\n }\n this.cdr.markForCheck();\n }\n\n public OnBackdropClick(): void {\n this.OnCancel();\n }\n\n /** Open the reassign dialog */\n public OnReassignClick(): void {\n this.ShowReassignDialog = true;\n this.ReassignSearchTerm = '';\n this.ReassignNote = '';\n this.ReassignUsers = [];\n this.SelectedReassignUser = null;\n this.cdr.markForCheck();\n }\n\n /** Close the reassign dialog */\n public OnReassignCancel(): void {\n this.ShowReassignDialog = false;\n this.cdr.markForCheck();\n }\n\n /** Search users by name/email for reassignment */\n public OnReassignSearchChange(term: string): void {\n this.ReassignSearchTerm = term;\n if (this.reassignSearchTimeout) {\n clearTimeout(this.reassignSearchTimeout);\n }\n if (term.length < 2) {\n this.ReassignUsers = [];\n this.cdr.markForCheck();\n return;\n }\n this.reassignSearchTimeout = setTimeout(() => this.searchUsers(term), 300);\n }\n\n /** Select a user from the search results */\n public OnSelectReassignUser(user: { ID: string; Name: string; Email: string }): void {\n this.SelectedReassignUser = user;\n this.cdr.markForCheck();\n }\n\n /** Submit the reassignment */\n public async OnReassignSubmit(): Promise<void> {\n if (!this.Request || !this.SelectedReassignUser || this.IsReassigning) return;\n\n this.IsReassigning = true;\n this.cdr.markForCheck();\n\n try {\n this.Request.RequestForUserID = this.SelectedReassignUser.ID;\n\n // Append reassignment note to Comments\n const timestamp = new Date().toISOString();\n const reassignEntry = `[${timestamp}] Reassigned to ${this.SelectedReassignUser.Name || this.SelectedReassignUser.Email}${this.ReassignNote ? ` — \"${this.ReassignNote}\"` : ''}`;\n this.Request.Comments = this.Request.Comments\n ? `${this.Request.Comments}\\n${reassignEntry}`\n : reassignEntry;\n\n const saved = await this.Request.Save();\n if (saved) {\n this.notificationService.CreateSimpleNotification(\n `Request reassigned to ${this.SelectedReassignUser.Name || this.SelectedReassignUser.Email}`, 'success', 3000\n );\n this.ShowReassignDialog = false;\n this.IsOpen = false;\n this.Close.emit({ Success: true, Request: this.Request, Action: 'cancelled' });\n } else {\n this.notificationService.CreateSimpleNotification(\n 'Failed to reassign request. Please try again.', 'error', 5000\n );\n }\n } catch (error) {\n console.error('Error reassigning request:', error);\n this.notificationService.CreateSimpleNotification(\n 'An unexpected error occurred.', 'error', 5000\n );\n } finally {\n this.IsReassigning = false;\n this.cdr.markForCheck();\n }\n }\n\n private async searchUsers(term: string): Promise<void> {\n this.IsSearchingUsers = true;\n this.cdr.markForCheck();\n\n try {\n const rv = new RunView();\n const result = await rv.RunView<{ ID: string; Name: string; Email: string }>({\n EntityName: 'Users',\n ExtraFilter: `(Name LIKE '%${term.replace(/'/g, \"''\")}%' OR Email LIKE '%${term.replace(/'/g, \"''\")}%')`,\n OrderBy: 'Name',\n MaxRows: 10,\n Fields: ['ID', 'Name', 'Email'],\n ResultType: 'simple'\n });\n this.ReassignUsers = result.Success ? result.Results : [];\n } catch {\n this.ReassignUsers = [];\n } finally {\n this.IsSearchingUsers = false;\n this.cdr.markForCheck();\n }\n }\n\n // ========================================================================\n // Resize\n // ========================================================================\n\n /** Begin resizing when the user mousedowns on the resize handle */\n public OnResizeStart(event: MouseEvent): void {\n event.preventDefault();\n this.IsResizing = true;\n this.resizeStartX = event.clientX;\n this.resizeStartWidth = this.PanelWidth;\n\n this.boundOnResizeMove = (e: MouseEvent) => this.onResizeMove(e);\n this.boundOnResizeEnd = () => this.onResizeEnd();\n document.addEventListener('mousemove', this.boundOnResizeMove);\n document.addEventListener('mouseup', this.boundOnResizeEnd);\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n }\n\n private onResizeMove(event: MouseEvent): void {\n // Panel is on the right, so dragging left (negative deltaX) increases width\n const deltaX = this.resizeStartX - event.clientX;\n const newWidth = Math.max(MIN_PANEL_WIDTH, Math.min(MAX_PANEL_WIDTH, this.resizeStartWidth + deltaX));\n this.PanelWidth = newWidth;\n this.cdr.markForCheck();\n }\n\n private onResizeEnd(): void {\n this.IsResizing = false;\n this.cleanupResizeListeners();\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n this.savePanelWidth();\n this.cdr.markForCheck();\n }\n\n private cleanupResizeListeners(): void {\n if (this.boundOnResizeMove) {\n document.removeEventListener('mousemove', this.boundOnResizeMove);\n this.boundOnResizeMove = null;\n }\n if (this.boundOnResizeEnd) {\n document.removeEventListener('mouseup', this.boundOnResizeEnd);\n this.boundOnResizeEnd = null;\n }\n }\n\n private loadPanelWidth(): void {\n try {\n const saved = UserInfoEngine.Instance.GetSetting(PANEL_WIDTH_SETTING_KEY);\n if (saved) {\n const parsed = parseInt(saved, 10);\n if (!isNaN(parsed) && parsed >= MIN_PANEL_WIDTH && parsed <= MAX_PANEL_WIDTH) {\n this.PanelWidth = parsed;\n }\n }\n } catch {\n // UserInfoEngine may not be initialized yet — use default\n }\n }\n\n private savePanelWidth(): void {\n try {\n UserInfoEngine.Instance.SetSettingDebounced(PANEL_WIDTH_SETTING_KEY, String(this.PanelWidth));\n } catch {\n // Silently ignore save failures\n }\n }\n\n // ========================================================================\n // Form handling\n // ========================================================================\n\n /**\n * Parse the ResponseSchema JSON into an AgentResponseForm for the dynamic form component.\n */\n private initializeForm(): void {\n this.ResponseFormDefinition = null;\n\n if (!this.Request?.ResponseSchema) return;\n\n try {\n const schema = JSON.parse(this.Request.ResponseSchema) as AgentResponseForm;\n if (schema?.questions && Array.isArray(schema.questions)) {\n this.ResponseFormDefinition = schema;\n }\n } catch {\n // If schema is invalid JSON, ignore — user can still provide free-text response\n }\n }\n\n /**\n * Collect current form values from the DynamicFormComponent's reactive FormGroup.\n * This reads values directly so the user doesn't need to click the form's\n * internal submit button before clicking the panel's action buttons.\n */\n private collectFormData(): Record<string, unknown> | null {\n if (!this.dynamicForm?.FormGroup) return null;\n const values = this.dynamicForm.FormGroup.value;\n if (values && Object.keys(values).length > 0) {\n return values;\n }\n return null;\n }\n\n /**\n * Shared logic for submitting any response type\n */\n private async submitResponse(\n status: 'Approved' | 'Rejected' | 'Responded',\n action: 'approved' | 'rejected' | 'responded'\n ): Promise<void> {\n if (!this.Request || this.IsSaving) return;\n\n this.IsSaving = true;\n this.cdr.markForCheck();\n\n try {\n this.Request.Status = status;\n this.Request.Response = this.ResponseText || null;\n this.Request.RespondedAt = new Date();\n\n const formData = this.collectFormData();\n if (formData) {\n this.Request.ResponseData = JSON.stringify(formData);\n }\n\n const saved = await this.Request.Save();\n if (saved) {\n this.notificationService.CreateSimpleNotification(\n `Agent request has been ${action} successfully.`, 'success', 3000\n );\n // Keep panel open so the user can see their submitted response.\n // Template auto-switches to read-only mode since IsActionable becomes false.\n this.completedAction = action;\n } else {\n this.notificationService.CreateSimpleNotification(\n 'Failed to save response. Please try again.', 'error', 5000\n );\n }\n } catch (error) {\n console.error('Error submitting response:', error);\n this.notificationService.CreateSimpleNotification(\n 'An unexpected error occurred while saving the response.', 'error', 5000\n );\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n}\n","@if (IsOpen && Request) {\n <div class=\"panel-backdrop\" (click)=\"OnBackdropClick()\">\n <div class=\"request-panel\" #panelElement [class.open]=\"IsOpen\" [class.resizing]=\"IsResizing\" [style.width.px]=\"PanelWidth\" (click)=\"$event.stopPropagation()\">\n <!-- Resize Handle (left edge) -->\n <div class=\"resize-handle\" (mousedown)=\"OnResizeStart($event)\">\n <div class=\"resize-grip\"></div>\n </div>\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-content\">\n <div class=\"header-title-row\">\n @if (RequestType?.Icon) {\n <i class=\"{{ RequestType!.Icon }} header-icon\"></i>\n }\n <h3 class=\"panel-title\">{{ RequestType?.Name || 'Agent Request' }}</h3>\n <span class=\"priority-badge\" [class]=\"PriorityClass\">{{ PriorityLabel }}</span>\n <span class=\"status-badge status-{{ Request.Status.toLowerCase() }}\">{{ Request.Status }}</span>\n </div>\n @if (Request.Agent) {\n <span class=\"agent-name\">\n <i class=\"fa-solid fa-robot\"></i> {{ Request.Agent }}\n </span>\n }\n </div>\n <button class=\"close-btn\" (click)=\"OnCancel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"panel-body\">\n <!-- Request Details -->\n <div class=\"section\">\n <h4 class=\"section-title\">Request</h4>\n <p class=\"request-text\">{{ Request.Request }}</p>\n </div>\n\n <!-- Metadata -->\n <div class=\"section metadata-section\">\n <div class=\"metadata-grid\">\n @if (Request.ExpiresAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Expires</span>\n <span class=\"metadata-value\" [class.expired]=\"IsExpired\">\n {{ Request.ExpiresAt | date:'medium' }}\n @if (IsExpired) {\n <span class=\"expired-tag\">Expired</span>\n }\n </span>\n </div>\n }\n @if (Request.__mj_CreatedAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Created</span>\n <span class=\"metadata-value\">{{ Request.__mj_CreatedAt | date:'medium' }}</span>\n </div>\n }\n @if (Request.RespondedAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Responded</span>\n <span class=\"metadata-value\">{{ Request.RespondedAt | date:'medium' }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Dynamic Response Form (from ResponseSchema) -->\n @if (HasResponseForm && IsActionable && ResponseFormDefinition) {\n <div class=\"section\">\n <mj-dynamic-form #dynamicForm\n [FormDefinition]=\"ResponseFormDefinition\"\n [Disabled]=\"IsSaving\">\n </mj-dynamic-form>\n </div>\n }\n\n <!-- Free-text response (always available for actionable requests) -->\n @if (IsActionable) {\n <div class=\"section\">\n <h4 class=\"section-title\">\n @if (HasResponseForm) {\n Additional Comments\n } @else {\n Response\n }\n </h4>\n <textarea\n class=\"response-textarea\"\n [(ngModel)]=\"ResponseText\"\n placeholder=\"Type your response here...\"\n rows=\"4\">\n </textarea>\n </div>\n }\n\n <!-- Show existing response for already-handled requests -->\n @if (!IsActionable && (Request.Response || Request.ResponseData)) {\n @if (Request.ResponseData) {\n <div class=\"section\">\n <mj-dynamic-form-response\n [FormDefinition]=\"ResponseFormDefinition\"\n [ResponseData]=\"Request.ResponseData\"\n DisplayMode=\"card\">\n </mj-dynamic-form-response>\n </div>\n }\n @if (Request.Response) {\n <div class=\"section\">\n <h4 class=\"section-title\">\n @if (Request.ResponseData) {\n Additional Comments\n } @else {\n Response\n }\n </h4>\n <p class=\"response-text\">{{ Request.Response }}</p>\n </div>\n }\n }\n </div>\n\n <!-- Footer (action buttons) -->\n @if (IsActionable && !IsExpired) {\n <div class=\"panel-footer\">\n @if (IsApprovalType) {\n <button\n class=\"btn btn-approve\"\n (click)=\"OnApprove()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-check\"></i> Approve\n </button>\n <button\n class=\"btn btn-reject\"\n (click)=\"OnReject()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-times\"></i> Reject\n </button>\n } @else {\n <button\n class=\"btn btn-respond\"\n (click)=\"OnRespond()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-paper-plane\"></i> Submit Response\n </button>\n }\n <button\n class=\"btn btn-reassign\"\n (click)=\"OnReassignClick()\"\n [disabled]=\"IsSaving\"\n title=\"Reassign to another user\">\n <i class=\"fa-solid fa-user-plus\"></i> Reassign\n </button>\n <button\n class=\"btn btn-cancel\"\n (click)=\"OnCancel()\"\n [disabled]=\"IsSaving\">\n Cancel\n </button>\n </div>\n } @else if (IsExpired) {\n <div class=\"panel-footer\">\n <div class=\"expired-notice\">\n <i class=\"fa-solid fa-clock\"></i> This request has expired and can no longer be responded to.\n </div>\n <button class=\"btn btn-cancel\" (click)=\"OnCancel()\">Close</button>\n </div>\n } @else {\n <div class=\"panel-footer\">\n <button class=\"btn btn-cancel\" (click)=\"OnCancel()\">Close</button>\n </div>\n }\n </div>\n </div>\n\n <!-- Reassign Dialog Overlay -->\n @if (ShowReassignDialog) {\n <div class=\"reassign-overlay\" (click)=\"OnReassignCancel()\">\n <div class=\"reassign-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"reassign-header\">\n <h4 class=\"reassign-title\">\n <i class=\"fa-solid fa-user-plus\"></i> Reassign Request\n </h4>\n <button class=\"close-btn\" (click)=\"OnReassignCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"reassign-body\">\n <!-- User Search -->\n <div class=\"reassign-field\">\n <label class=\"field-label\">Search User</label>\n <div class=\"search-input-wrapper\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"field-input search-input\"\n placeholder=\"Type a name or email...\"\n [value]=\"ReassignSearchTerm\"\n (input)=\"OnReassignSearchChange($any($event.target).value)\">\n </div>\n </div>\n\n <!-- Search Results -->\n @if (IsSearchingUsers) {\n <div class=\"search-status\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Searching...\n </div>\n }\n @if (ReassignUsers.length > 0) {\n <div class=\"user-results\">\n @for (user of ReassignUsers; track user.ID) {\n <button\n class=\"user-result-item\"\n [class.selected]=\"SelectedReassignUser?.ID === user.ID\"\n (click)=\"OnSelectReassignUser(user)\">\n <i class=\"fa-solid fa-user user-avatar\"></i>\n <div class=\"user-info\">\n <span class=\"user-name\">{{ user.Name }}</span>\n <span class=\"user-email\">{{ user.Email }}</span>\n </div>\n @if (SelectedReassignUser?.ID === user.ID) {\n <i class=\"fa-solid fa-check selected-check\"></i>\n }\n </button>\n }\n </div>\n } @else if (ReassignSearchTerm.length >= 2 && !IsSearchingUsers) {\n <div class=\"search-status\">No users found</div>\n }\n\n <!-- Note -->\n <div class=\"reassign-field\">\n <label class=\"field-label\">Note (optional)</label>\n <textarea\n class=\"field-textarea\"\n [(ngModel)]=\"ReassignNote\"\n placeholder=\"Add a reason for reassignment...\"\n rows=\"2\">\n </textarea>\n </div>\n </div>\n\n <div class=\"reassign-footer\">\n <button\n class=\"btn btn-respond\"\n (click)=\"OnReassignSubmit()\"\n [disabled]=\"!SelectedReassignUser || IsReassigning\">\n @if (IsReassigning) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Reassigning...\n } @else {\n <i class=\"fa-solid fa-user-plus\"></i> Reassign\n }\n </button>\n <button\n class=\"btn btn-cancel\"\n (click)=\"OnReassignCancel()\"\n [disabled]=\"IsReassigning\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n}\n"]}
1
+ {"version":3,"file":"agent-request-panel.component.js","sourceRoot":"","sources":["../../../../src/lib/panels/agent-request-panel/agent-request-panel.component.ts","../../../../src/lib/panels/agent-request-panel/agent-request-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Agent Request Panel Component\n *\n * Slide-in panel for viewing and responding to AI agent feedback requests.\n * Displays request details, renders ResponseSchema as a dynamic form,\n * and submits ResponseData back to the request entity.\n */\n\nimport {\n Component, Input, Output, EventEmitter, ChangeDetectorRef,\n ChangeDetectionStrategy, OnInit, OnDestroy, HostListener, ViewChild, ElementRef\n} from '@angular/core';\nimport { MJAIAgentRequestEntity, MJAIAgentRequestTypeEntity } from '@memberjunction/core-entities';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { RunView } from '@memberjunction/core';\nimport { UserInfoEngine } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { AgentResponseForm } from '@memberjunction/ai-core-plus';\nimport { DynamicFormComponent } from '@memberjunction/ng-forms';\n\nconst PANEL_WIDTH_SETTING_KEY = 'Explorer.AgentRequestPanelWidth';\nconst DEFAULT_PANEL_WIDTH = 520;\nconst MIN_PANEL_WIDTH = 360;\nconst MAX_PANEL_WIDTH = 900;\n\n/**\n * Result returned when the panel closes after an action\n */\nexport interface AgentRequestPanelResult {\n /** Whether an action was taken (responded, approved, rejected) */\n Success: boolean;\n /** The updated request entity */\n Request?: MJAIAgentRequestEntity;\n /** The action that was taken */\n Action: 'responded' | 'approved' | 'rejected' | 'cancelled';\n}\n\n@Component({\n standalone: false,\n selector: 'mj-agent-request-panel',\n templateUrl: './agent-request-panel.component.html',\n styleUrls: ['./agent-request-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AgentRequestPanelComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n @Input() Request: MJAIAgentRequestEntity | null = null;\n @Input() RequestTypes: MJAIAgentRequestTypeEntity[] = [];\n @Input() IsOpen = false;\n\n @Output() Close = new EventEmitter<AgentRequestPanelResult>();\n\n @ViewChild('dynamicForm') dynamicForm: DynamicFormComponent | undefined;\n @ViewChild('panelElement') panelElement: ElementRef<HTMLDivElement> | undefined;\n\n public IsLoading = false;\n public IsSaving = false;\n public ResponseText = '';\n public ResponseFormDefinition: AgentResponseForm | null = null;\n public PanelWidth = DEFAULT_PANEL_WIDTH;\n\n /** Tracks whether a response was submitted so the Close event carries the right result */\n private completedAction: 'responded' | 'approved' | 'rejected' | null = null;\n\n // Resize state\n public IsResizing = false;\n private resizeStartX = 0;\n private resizeStartWidth = 0;\n private boundOnResizeMove: ((e: MouseEvent) => void) | null = null;\n private boundOnResizeEnd: (() => void) | null = null;\n\n // Reassign state\n public ShowReassignDialog = false;\n public ReassignSearchTerm = '';\n public ReassignNote = '';\n public ReassignUsers: Array<{ ID: string; Name: string; Email: string }> = [];\n public SelectedReassignUser: { ID: string; Name: string; Email: string } | null = null;\n public IsSearchingUsers = false;\n public IsReassigning = false;\n\n private reassignSearchTimeout: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n private cdr: ChangeDetectorRef,\n private notificationService: MJNotificationService\n ) {\n super();}\n\n ngOnInit(): void {\n this.loadPanelWidth();\n if (this.Request) {\n this.initializeForm();\n }\n }\n\n ngOnDestroy(): void {\n this.cleanupResizeListeners();\n }\n\n @HostListener('document:keydown.escape')\n public OnEscapeKey(): void {\n if (this.IsOpen) {\n this.OnCancel();\n }\n }\n\n /** The request type entity for the current request */\n public get RequestType(): MJAIAgentRequestTypeEntity | null {\n if (!this.Request?.RequestTypeID) return null;\n return this.RequestTypes.find(t => UUIDsEqual(t.ID, this.Request!.RequestTypeID!)) ?? null;\n }\n\n /** Whether this request is still actionable (status = Requested) */\n public get IsActionable(): boolean {\n return this.Request?.Status === 'Requested';\n }\n\n /** Whether this is an approval-type request (show approve/reject buttons) */\n public get IsApprovalType(): boolean {\n const typeName = this.RequestType?.Name;\n return typeName === 'Approval';\n }\n\n /** Whether the request has a structured response form */\n public get HasResponseForm(): boolean {\n return this.ResponseFormDefinition != null && (this.ResponseFormDefinition.questions?.length ?? 0) > 0;\n }\n\n /** Priority display label */\n public get PriorityLabel(): string {\n if (!this.Request) return '';\n const p = this.Request.Priority;\n if (p <= 25) return 'Low';\n if (p <= 50) return 'Normal';\n if (p <= 75) return 'High';\n return 'Critical';\n }\n\n /** Priority CSS class */\n public get PriorityClass(): string {\n if (!this.Request) return '';\n const p = this.Request.Priority;\n if (p <= 25) return 'priority-low';\n if (p <= 50) return 'priority-normal';\n if (p <= 75) return 'priority-high';\n return 'priority-critical';\n }\n\n /** Whether the request is expired */\n public get IsExpired(): boolean {\n if (!this.Request?.ExpiresAt) return false;\n return new Date(this.Request.ExpiresAt) < new Date();\n }\n\n /**\n * Opens the panel with a specific request\n */\n public Open(request: MJAIAgentRequestEntity): void {\n this.Request = request;\n this.IsOpen = true;\n this.ResponseText = '';\n this.completedAction = null;\n this.initializeForm();\n this.cdr.markForCheck();\n }\n\n /**\n * Approve the request\n */\n public async OnApprove(): Promise<void> {\n await this.submitResponse('Approved', 'approved');\n }\n\n /**\n * Reject the request\n */\n public async OnReject(): Promise<void> {\n await this.submitResponse('Rejected', 'rejected');\n }\n\n /**\n * Submit a response (for non-approval types)\n */\n public async OnRespond(): Promise<void> {\n await this.submitResponse('Responded', 'responded');\n }\n\n /**\n * Cancel / close the panel without action\n */\n public OnCancel(): void {\n this.IsOpen = false;\n if (this.completedAction) {\n // A response was submitted — tell the parent about the action taken\n this.Close.emit({ Success: true, Request: this.Request!, Action: this.completedAction });\n this.completedAction = null;\n } else {\n this.Close.emit({ Success: false, Action: 'cancelled' });\n }\n this.cdr.markForCheck();\n }\n\n public OnBackdropClick(): void {\n this.OnCancel();\n }\n\n /** Open the reassign dialog */\n public OnReassignClick(): void {\n this.ShowReassignDialog = true;\n this.ReassignSearchTerm = '';\n this.ReassignNote = '';\n this.ReassignUsers = [];\n this.SelectedReassignUser = null;\n this.cdr.markForCheck();\n }\n\n /** Close the reassign dialog */\n public OnReassignCancel(): void {\n this.ShowReassignDialog = false;\n this.cdr.markForCheck();\n }\n\n /** Search users by name/email for reassignment */\n public OnReassignSearchChange(term: string): void {\n this.ReassignSearchTerm = term;\n if (this.reassignSearchTimeout) {\n clearTimeout(this.reassignSearchTimeout);\n }\n if (term.length < 2) {\n this.ReassignUsers = [];\n this.cdr.markForCheck();\n return;\n }\n this.reassignSearchTimeout = setTimeout(() => this.searchUsers(term), 300);\n }\n\n /** Select a user from the search results */\n public OnSelectReassignUser(user: { ID: string; Name: string; Email: string }): void {\n this.SelectedReassignUser = user;\n this.cdr.markForCheck();\n }\n\n /** Submit the reassignment */\n public async OnReassignSubmit(): Promise<void> {\n if (!this.Request || !this.SelectedReassignUser || this.IsReassigning) return;\n\n this.IsReassigning = true;\n this.cdr.markForCheck();\n\n try {\n this.Request.RequestForUserID = this.SelectedReassignUser.ID;\n\n // Append reassignment note to Comments\n const timestamp = new Date().toISOString();\n const reassignEntry = `[${timestamp}] Reassigned to ${this.SelectedReassignUser.Name || this.SelectedReassignUser.Email}${this.ReassignNote ? ` — \"${this.ReassignNote}\"` : ''}`;\n this.Request.Comments = this.Request.Comments\n ? `${this.Request.Comments}\\n${reassignEntry}`\n : reassignEntry;\n\n const saved = await this.Request.Save();\n if (saved) {\n this.notificationService.CreateSimpleNotification(\n `Request reassigned to ${this.SelectedReassignUser.Name || this.SelectedReassignUser.Email}`, 'success', 3000\n );\n this.ShowReassignDialog = false;\n this.IsOpen = false;\n this.Close.emit({ Success: true, Request: this.Request, Action: 'cancelled' });\n } else {\n this.notificationService.CreateSimpleNotification(\n 'Failed to reassign request. Please try again.', 'error', 5000\n );\n }\n } catch (error) {\n console.error('Error reassigning request:', error);\n this.notificationService.CreateSimpleNotification(\n 'An unexpected error occurred.', 'error', 5000\n );\n } finally {\n this.IsReassigning = false;\n this.cdr.markForCheck();\n }\n }\n\n private async searchUsers(term: string): Promise<void> {\n this.IsSearchingUsers = true;\n this.cdr.markForCheck();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const result = await rv.RunView<{ ID: string; Name: string; Email: string }>({\n EntityName: 'Users',\n ExtraFilter: `(Name LIKE '%${term.replace(/'/g, \"''\")}%' OR Email LIKE '%${term.replace(/'/g, \"''\")}%')`,\n OrderBy: 'Name',\n MaxRows: 10,\n Fields: ['ID', 'Name', 'Email'],\n ResultType: 'simple'\n });\n this.ReassignUsers = result.Success ? result.Results : [];\n } catch {\n this.ReassignUsers = [];\n } finally {\n this.IsSearchingUsers = false;\n this.cdr.markForCheck();\n }\n }\n\n // ========================================================================\n // Resize\n // ========================================================================\n\n /** Begin resizing when the user mousedowns on the resize handle */\n public OnResizeStart(event: MouseEvent): void {\n event.preventDefault();\n this.IsResizing = true;\n this.resizeStartX = event.clientX;\n this.resizeStartWidth = this.PanelWidth;\n\n this.boundOnResizeMove = (e: MouseEvent) => this.onResizeMove(e);\n this.boundOnResizeEnd = () => this.onResizeEnd();\n document.addEventListener('mousemove', this.boundOnResizeMove);\n document.addEventListener('mouseup', this.boundOnResizeEnd);\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n }\n\n private onResizeMove(event: MouseEvent): void {\n // Panel is on the right, so dragging left (negative deltaX) increases width\n const deltaX = this.resizeStartX - event.clientX;\n const newWidth = Math.max(MIN_PANEL_WIDTH, Math.min(MAX_PANEL_WIDTH, this.resizeStartWidth + deltaX));\n this.PanelWidth = newWidth;\n this.cdr.markForCheck();\n }\n\n private onResizeEnd(): void {\n this.IsResizing = false;\n this.cleanupResizeListeners();\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n this.savePanelWidth();\n this.cdr.markForCheck();\n }\n\n private cleanupResizeListeners(): void {\n if (this.boundOnResizeMove) {\n document.removeEventListener('mousemove', this.boundOnResizeMove);\n this.boundOnResizeMove = null;\n }\n if (this.boundOnResizeEnd) {\n document.removeEventListener('mouseup', this.boundOnResizeEnd);\n this.boundOnResizeEnd = null;\n }\n }\n\n private loadPanelWidth(): void {\n try {\n const saved = UserInfoEngine.Instance.GetSetting(PANEL_WIDTH_SETTING_KEY);\n if (saved) {\n const parsed = parseInt(saved, 10);\n if (!isNaN(parsed) && parsed >= MIN_PANEL_WIDTH && parsed <= MAX_PANEL_WIDTH) {\n this.PanelWidth = parsed;\n }\n }\n } catch {\n // UserInfoEngine may not be initialized yet — use default\n }\n }\n\n private savePanelWidth(): void {\n try {\n UserInfoEngine.Instance.SetSettingDebounced(PANEL_WIDTH_SETTING_KEY, String(this.PanelWidth));\n } catch {\n // Silently ignore save failures\n }\n }\n\n // ========================================================================\n // Form handling\n // ========================================================================\n\n /**\n * Parse the ResponseSchema JSON into an AgentResponseForm for the dynamic form component.\n */\n private initializeForm(): void {\n this.ResponseFormDefinition = null;\n\n if (!this.Request?.ResponseSchema) return;\n\n try {\n const schema = JSON.parse(this.Request.ResponseSchema) as AgentResponseForm;\n if (schema?.questions && Array.isArray(schema.questions)) {\n this.ResponseFormDefinition = schema;\n }\n } catch {\n // If schema is invalid JSON, ignore — user can still provide free-text response\n }\n }\n\n /**\n * Collect current form values from the DynamicFormComponent's reactive FormGroup.\n * This reads values directly so the user doesn't need to click the form's\n * internal submit button before clicking the panel's action buttons.\n */\n private collectFormData(): Record<string, unknown> | null {\n if (!this.dynamicForm?.FormGroup) return null;\n const values = this.dynamicForm.FormGroup.value;\n if (values && Object.keys(values).length > 0) {\n return values;\n }\n return null;\n }\n\n /**\n * Shared logic for submitting any response type\n */\n private async submitResponse(\n status: 'Approved' | 'Rejected' | 'Responded',\n action: 'approved' | 'rejected' | 'responded'\n ): Promise<void> {\n if (!this.Request || this.IsSaving) return;\n\n this.IsSaving = true;\n this.cdr.markForCheck();\n\n try {\n this.Request.Status = status;\n this.Request.Response = this.ResponseText || null;\n this.Request.RespondedAt = new Date();\n\n const formData = this.collectFormData();\n if (formData) {\n this.Request.ResponseData = JSON.stringify(formData);\n }\n\n const saved = await this.Request.Save();\n if (saved) {\n this.notificationService.CreateSimpleNotification(\n `Agent request has been ${action} successfully.`, 'success', 3000\n );\n // Keep panel open so the user can see their submitted response.\n // Template auto-switches to read-only mode since IsActionable becomes false.\n this.completedAction = action;\n } else {\n this.notificationService.CreateSimpleNotification(\n 'Failed to save response. Please try again.', 'error', 5000\n );\n }\n } catch (error) {\n console.error('Error submitting response:', error);\n this.notificationService.CreateSimpleNotification(\n 'An unexpected error occurred while saving the response.', 'error', 5000\n );\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n}\n","@if (IsOpen && Request) {\n <div class=\"panel-backdrop\" (click)=\"OnBackdropClick()\">\n <div class=\"request-panel\" #panelElement [class.open]=\"IsOpen\" [class.resizing]=\"IsResizing\" [style.width.px]=\"PanelWidth\" (click)=\"$event.stopPropagation()\">\n <!-- Resize Handle (left edge) -->\n <div class=\"resize-handle\" (mousedown)=\"OnResizeStart($event)\">\n <div class=\"resize-grip\"></div>\n </div>\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-content\">\n <div class=\"header-title-row\">\n @if (RequestType?.Icon) {\n <i class=\"{{ RequestType!.Icon }} header-icon\"></i>\n }\n <h3 class=\"panel-title\">{{ RequestType?.Name || 'Agent Request' }}</h3>\n <span class=\"priority-badge\" [class]=\"PriorityClass\">{{ PriorityLabel }}</span>\n <span class=\"status-badge status-{{ Request.Status.toLowerCase() }}\">{{ Request.Status }}</span>\n </div>\n @if (Request.Agent) {\n <span class=\"agent-name\">\n <i class=\"fa-solid fa-robot\"></i> {{ Request.Agent }}\n </span>\n }\n </div>\n <button class=\"close-btn\" (click)=\"OnCancel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"panel-body\">\n <!-- Request Details -->\n <div class=\"section\">\n <h4 class=\"section-title\">Request</h4>\n <p class=\"request-text\">{{ Request.Request }}</p>\n </div>\n\n <!-- Metadata -->\n <div class=\"section metadata-section\">\n <div class=\"metadata-grid\">\n @if (Request.ExpiresAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Expires</span>\n <span class=\"metadata-value\" [class.expired]=\"IsExpired\">\n {{ Request.ExpiresAt | date:'medium' }}\n @if (IsExpired) {\n <span class=\"expired-tag\">Expired</span>\n }\n </span>\n </div>\n }\n @if (Request.__mj_CreatedAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Created</span>\n <span class=\"metadata-value\">{{ Request.__mj_CreatedAt | date:'medium' }}</span>\n </div>\n }\n @if (Request.RespondedAt) {\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Responded</span>\n <span class=\"metadata-value\">{{ Request.RespondedAt | date:'medium' }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Dynamic Response Form (from ResponseSchema) -->\n @if (HasResponseForm && IsActionable && ResponseFormDefinition) {\n <div class=\"section\">\n <mj-dynamic-form #dynamicForm\n [FormDefinition]=\"ResponseFormDefinition\"\n [Disabled]=\"IsSaving\">\n </mj-dynamic-form>\n </div>\n }\n\n <!-- Free-text response (always available for actionable requests) -->\n @if (IsActionable) {\n <div class=\"section\">\n <h4 class=\"section-title\">\n @if (HasResponseForm) {\n Additional Comments\n } @else {\n Response\n }\n </h4>\n <textarea\n class=\"response-textarea\"\n [(ngModel)]=\"ResponseText\"\n placeholder=\"Type your response here...\"\n rows=\"4\">\n </textarea>\n </div>\n }\n\n <!-- Show existing response for already-handled requests -->\n @if (!IsActionable && (Request.Response || Request.ResponseData)) {\n @if (Request.ResponseData) {\n <div class=\"section\">\n <mj-dynamic-form-response\n [FormDefinition]=\"ResponseFormDefinition\"\n [ResponseData]=\"Request.ResponseData\"\n DisplayMode=\"card\">\n </mj-dynamic-form-response>\n </div>\n }\n @if (Request.Response) {\n <div class=\"section\">\n <h4 class=\"section-title\">\n @if (Request.ResponseData) {\n Additional Comments\n } @else {\n Response\n }\n </h4>\n <p class=\"response-text\">{{ Request.Response }}</p>\n </div>\n }\n }\n </div>\n\n <!-- Footer (action buttons) -->\n @if (IsActionable && !IsExpired) {\n <div class=\"panel-footer\">\n @if (IsApprovalType) {\n <button\n class=\"btn btn-approve\"\n (click)=\"OnApprove()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-check\"></i> Approve\n </button>\n <button\n class=\"btn btn-reject\"\n (click)=\"OnReject()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-times\"></i> Reject\n </button>\n } @else {\n <button\n class=\"btn btn-respond\"\n (click)=\"OnRespond()\"\n [disabled]=\"IsSaving\">\n <i class=\"fa-solid fa-paper-plane\"></i> Submit Response\n </button>\n }\n <button\n class=\"btn btn-reassign\"\n (click)=\"OnReassignClick()\"\n [disabled]=\"IsSaving\"\n title=\"Reassign to another user\">\n <i class=\"fa-solid fa-user-plus\"></i> Reassign\n </button>\n <button\n class=\"btn btn-cancel\"\n (click)=\"OnCancel()\"\n [disabled]=\"IsSaving\">\n Cancel\n </button>\n </div>\n } @else if (IsExpired) {\n <div class=\"panel-footer\">\n <div class=\"expired-notice\">\n <i class=\"fa-solid fa-clock\"></i> This request has expired and can no longer be responded to.\n </div>\n <button class=\"btn btn-cancel\" (click)=\"OnCancel()\">Close</button>\n </div>\n } @else {\n <div class=\"panel-footer\">\n <button class=\"btn btn-cancel\" (click)=\"OnCancel()\">Close</button>\n </div>\n }\n </div>\n </div>\n\n <!-- Reassign Dialog Overlay -->\n @if (ShowReassignDialog) {\n <div class=\"reassign-overlay\" (click)=\"OnReassignCancel()\">\n <div class=\"reassign-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"reassign-header\">\n <h4 class=\"reassign-title\">\n <i class=\"fa-solid fa-user-plus\"></i> Reassign Request\n </h4>\n <button class=\"close-btn\" (click)=\"OnReassignCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"reassign-body\">\n <!-- User Search -->\n <div class=\"reassign-field\">\n <label class=\"field-label\">Search User</label>\n <div class=\"search-input-wrapper\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"field-input search-input\"\n placeholder=\"Type a name or email...\"\n [value]=\"ReassignSearchTerm\"\n (input)=\"OnReassignSearchChange($any($event.target).value)\">\n </div>\n </div>\n\n <!-- Search Results -->\n @if (IsSearchingUsers) {\n <div class=\"search-status\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Searching...\n </div>\n }\n @if (ReassignUsers.length > 0) {\n <div class=\"user-results\">\n @for (user of ReassignUsers; track user.ID) {\n <button\n class=\"user-result-item\"\n [class.selected]=\"SelectedReassignUser?.ID === user.ID\"\n (click)=\"OnSelectReassignUser(user)\">\n <i class=\"fa-solid fa-user user-avatar\"></i>\n <div class=\"user-info\">\n <span class=\"user-name\">{{ user.Name }}</span>\n <span class=\"user-email\">{{ user.Email }}</span>\n </div>\n @if (SelectedReassignUser?.ID === user.ID) {\n <i class=\"fa-solid fa-check selected-check\"></i>\n }\n </button>\n }\n </div>\n } @else if (ReassignSearchTerm.length >= 2 && !IsSearchingUsers) {\n <div class=\"search-status\">No users found</div>\n }\n\n <!-- Note -->\n <div class=\"reassign-field\">\n <label class=\"field-label\">Note (optional)</label>\n <textarea\n class=\"field-textarea\"\n [(ngModel)]=\"ReassignNote\"\n placeholder=\"Add a reason for reassignment...\"\n rows=\"2\">\n </textarea>\n </div>\n </div>\n\n <div class=\"reassign-footer\">\n <button\n class=\"btn btn-respond\"\n (click)=\"OnReassignSubmit()\"\n [disabled]=\"!SelectedReassignUser || IsReassigning\">\n @if (IsReassigning) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Reassigning...\n } @else {\n <i class=\"fa-solid fa-user-plus\"></i> Reassign\n }\n </button>\n <button\n class=\"btn btn-cancel\"\n (click)=\"OnReassignCancel()\"\n [disabled]=\"IsReassigning\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n}\n"]}
package/package.json CHANGED
@@ -1,17 +1,12 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-agent-requests",
3
- "version": "5.51.0",
3
+ "version": "6.1.0-edge.1",
4
4
  "description": "MemberJunction: Angular components for AI agent request management - panels and dialogs for viewing and responding to agent feedback requests",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
7
7
  "files": [
8
8
  "/dist"
9
9
  ],
10
- "scripts": {
11
- "test": "vitest run",
12
- "build": "ngc",
13
- "test:watch": "vitest"
14
- },
15
10
  "keywords": [
16
11
  "memberjunction",
17
12
  "agent-requests",
@@ -24,28 +19,36 @@
24
19
  "devDependencies": {
25
20
  "@angular/compiler": "21.1.3",
26
21
  "@angular/compiler-cli": "21.1.3",
27
- "@memberjunction/ng-test-utils": "5.51.0",
22
+ "@memberjunction/ng-test-utils": "6.1.0-edge.1",
28
23
  "vitest": "^4.0.18"
29
24
  },
30
25
  "peerDependencies": {
31
- "@angular/common": "21.1.3",
32
- "@angular/core": "21.1.3",
33
- "@angular/forms": "21.1.3"
26
+ "@angular/common": "^21.1.3",
27
+ "@angular/core": "^21.1.3",
28
+ "@angular/forms": "^21.1.3"
34
29
  },
35
30
  "dependencies": {
36
- "@memberjunction/core": "5.51.0",
37
- "@memberjunction/core-entities": "5.51.0",
38
- "@memberjunction/global": "5.51.0",
39
- "@memberjunction/ai-core-plus": "5.51.0",
40
- "@memberjunction/ng-forms": "5.51.0",
41
- "@memberjunction/ng-notifications": "5.51.0",
42
- "@memberjunction/ng-shared-generic": "5.51.0",
43
- "tslib": "^2.8.1",
44
- "rxjs": "^7.8.2"
31
+ "@memberjunction/ai-core-plus": "6.1.0-edge.1",
32
+ "@memberjunction/core": "6.1.0-edge.1",
33
+ "@memberjunction/core-entities": "6.1.0-edge.1",
34
+ "@memberjunction/global": "6.1.0-edge.1",
35
+ "@memberjunction/ng-base-types": "6.1.0-edge.1",
36
+ "@memberjunction/ng-forms": "6.1.0-edge.1",
37
+ "@memberjunction/ng-notifications": "6.1.0-edge.1",
38
+ "@memberjunction/ng-shared-generic": "6.1.0-edge.1",
39
+ "rxjs": "^7.8.2",
40
+ "tslib": "^2.8.1"
45
41
  },
46
42
  "sideEffects": false,
47
43
  "repository": {
48
44
  "type": "git",
49
45
  "url": "https://github.com/MemberJunction/MJ"
46
+ },
47
+ "mjUILayer": "widgets",
48
+ "scripts": {
49
+ "test": "vitest run",
50
+ "test:types": "tsc --noEmit -p tsconfig.spec.json",
51
+ "build": "ngc",
52
+ "test:watch": "vitest"
50
53
  }
51
- }
54
+ }