@memberjunction/ng-dashboards 5.36.0 → 5.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +14 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +450 -292
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +73 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +512 -127
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-resource.component.d.ts +22 -0
- package/dist/ComponentStudio/component-studio-resource.component.d.ts.map +1 -0
- package/dist/ComponentStudio/component-studio-resource.component.js +55 -0
- package/dist/ComponentStudio/component-studio-resource.component.js.map +1 -0
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +104 -45
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +234 -331
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts +54 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js +339 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts +65 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js +492 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts +88 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js +457 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts +106 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js +478 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js.map +1 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +54 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +361 -50
- package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts +10 -0
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +114 -45
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
- package/dist/ComponentStudio/services/canvas-to-code.d.ts +32 -0
- package/dist/ComponentStudio/services/canvas-to-code.d.ts.map +1 -0
- package/dist/ComponentStudio/services/canvas-to-code.js +347 -0
- package/dist/ComponentStudio/services/canvas-to-code.js.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts +32 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.js +92 -0
- package/dist/ComponentStudio/services/code-to-canvas.js.map +1 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts +29 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.js +76 -0
- package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts +86 -0
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts.map +1 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js +246 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts +29 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js +110 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts +56 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.js +35 -0
- package/dist/ComponentStudio/services/form-canvas-model.js.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js.map +1 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.d.ts +964 -0
- package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-resource.component.js +4487 -0
- package/dist/FormBuilder/form-builder-resource.component.js.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts +55 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js +73 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js.map +1 -0
- package/dist/Home/home-application.d.ts +21 -1
- package/dist/Home/home-application.d.ts.map +1 -1
- package/dist/Home/home-application.js +60 -8
- package/dist/Home/home-application.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +14 -14
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +11 -10
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/component-studio-dashboards.module.d.ts +34 -22
- package/dist/component-studio-dashboards.module.d.ts.map +1 -1
- package/dist/component-studio-dashboards.module.js +65 -9
- package/dist/component-studio-dashboards.module.js.map +1 -1
- package/package.json +54 -53
|
@@ -1,402 +1,305 @@
|
|
|
1
|
-
import { Component,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, } from '@angular/core';
|
|
2
|
+
import { CompositeKey, LogError } from '@memberjunction/core';
|
|
3
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
4
|
+
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
5
5
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
6
|
+
import { Subject, takeUntil } from 'rxjs';
|
|
7
|
+
import { MJEnvironmentEntityExtended } from '@memberjunction/core-entities';
|
|
8
|
+
import { NavigationService } from '@memberjunction/ng-shared';
|
|
6
9
|
import * as i0 from "@angular/core";
|
|
7
10
|
import * as i1 from "../../services/component-studio-state.service";
|
|
8
|
-
import * as i2 from "@
|
|
9
|
-
const _c0 = ["chatThread"];
|
|
10
|
-
const _c1 = ["chatInput"];
|
|
11
|
+
import * as i2 from "@memberjunction/ng-conversations";
|
|
11
12
|
const _forTrack0 = ($index, $item) => $item.Label;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
i0.ɵɵelementStart(0, "
|
|
15
|
-
i0.ɵɵ
|
|
16
|
-
i0.ɵɵelementStart(2, "span");
|
|
17
|
-
i0.ɵɵtext(3, "Loading models...");
|
|
18
|
-
i0.ɵɵelementEnd()();
|
|
19
|
-
} }
|
|
20
|
-
function AIAssistantPanelComponent_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
21
|
-
i0.ɵɵelementStart(0, "option", 27);
|
|
22
|
-
i0.ɵɵtext(1);
|
|
23
|
-
i0.ɵɵelementEnd();
|
|
24
|
-
} if (rf & 2) {
|
|
25
|
-
const model_r4 = ctx.$implicit;
|
|
26
|
-
i0.ɵɵproperty("value", model_r4.ID);
|
|
27
|
-
i0.ɵɵadvance();
|
|
28
|
-
i0.ɵɵtextInterpolate(model_r4.DisplayLabel);
|
|
29
|
-
} }
|
|
30
|
-
function AIAssistantPanelComponent_Conditional_13_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
31
|
-
i0.ɵɵelementStart(0, "option", 28);
|
|
32
|
-
i0.ɵɵtext(1, "No models available");
|
|
33
|
-
i0.ɵɵelementEnd();
|
|
34
|
-
} if (rf & 2) {
|
|
35
|
-
i0.ɵɵproperty("value", null);
|
|
36
|
-
} }
|
|
37
|
-
function AIAssistantPanelComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
38
|
-
const _r2 = i0.ɵɵgetCurrentView();
|
|
39
|
-
i0.ɵɵelementStart(0, "select", 26);
|
|
40
|
-
i0.ɵɵtwoWayListener("ngModelChange", function AIAssistantPanelComponent_Conditional_13_Template_select_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.SelectedModelID, $event) || (ctx_r2.SelectedModelID = $event); return i0.ɵɵresetView($event); });
|
|
41
|
-
i0.ɵɵrepeaterCreate(1, AIAssistantPanelComponent_Conditional_13_For_2_Template, 2, 2, "option", 27, _forTrack1);
|
|
42
|
-
i0.ɵɵconditionalCreate(3, AIAssistantPanelComponent_Conditional_13_Conditional_3_Template, 2, 1, "option", 28);
|
|
43
|
-
i0.ɵɵelementEnd();
|
|
44
|
-
} if (rf & 2) {
|
|
45
|
-
const ctx_r2 = i0.ɵɵnextContext();
|
|
46
|
-
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.SelectedModelID);
|
|
47
|
-
i0.ɵɵproperty("disabled", ctx_r2.AvailableModels.length === 0);
|
|
48
|
-
i0.ɵɵadvance();
|
|
49
|
-
i0.ɵɵrepeater(ctx_r2.AvailableModels);
|
|
50
|
-
i0.ɵɵadvance(2);
|
|
51
|
-
i0.ɵɵconditional(ctx_r2.AvailableModels.length === 0 ? 3 : -1);
|
|
52
|
-
} }
|
|
53
|
-
function AIAssistantPanelComponent_For_16_Template(rf, ctx) { if (rf & 1) {
|
|
54
|
-
const _r5 = i0.ɵɵgetCurrentView();
|
|
55
|
-
i0.ɵɵelementStart(0, "button", 29);
|
|
56
|
-
i0.ɵɵlistener("click", function AIAssistantPanelComponent_For_16_Template_button_click_0_listener() { const action_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnQuickAction(action_r6)); });
|
|
13
|
+
function AIAssistantPanelComponent_For_10_Template(rf, ctx) { if (rf & 1) {
|
|
14
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
15
|
+
i0.ɵɵelementStart(0, "button", 11);
|
|
16
|
+
i0.ɵɵlistener("click", function AIAssistantPanelComponent_For_10_Template_button_click_0_listener() { const action_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnQuickAction(action_r2)); });
|
|
57
17
|
i0.ɵɵelement(1, "i");
|
|
58
18
|
i0.ɵɵelementStart(2, "span");
|
|
59
19
|
i0.ɵɵtext(3);
|
|
60
20
|
i0.ɵɵelementEnd()();
|
|
61
21
|
} if (rf & 2) {
|
|
62
|
-
const
|
|
22
|
+
const action_r2 = ctx.$implicit;
|
|
63
23
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
64
|
-
i0.ɵɵclassProp("disabled", !ctx_r2.IsQuickActionEnabled(
|
|
65
|
-
i0.ɵɵproperty("disabled", !ctx_r2.IsQuickActionEnabled(
|
|
24
|
+
i0.ɵɵclassProp("disabled", !ctx_r2.IsQuickActionEnabled(action_r2));
|
|
25
|
+
i0.ɵɵproperty("disabled", !ctx_r2.IsQuickActionEnabled(action_r2))("title", action_r2.Label);
|
|
66
26
|
i0.ɵɵadvance();
|
|
67
|
-
i0.ɵɵclassMap(i0.ɵɵinterpolate1("fa-solid ",
|
|
27
|
+
i0.ɵɵclassMap(i0.ɵɵinterpolate1("fa-solid ", action_r2.Icon));
|
|
68
28
|
i0.ɵɵadvance(2);
|
|
69
|
-
i0.ɵɵtextInterpolate(
|
|
29
|
+
i0.ɵɵtextInterpolate(action_r2.Label);
|
|
70
30
|
} }
|
|
71
|
-
function
|
|
72
|
-
i0.ɵɵ
|
|
73
|
-
i0.ɵɵ
|
|
74
|
-
i0.ɵɵ
|
|
75
|
-
i0.ɵɵtext(3, "No messages yet. Start a conversation or use a quick action above.");
|
|
76
|
-
i0.ɵɵelementEnd()();
|
|
77
|
-
} }
|
|
78
|
-
function AIAssistantPanelComponent_For_21_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
79
|
-
i0.ɵɵelementStart(0, "div", 32);
|
|
80
|
-
i0.ɵɵelement(1, "i", 5);
|
|
81
|
-
i0.ɵɵelementEnd();
|
|
82
|
-
} }
|
|
83
|
-
function AIAssistantPanelComponent_For_21_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
84
|
-
i0.ɵɵelementStart(0, "div", 36);
|
|
85
|
-
i0.ɵɵelement(1, "i", 37);
|
|
86
|
-
i0.ɵɵelementEnd();
|
|
87
|
-
} }
|
|
88
|
-
function AIAssistantPanelComponent_For_21_Template(rf, ctx) { if (rf & 1) {
|
|
89
|
-
i0.ɵɵelementStart(0, "div", 31);
|
|
90
|
-
i0.ɵɵconditionalCreate(1, AIAssistantPanelComponent_For_21_Conditional_1_Template, 2, 0, "div", 32);
|
|
91
|
-
i0.ɵɵelementStart(2, "div", 33)(3, "div", 34);
|
|
92
|
-
i0.ɵɵtext(4);
|
|
93
|
-
i0.ɵɵelementEnd();
|
|
94
|
-
i0.ɵɵelementStart(5, "div", 35);
|
|
95
|
-
i0.ɵɵtext(6);
|
|
96
|
-
i0.ɵɵelementEnd()();
|
|
97
|
-
i0.ɵɵconditionalCreate(7, AIAssistantPanelComponent_For_21_Conditional_7_Template, 2, 0, "div", 36);
|
|
31
|
+
function AIAssistantPanelComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
32
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
33
|
+
i0.ɵɵelementStart(0, "mj-conversation-chat-area", 12);
|
|
34
|
+
i0.ɵɵlistener("conversationCreated", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_conversationCreated_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnConversationCreated($event)); })("pendingMessageConsumed", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_pendingMessageConsumed_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnPendingMessageConsumed()); })("openEntityRecord", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_openEntityRecord_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnOpenEntityRecord($event)); })("navigationRequest", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_navigationRequest_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnNavigationRequest($event)); })("taskClicked", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_taskClicked_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnTaskClicked($event)); })("artifactLinkClicked", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_artifactLinkClicked_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnArtifactLinkClicked($event)); })("conversationRenamed", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_conversationRenamed_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnConversationRenamed($event)); })("threadOpened", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_threadOpened_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnThreadOpened($event)); })("threadClosed", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_threadClosed_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnThreadClosed()); })("pendingArtifactConsumed", function AIAssistantPanelComponent_Conditional_12_Template_mj_conversation_chat_area_pendingArtifactConsumed_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnPendingArtifactConsumed()); });
|
|
98
35
|
i0.ɵɵelementEnd();
|
|
99
36
|
} if (rf & 2) {
|
|
100
|
-
const message_r7 = ctx.$implicit;
|
|
101
37
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
102
|
-
i0.ɵɵ
|
|
103
|
-
i0.ɵɵadvance();
|
|
104
|
-
i0.ɵɵconditional(message_r7.Role === "assistant" ? 1 : -1);
|
|
105
|
-
i0.ɵɵadvance();
|
|
106
|
-
i0.ɵɵclassProp("user-bubble", message_r7.Role === "user")("assistant-bubble", message_r7.Role === "assistant")("system-bubble", message_r7.Role === "system");
|
|
107
|
-
i0.ɵɵadvance(2);
|
|
108
|
-
i0.ɵɵtextInterpolate(message_r7.Content);
|
|
109
|
-
i0.ɵɵadvance(2);
|
|
110
|
-
i0.ɵɵtextInterpolate(ctx_r2.FormatTimestamp(message_r7.Timestamp));
|
|
111
|
-
i0.ɵɵadvance();
|
|
112
|
-
i0.ɵɵconditional(message_r7.Role === "user" ? 7 : -1);
|
|
38
|
+
i0.ɵɵproperty("Provider", ctx_r2.Provider)("environmentId", ctx_r2.EnvironmentId)("currentUser", ctx_r2.CurrentUser)("conversationId", ctx_r2.ChatConversationId)("conversation", ctx_r2.ChatConversation)("isNewConversation", ctx_r2.ChatIsNewConversation)("pendingMessage", ctx_r2.PendingMessage)("pendingAttachments", ctx_r2.PendingAttachments)("threadId", ctx_r2.ChatThreadId)("pendingArtifactId", ctx_r2.ChatPendingArtifactId)("pendingArtifactVersionNumber", ctx_r2.ChatPendingArtifactVersionNumber)("overlayMode", true)("showExportButton", false)("showShareButton", false)("showArtifactIndicator", false)("appContext", ctx_r2.ChatAppContext)("defaultAgentId", ctx_r2.CodesmithAgentId)("applicationScope", "Application")("applicationId", ctx_r2.CockpitApplicationId)("linkedEntityId", ctx_r2.ComponentsEntityID)("linkedRecordId", ctx_r2.LinkedComponentID)("emptyStateGreeting", "How can I help with this component?");
|
|
113
39
|
} }
|
|
114
|
-
function
|
|
115
|
-
i0.ɵɵelementStart(0, "div",
|
|
116
|
-
i0.ɵɵ
|
|
40
|
+
function AIAssistantPanelComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
41
|
+
i0.ɵɵelementStart(0, "div", 10);
|
|
42
|
+
i0.ɵɵtext(1, "Loading\u2026");
|
|
117
43
|
i0.ɵɵelementEnd();
|
|
118
|
-
i0.ɵɵelementStart(3, "div", 38)(4, "div", 39);
|
|
119
|
-
i0.ɵɵelement(5, "span", 40)(6, "span", 40)(7, "span", 40);
|
|
120
|
-
i0.ɵɵelementEnd()()();
|
|
121
44
|
} }
|
|
45
|
+
/**
|
|
46
|
+
* Component Studio's right-pane AI assistant.
|
|
47
|
+
*
|
|
48
|
+
* Previously this was a 880-line bespoke chat stub that emitted "AI
|
|
49
|
+
* assistant coming soon" — no agent was actually called. This version
|
|
50
|
+
* thin-wraps `<mj-conversation-chat-area>` (the same primitive the main
|
|
51
|
+
* Chat app and the Form Builder cockpit use) so the assistant becomes
|
|
52
|
+
* fully functional with zero duplicated chat plumbing.
|
|
53
|
+
*
|
|
54
|
+
* Domain integration preserved from the old stub:
|
|
55
|
+
* - **Quick-actions bar** (Fix Errors / Improve / Generate / Explain)
|
|
56
|
+
* above the chat — clicking sets `PendingMessage` which the chat-area
|
|
57
|
+
* consumes on the next render, mirroring the empty-state handoff.
|
|
58
|
+
* - **`SendErrorToAI` channel** — when the runtime preview throws, the
|
|
59
|
+
* state service emits a `ComponentError`. We listen and shove a
|
|
60
|
+
* "Fix this error: …" message into the same pendingMessage pipe so
|
|
61
|
+
* the user doesn't have to copy/paste error text.
|
|
62
|
+
*
|
|
63
|
+
* Scoping:
|
|
64
|
+
* - `[applicationScope]="'Application'"` + Component Studio app ID →
|
|
65
|
+
* conversations stay out of main chat (per the migration scoping work).
|
|
66
|
+
* - `[defaultAgentId]` → Codesmith Agent so messages route to the code
|
|
67
|
+
* specialist instead of Sage by default. User can still @mention any
|
|
68
|
+
* agent, override via the per-conversation pin, or pick a different
|
|
69
|
+
* agent through the chat header's picker.
|
|
70
|
+
*/
|
|
122
71
|
export class AIAssistantPanelComponent extends BaseAngularComponent {
|
|
123
72
|
State;
|
|
124
|
-
|
|
125
|
-
chatThreadEl;
|
|
126
|
-
chatInputEl;
|
|
127
|
-
// --- Chat State ---
|
|
128
|
-
Messages = [];
|
|
129
|
-
InputText = '';
|
|
130
|
-
IsWaitingForResponse = false;
|
|
131
|
-
// --- Model Selector ---
|
|
132
|
-
AvailableModels = [];
|
|
133
|
-
SelectedModelID = null;
|
|
134
|
-
IsLoadingModels = false;
|
|
135
|
-
// --- Quick Actions ---
|
|
73
|
+
/** Quick actions surfaced as buttons above the embedded chat. */
|
|
136
74
|
QuickActions = [
|
|
137
75
|
{ Label: 'Fix Errors', Icon: 'fa-bug', Prompt: 'Fix this error: ', RequiresError: true },
|
|
138
76
|
{ Label: 'Improve Code', Icon: 'fa-magic', Prompt: 'Review and improve the current component code. Suggest optimizations, better patterns, and cleaner structure.', RequiresError: false },
|
|
139
77
|
{ Label: 'Generate Code', Icon: 'fa-code', Prompt: 'Generate code for the current component based on its specification.', RequiresError: false },
|
|
140
|
-
{ Label: 'Explain', Icon: 'fa-question-circle', Prompt: 'Explain what the current component does, including its structure, data flow, and key behaviors.', RequiresError: false }
|
|
78
|
+
{ Label: 'Explain', Icon: 'fa-question-circle', Prompt: 'Explain what the current component does, including its structure, data flow, and key behaviors.', RequiresError: false },
|
|
141
79
|
];
|
|
80
|
+
/** Embedded chat state — same shape the Form Builder cockpit uses. */
|
|
81
|
+
ChatConversation = null;
|
|
82
|
+
ChatConversationId = null;
|
|
83
|
+
ChatIsNewConversation = true;
|
|
84
|
+
PendingMessage = null;
|
|
85
|
+
PendingAttachments = null;
|
|
86
|
+
ChatThreadId = null;
|
|
87
|
+
ChatPendingArtifactId = null;
|
|
88
|
+
ChatPendingArtifactVersionNumber = null;
|
|
89
|
+
/** Snapshot from NavigationService — drives the agent's app context. */
|
|
90
|
+
ChatAppContext = null;
|
|
91
|
+
/** Codesmith Agent ID resolved from AIEngineBase cache (no RunView). */
|
|
92
|
+
CodesmithAgentId = null;
|
|
93
|
+
/** Component Studio's Application ID — resolved from Metadata cache. */
|
|
94
|
+
CockpitApplicationId = null;
|
|
95
|
+
/**
|
|
96
|
+
* EntityID for `MJ: Components`. Stamped on every conversation
|
|
97
|
+
* created from this panel as the `LinkedEntityID`, paired with the
|
|
98
|
+
* currently-selected Component's ID. Enables "show prior conversations
|
|
99
|
+
* about THIS component" later. In-memory Metadata lookup; no RunView.
|
|
100
|
+
*/
|
|
101
|
+
ComponentsEntityID = null;
|
|
102
|
+
/**
|
|
103
|
+
* The DB-backed Component ID currently selected — null when the
|
|
104
|
+
* panel has nothing selected, or when the selection is a
|
|
105
|
+
* file-loaded (transient) component that has no persistent DB row
|
|
106
|
+
* to link conversations to. Used as `[linkedRecordId]` on the
|
|
107
|
+
* embedded chat-area. Pairs with {@link ComponentsEntityID}.
|
|
108
|
+
*/
|
|
109
|
+
get LinkedComponentID() {
|
|
110
|
+
const sel = this.State.SelectedComponent;
|
|
111
|
+
if (!sel)
|
|
112
|
+
return null;
|
|
113
|
+
// FileLoadedComponent has `isFileLoaded === true` and a lower-case
|
|
114
|
+
// `id`; DbComponentSummary has the canonical `ID`. Discriminate by
|
|
115
|
+
// the flag rather than property presence to keep TS happy.
|
|
116
|
+
if ('isFileLoaded' in sel && sel.isFileLoaded === true)
|
|
117
|
+
return null;
|
|
118
|
+
return sel.ID ?? null;
|
|
119
|
+
}
|
|
120
|
+
static CODESMITH_AGENT_NAME = 'Codesmith Agent';
|
|
121
|
+
static COCKPIT_APP_NAME = 'Component Studio';
|
|
142
122
|
destroy$ = new Subject();
|
|
143
|
-
|
|
123
|
+
appContextSubscription = null;
|
|
124
|
+
cdr = inject(ChangeDetectorRef);
|
|
125
|
+
navigationService = inject(NavigationService);
|
|
126
|
+
constructor(State) {
|
|
144
127
|
super();
|
|
145
128
|
this.State = State;
|
|
146
|
-
this.cdr = cdr;
|
|
147
129
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
await this.LoadModels();
|
|
151
|
-
this.addWelcomeMessage();
|
|
130
|
+
get EnvironmentId() {
|
|
131
|
+
return MJEnvironmentEntityExtended.DefaultEnvironmentID;
|
|
152
132
|
}
|
|
153
|
-
|
|
154
|
-
this.
|
|
155
|
-
this.destroy$.complete();
|
|
133
|
+
get CurrentUser() {
|
|
134
|
+
return this.ProviderToUse?.CurrentUser ?? null;
|
|
156
135
|
}
|
|
157
|
-
|
|
158
|
-
// MODEL LOADING
|
|
159
|
-
// ============================================================
|
|
160
|
-
async LoadModels() {
|
|
161
|
-
this.IsLoadingModels = true;
|
|
136
|
+
async ngOnInit() {
|
|
162
137
|
try {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
Name: model.Name,
|
|
174
|
-
Vendor: model.Vendor,
|
|
175
|
-
DisplayLabel: model.Vendor ? `${model.Name} (${model.Vendor})` : model.Name
|
|
176
|
-
}));
|
|
177
|
-
if (this.AvailableModels.length > 0) {
|
|
178
|
-
this.SelectedModelID = this.AvailableModels[0].ID;
|
|
179
|
-
}
|
|
138
|
+
// Resolve default agent + cockpit app ID from in-memory caches
|
|
139
|
+
// (no RunView round-trips). Both fall back to null cleanly:
|
|
140
|
+
// missing agent → routes through Sage; missing app → safety
|
|
141
|
+
// guard in chat-area demotes scope to 'Global'.
|
|
142
|
+
await AIEngineBase.Instance.Config(false);
|
|
143
|
+
const codesmith = AIEngineBase.Instance.Agents
|
|
144
|
+
?.find(a => a.Name?.trim().toLowerCase() === AIAssistantPanelComponent.CODESMITH_AGENT_NAME.toLowerCase());
|
|
145
|
+
this.CodesmithAgentId = codesmith?.ID ?? null;
|
|
146
|
+
if (!codesmith) {
|
|
147
|
+
LogError(`AIAssistantPanel: '${AIAssistantPanelComponent.CODESMITH_AGENT_NAME}' not found in AIEngineBase cache`);
|
|
180
148
|
}
|
|
149
|
+
const md = this.ProviderToUse;
|
|
150
|
+
const app = md.Applications?.find(a => a.Name?.trim().toLowerCase() === AIAssistantPanelComponent.COCKPIT_APP_NAME.toLowerCase());
|
|
151
|
+
this.CockpitApplicationId = app?.ID ?? null;
|
|
152
|
+
// Resolve MJ: Components entity ID for conversation linkage.
|
|
153
|
+
const componentsEntity = md.EntityByName?.('MJ: Components');
|
|
154
|
+
if (!componentsEntity) {
|
|
155
|
+
LogError(`AIAssistantPanel: Entity 'MJ: Components' not found in Metadata cache — conversation linkage will be skipped.`);
|
|
156
|
+
}
|
|
157
|
+
this.ComponentsEntityID = componentsEntity?.ID ?? null;
|
|
158
|
+
// Subscribe to the Explorer shell's app-context publisher so
|
|
159
|
+
// the agent sees the same snapshot the floating overlay sees.
|
|
160
|
+
this.appContextSubscription = this.navigationService.AppContextSnapshot$
|
|
161
|
+
.subscribe(snapshot => {
|
|
162
|
+
this.ChatAppContext = snapshot;
|
|
163
|
+
this.cdr.markForCheck();
|
|
164
|
+
});
|
|
165
|
+
// Wire the SendErrorToAI channel — when the runtime preview
|
|
166
|
+
// hits an error, push a canned "Fix this error: …" message
|
|
167
|
+
// into the chat-area's pendingMessage pipe so the user
|
|
168
|
+
// doesn't have to manually copy the error text.
|
|
169
|
+
this.State.SendErrorToAI
|
|
170
|
+
.pipe(takeUntil(this.destroy$))
|
|
171
|
+
.subscribe(err => this.handleIncomingError(err));
|
|
172
|
+
this.cdr.markForCheck();
|
|
181
173
|
}
|
|
182
|
-
catch (
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
finally {
|
|
186
|
-
this.IsLoadingModels = false;
|
|
187
|
-
this.cdr.detectChanges();
|
|
174
|
+
catch (err) {
|
|
175
|
+
LogError(`AIAssistantPanel.ngOnInit: ${err instanceof Error ? err.message : String(err)}`);
|
|
188
176
|
}
|
|
189
177
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
this.
|
|
195
|
-
.pipe(takeUntil(this.destroy$))
|
|
196
|
-
.subscribe((error) => {
|
|
197
|
-
this.handleIncomingError(error);
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
handleIncomingError(error) {
|
|
201
|
-
const errorDetails = error.technicalDetails
|
|
202
|
-
? (typeof error.technicalDetails === 'string' ? error.technicalDetails : JSON.stringify(error.technicalDetails, null, 2))
|
|
203
|
-
: '';
|
|
204
|
-
const systemContent = `Error detected [${error.type}]: ${error.message}${errorDetails ? '\n\nDetails:\n' + errorDetails : ''}`;
|
|
205
|
-
this.addMessage('system', systemContent);
|
|
206
|
-
this.InputText = `Fix this error: ${error.type} - ${error.message}`;
|
|
207
|
-
this.cdr.detectChanges();
|
|
208
|
-
this.focusInput();
|
|
209
|
-
}
|
|
210
|
-
// ============================================================
|
|
211
|
-
// WELCOME MESSAGE
|
|
212
|
-
// ============================================================
|
|
213
|
-
addWelcomeMessage() {
|
|
214
|
-
this.addMessage('assistant', 'Welcome to the Component Studio AI Assistant. I can help you fix errors, improve code, generate components, and explain how things work. Select a component and ask me anything!');
|
|
178
|
+
ngOnDestroy() {
|
|
179
|
+
this.destroy$.next();
|
|
180
|
+
this.destroy$.complete();
|
|
181
|
+
this.appContextSubscription?.unsubscribe();
|
|
182
|
+
this.appContextSubscription = null;
|
|
215
183
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const text = this.InputText.trim();
|
|
221
|
-
if (!text || this.IsWaitingForResponse)
|
|
222
|
-
return;
|
|
223
|
-
this.addMessage('user', text);
|
|
224
|
-
this.InputText = '';
|
|
225
|
-
this.resetInputHeight();
|
|
226
|
-
this.simulateResponse(text);
|
|
184
|
+
/** Collapse the right pane (delegated to the parent dashboard). */
|
|
185
|
+
OnCollapsePanel() {
|
|
186
|
+
this.State.IsAIPanelCollapsed = true;
|
|
187
|
+
this.State.StateChanged.emit();
|
|
227
188
|
}
|
|
189
|
+
/** Quick-action click — prefill the chat with the canned prompt. */
|
|
228
190
|
OnQuickAction(action) {
|
|
229
191
|
if (action.RequiresError && !this.State.CurrentError)
|
|
230
192
|
return;
|
|
193
|
+
let prompt = action.Prompt;
|
|
231
194
|
if (action.RequiresError && this.State.CurrentError) {
|
|
232
|
-
|
|
233
|
-
this.InputText = `${action.Prompt}${errorContext}`;
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
this.InputText = action.Prompt;
|
|
195
|
+
prompt += `${this.State.CurrentError.type} - ${this.State.CurrentError.message}`;
|
|
237
196
|
}
|
|
238
|
-
this.
|
|
239
|
-
this.
|
|
197
|
+
this.PendingMessage = prompt;
|
|
198
|
+
this.PendingAttachments = null;
|
|
199
|
+
this.cdr.markForCheck();
|
|
240
200
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
event.preventDefault();
|
|
244
|
-
this.OnSendMessage();
|
|
245
|
-
}
|
|
201
|
+
IsQuickActionEnabled(action) {
|
|
202
|
+
return !action.RequiresError || this.State.CurrentError != null;
|
|
246
203
|
}
|
|
247
|
-
|
|
248
|
-
|
|
204
|
+
/** Runtime preview surfaced an error — auto-send "Fix this error: …". */
|
|
205
|
+
handleIncomingError(error) {
|
|
206
|
+
const details = error.technicalDetails
|
|
207
|
+
? (typeof error.technicalDetails === 'string'
|
|
208
|
+
? error.technicalDetails
|
|
209
|
+
: JSON.stringify(error.technicalDetails, null, 2))
|
|
210
|
+
: '';
|
|
211
|
+
this.PendingMessage = `Fix this error: ${error.type} - ${error.message}${details ? '\n\nDetails:\n' + details : ''}`;
|
|
212
|
+
this.PendingAttachments = null;
|
|
213
|
+
this.cdr.markForCheck();
|
|
249
214
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.
|
|
215
|
+
// ── chat-area event wiring ───────────────────────────────────────
|
|
216
|
+
OnConversationCreated(event) {
|
|
217
|
+
this.PendingMessage = event.pendingMessage ?? null;
|
|
218
|
+
this.PendingAttachments = (event.pendingAttachments ?? null);
|
|
219
|
+
this.ChatConversation = event.conversation;
|
|
220
|
+
this.ChatConversationId = event.conversation.ID;
|
|
221
|
+
this.ChatIsNewConversation = false;
|
|
222
|
+
this.cdr.markForCheck();
|
|
253
223
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
224
|
+
OnPendingMessageConsumed() {
|
|
225
|
+
this.PendingMessage = null;
|
|
226
|
+
this.PendingAttachments = null;
|
|
227
|
+
this.cdr.markForCheck();
|
|
228
|
+
}
|
|
229
|
+
OnOpenEntityRecord(event) {
|
|
230
|
+
try {
|
|
231
|
+
this.navigationService.OpenEntityRecord(event.entityName, event.compositeKey);
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
LogError(`AIAssistantPanel.OnOpenEntityRecord: ${err instanceof Error ? err.message : String(err)}`);
|
|
257
235
|
}
|
|
258
|
-
return true;
|
|
259
236
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
// ============================================================
|
|
263
|
-
addMessage(role, content) {
|
|
264
|
-
this.Messages.push({
|
|
265
|
-
Role: role,
|
|
266
|
-
Content: content,
|
|
267
|
-
Timestamp: new Date()
|
|
268
|
-
});
|
|
269
|
-
this.cdr.detectChanges();
|
|
270
|
-
this.scrollToBottom();
|
|
237
|
+
OnNavigationRequest(event) {
|
|
238
|
+
void this.navigationService.OpenNavItemByName(event.navItemName, event.params, event.appId);
|
|
271
239
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}, 1000);
|
|
240
|
+
OnTaskClicked(task) {
|
|
241
|
+
try {
|
|
242
|
+
const key = CompositeKey.FromID(task.ID);
|
|
243
|
+
this.navigationService.OpenEntityRecord('MJ: Tasks', key);
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
LogError(`AIAssistantPanel.OnTaskClicked: ${err instanceof Error ? err.message : String(err)}`);
|
|
247
|
+
}
|
|
281
248
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
Promise.resolve().then(() => {
|
|
287
|
-
if (this.chatThreadEl) {
|
|
288
|
-
const el = this.chatThreadEl.nativeElement;
|
|
289
|
-
el.scrollTop = el.scrollHeight;
|
|
290
|
-
}
|
|
291
|
-
});
|
|
249
|
+
OnArtifactLinkClicked(event) {
|
|
250
|
+
const navItemName = event.type === 'conversation' ? 'Conversations' : 'Collections';
|
|
251
|
+
const paramKey = event.type === 'conversation' ? 'conversationId' : 'collectionId';
|
|
252
|
+
void this.navigationService.OpenNavItemByName(navItemName, { [paramKey]: event.id });
|
|
292
253
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
254
|
+
OnConversationRenamed(event) {
|
|
255
|
+
if (this.ChatConversation && UUIDsEqual(this.ChatConversation.ID, event.conversationId)) {
|
|
256
|
+
this.ChatConversation.Name = event.name;
|
|
257
|
+
if (event.description !== undefined) {
|
|
258
|
+
this.ChatConversation.Description = event.description;
|
|
297
259
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
autoGrowTextarea() {
|
|
301
|
-
if (!this.chatInputEl)
|
|
302
|
-
return;
|
|
303
|
-
const textarea = this.chatInputEl.nativeElement;
|
|
304
|
-
textarea.style.height = 'auto';
|
|
305
|
-
const lineHeight = 20;
|
|
306
|
-
const maxLines = 4;
|
|
307
|
-
const maxHeight = lineHeight * maxLines;
|
|
308
|
-
textarea.style.height = Math.min(textarea.scrollHeight, maxHeight) + 'px';
|
|
260
|
+
this.cdr.markForCheck();
|
|
261
|
+
}
|
|
309
262
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
this.chatInputEl.nativeElement.style.height = 'auto';
|
|
263
|
+
OnThreadOpened(threadId) {
|
|
264
|
+
this.ChatThreadId = threadId;
|
|
265
|
+
this.cdr.markForCheck();
|
|
314
266
|
}
|
|
315
|
-
|
|
316
|
-
|
|
267
|
+
OnThreadClosed() {
|
|
268
|
+
this.ChatThreadId = null;
|
|
269
|
+
this.cdr.markForCheck();
|
|
317
270
|
}
|
|
318
|
-
|
|
319
|
-
|
|
271
|
+
OnPendingArtifactConsumed() {
|
|
272
|
+
this.ChatPendingArtifactId = null;
|
|
273
|
+
this.ChatPendingArtifactVersionNumber = null;
|
|
274
|
+
this.cdr.markForCheck();
|
|
320
275
|
}
|
|
321
|
-
static ɵfac = function AIAssistantPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AIAssistantPanelComponent)(i0.ɵɵdirectiveInject(i1.ComponentStudioStateService)
|
|
322
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AIAssistantPanelComponent, selectors: [["mj-ai-assistant-panel"]],
|
|
323
|
-
i0.ɵɵ
|
|
324
|
-
|
|
325
|
-
let _t;
|
|
326
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.chatThreadEl = _t.first);
|
|
327
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.chatInputEl = _t.first);
|
|
328
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 38, vars: 8, consts: [["chatThread", ""], ["chatInput", ""], [1, "ai-assistant-panel"], [1, "panel-header"], [1, "header-title"], [1, "fa-solid", "fa-robot"], ["title", "Collapse panel", 1, "collapse-btn", 3, "click"], [1, "fa-solid", "fa-chevron-right"], [1, "model-selector"], [1, "model-label"], [1, "model-dropdown-wrapper"], [1, "model-loading"], [1, "model-dropdown", 3, "ngModel", "disabled"], [1, "quick-actions"], [1, "quick-action-btn", 3, "disabled", "title"], [1, "chat-thread"], [1, "empty-thread"], [1, "message-wrapper", 3, "user", "assistant", "system"], [1, "message-wrapper", "assistant"], [1, "chat-input-area"], [1, "input-wrapper"], ["placeholder", "Ask the AI assistant...", "rows", "1", 1, "chat-textarea", 3, "ngModelChange", "keydown", "input", "ngModel", "disabled"], ["title", "Send message", 1, "send-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-paper-plane"], [1, "input-hint"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "model-dropdown", 3, "ngModelChange", "ngModel", "disabled"], [3, "value"], ["disabled", "", 3, "value"], [1, "quick-action-btn", 3, "click", "disabled", "title"], [1, "fa-solid", "fa-comments"], [1, "message-wrapper"], [1, "message-avatar", "assistant-avatar"], [1, "message-bubble"], [1, "message-content"], [1, "message-timestamp"], [1, "message-avatar", "user-avatar"], [1, "fa-solid", "fa-user"], [1, "message-bubble", "assistant-bubble", "typing-bubble"], [1, "typing-indicator"], [1, "dot"]], template: function AIAssistantPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
329
|
-
const _r1 = i0.ɵɵgetCurrentView();
|
|
330
|
-
i0.ɵɵelementStart(0, "div", 2)(1, "div", 3)(2, "div", 4);
|
|
331
|
-
i0.ɵɵelement(3, "i", 5);
|
|
276
|
+
static ɵfac = function AIAssistantPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AIAssistantPanelComponent)(i0.ɵɵdirectiveInject(i1.ComponentStudioStateService)); };
|
|
277
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AIAssistantPanelComponent, selectors: [["mj-ai-assistant-panel"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 14, vars: 1, consts: [[1, "ai-assistant-panel"], [1, "panel-header"], [1, "header-title"], [1, "fa-solid", "fa-robot"], ["title", "Collapse panel", 1, "collapse-btn", 3, "click"], [1, "fa-solid", "fa-chevron-right"], [1, "quick-actions"], [1, "quick-action-btn", 3, "disabled", "title"], [1, "chat-host"], [3, "Provider", "environmentId", "currentUser", "conversationId", "conversation", "isNewConversation", "pendingMessage", "pendingAttachments", "threadId", "pendingArtifactId", "pendingArtifactVersionNumber", "overlayMode", "showExportButton", "showShareButton", "showArtifactIndicator", "appContext", "defaultAgentId", "applicationScope", "applicationId", "linkedEntityId", "linkedRecordId", "emptyStateGreeting"], [1, "chat-host__empty"], [1, "quick-action-btn", 3, "click", "disabled", "title"], [3, "conversationCreated", "pendingMessageConsumed", "openEntityRecord", "navigationRequest", "taskClicked", "artifactLinkClicked", "conversationRenamed", "threadOpened", "threadClosed", "pendingArtifactConsumed", "Provider", "environmentId", "currentUser", "conversationId", "conversation", "isNewConversation", "pendingMessage", "pendingAttachments", "threadId", "pendingArtifactId", "pendingArtifactVersionNumber", "overlayMode", "showExportButton", "showShareButton", "showArtifactIndicator", "appContext", "defaultAgentId", "applicationScope", "applicationId", "linkedEntityId", "linkedRecordId", "emptyStateGreeting"]], template: function AIAssistantPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
278
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
|
|
279
|
+
i0.ɵɵelement(3, "i", 3);
|
|
332
280
|
i0.ɵɵelementStart(4, "span");
|
|
333
281
|
i0.ɵɵtext(5, "AI Assistant");
|
|
334
282
|
i0.ɵɵelementEnd()();
|
|
335
|
-
i0.ɵɵelementStart(6, "button",
|
|
336
|
-
i0.ɵɵlistener("click", function AIAssistantPanelComponent_Template_button_click_6_listener() {
|
|
337
|
-
i0.ɵɵelement(7, "i",
|
|
338
|
-
i0.ɵɵelementEnd()();
|
|
339
|
-
i0.ɵɵelementStart(8, "div", 8)(9, "label", 9);
|
|
340
|
-
i0.ɵɵtext(10, "Model");
|
|
341
|
-
i0.ɵɵelementEnd();
|
|
342
|
-
i0.ɵɵelementStart(11, "div", 10);
|
|
343
|
-
i0.ɵɵconditionalCreate(12, AIAssistantPanelComponent_Conditional_12_Template, 4, 0, "div", 11)(13, AIAssistantPanelComponent_Conditional_13_Template, 4, 3, "select", 12);
|
|
283
|
+
i0.ɵɵelementStart(6, "button", 4);
|
|
284
|
+
i0.ɵɵlistener("click", function AIAssistantPanelComponent_Template_button_click_6_listener() { return ctx.OnCollapsePanel(); });
|
|
285
|
+
i0.ɵɵelement(7, "i", 5);
|
|
344
286
|
i0.ɵɵelementEnd()();
|
|
345
|
-
i0.ɵɵelementStart(
|
|
346
|
-
i0.ɵɵrepeaterCreate(
|
|
287
|
+
i0.ɵɵelementStart(8, "div", 6);
|
|
288
|
+
i0.ɵɵrepeaterCreate(9, AIAssistantPanelComponent_For_10_Template, 4, 8, "button", 7, _forTrack0);
|
|
347
289
|
i0.ɵɵelementEnd();
|
|
348
|
-
i0.ɵɵelementStart(
|
|
349
|
-
i0.ɵɵconditionalCreate(
|
|
350
|
-
i0.ɵɵrepeaterCreate(20, AIAssistantPanelComponent_For_21_Template, 8, 16, "div", 17, ctx.TrackByTimestamp, true);
|
|
351
|
-
i0.ɵɵconditionalCreate(22, AIAssistantPanelComponent_Conditional_22_Template, 8, 0, "div", 18);
|
|
352
|
-
i0.ɵɵelementEnd();
|
|
353
|
-
i0.ɵɵelementStart(23, "div", 19)(24, "div", 20)(25, "textarea", 21, 1);
|
|
354
|
-
i0.ɵɵtwoWayListener("ngModelChange", function AIAssistantPanelComponent_Template_textarea_ngModelChange_25_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.InputText, $event) || (ctx.InputText = $event); return i0.ɵɵresetView($event); });
|
|
355
|
-
i0.ɵɵlistener("keydown", function AIAssistantPanelComponent_Template_textarea_keydown_25_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnInputKeydown($event)); })("input", function AIAssistantPanelComponent_Template_textarea_input_25_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnInputChange()); });
|
|
356
|
-
i0.ɵɵelementEnd();
|
|
357
|
-
i0.ɵɵelementStart(27, "button", 22);
|
|
358
|
-
i0.ɵɵlistener("click", function AIAssistantPanelComponent_Template_button_click_27_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnSendMessage()); });
|
|
359
|
-
i0.ɵɵelement(28, "i", 23);
|
|
290
|
+
i0.ɵɵelementStart(11, "div", 8);
|
|
291
|
+
i0.ɵɵconditionalCreate(12, AIAssistantPanelComponent_Conditional_12_Template, 1, 22, "mj-conversation-chat-area", 9)(13, AIAssistantPanelComponent_Conditional_13_Template, 2, 0, "div", 10);
|
|
360
292
|
i0.ɵɵelementEnd()();
|
|
361
|
-
i0.ɵɵelementStart(29, "div", 24)(30, "span");
|
|
362
|
-
i0.ɵɵtext(31, "Press ");
|
|
363
|
-
i0.ɵɵelementStart(32, "kbd");
|
|
364
|
-
i0.ɵɵtext(33, "Enter");
|
|
365
|
-
i0.ɵɵelementEnd();
|
|
366
|
-
i0.ɵɵtext(34, " to send, ");
|
|
367
|
-
i0.ɵɵelementStart(35, "kbd");
|
|
368
|
-
i0.ɵɵtext(36, "Shift+Enter");
|
|
369
|
-
i0.ɵɵelementEnd();
|
|
370
|
-
i0.ɵɵtext(37, " for new line");
|
|
371
|
-
i0.ɵɵelementEnd()()()();
|
|
372
293
|
} if (rf & 2) {
|
|
373
|
-
i0.ɵɵadvance(
|
|
374
|
-
i0.ɵɵconditional(ctx.IsLoadingModels ? 12 : 13);
|
|
375
|
-
i0.ɵɵadvance(3);
|
|
294
|
+
i0.ɵɵadvance(9);
|
|
376
295
|
i0.ɵɵrepeater(ctx.QuickActions);
|
|
377
|
-
i0.ɵɵadvance(4);
|
|
378
|
-
i0.ɵɵconditional(ctx.Messages.length === 0 ? 19 : -1);
|
|
379
|
-
i0.ɵɵadvance();
|
|
380
|
-
i0.ɵɵrepeater(ctx.Messages);
|
|
381
|
-
i0.ɵɵadvance(2);
|
|
382
|
-
i0.ɵɵconditional(ctx.IsWaitingForResponse ? 22 : -1);
|
|
383
296
|
i0.ɵɵadvance(3);
|
|
384
|
-
i0.ɵɵ
|
|
385
|
-
|
|
386
|
-
i0.ɵɵadvance(2);
|
|
387
|
-
i0.ɵɵclassProp("active", ctx.InputText.trim().length > 0 && !ctx.IsWaitingForResponse);
|
|
388
|
-
i0.ɵɵproperty("disabled", ctx.InputText.trim().length === 0 || ctx.IsWaitingForResponse);
|
|
389
|
-
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.ai-assistant-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n\n\n\n\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n}\n\n.panel-header[_ngcontent-%COMP%] .header-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-header[_ngcontent-%COMP%] .header-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.panel-header[_ngcontent-%COMP%] .collapse-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.panel-header[_ngcontent-%COMP%] .collapse-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n\n\n\n\n\n\n\n.model-selector[_ngcontent-%COMP%] {\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.model-selector[_ngcontent-%COMP%] .model-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n}\n\n.model-selector[_ngcontent-%COMP%] .model-dropdown-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.model-selector[_ngcontent-%COMP%] .model-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n padding: 7px 10px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 12px;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s ease;\n appearance: none;\n -webkit-appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 8px center;\n padding-right: 28px;\n}\n\n.model-selector[_ngcontent-%COMP%] .model-dropdown[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.model-selector[_ngcontent-%COMP%] .model-dropdown[_ngcontent-%COMP%]:disabled {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n}\n\n.model-selector[_ngcontent-%COMP%] .model-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n padding: 7px 0;\n}\n\n.model-selector[_ngcontent-%COMP%] .model-loading[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n\n\n\n\n\n.quick-actions[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.quick-actions[_ngcontent-%COMP%] .quick-action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 5px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 11px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.quick-actions[_ngcontent-%COMP%] .quick-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.quick-actions[_ngcontent-%COMP%] .quick-action-btn[_ngcontent-%COMP%]:hover:not(.disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.quick-actions[_ngcontent-%COMP%] .quick-action-btn.disabled[_ngcontent-%COMP%] {\n opacity: 0.4;\n cursor: not-allowed;\n background: var(--mj-bg-surface-sunken);\n}\n\n\n\n\n\n\n\n\n.chat-thread[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n scroll-behavior: smooth;\n}\n\n\n\n.chat-thread[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n\n.chat-thread[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.chat-thread[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: 3px;\n}\n\n.chat-thread[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-secondary);\n}\n\n.empty-thread[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n text-align: center;\n color: var(--mj-text-secondary);\n padding: 32px 16px;\n}\n\n.empty-thread[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 36px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n.empty-thread[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 13px;\n line-height: 1.5;\n margin: 0;\n max-width: 220px;\n}\n\n\n\n\n\n\n\n\n.message-wrapper[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n}\n\n.message-wrapper.user[_ngcontent-%COMP%] {\n justify-content: flex-end;\n}\n\n.message-wrapper.assistant[_ngcontent-%COMP%] {\n justify-content: flex-start;\n}\n\n.message-wrapper.system[_ngcontent-%COMP%] {\n justify-content: center;\n}\n\n.message-avatar[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 12px;\n}\n\n.message-avatar.assistant-avatar[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.message-avatar.user-avatar[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 20%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.message-bubble[_ngcontent-%COMP%] {\n max-width: 80%;\n padding: 10px 14px;\n border-radius: 16px;\n position: relative;\n}\n\n.message-bubble.user-bubble[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-bottom-right-radius: 4px;\n}\n\n.message-bubble.user-bubble[_ngcontent-%COMP%] .message-timestamp[_ngcontent-%COMP%] {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.message-bubble.assistant-bubble[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n border-bottom-left-radius: 4px;\n}\n\n.message-bubble.assistant-bubble[_ngcontent-%COMP%] .message-timestamp[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n.message-bubble.system-bubble[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n font-style: italic;\n border-radius: 8px;\n max-width: 90%;\n}\n\n.message-bubble.system-bubble[_ngcontent-%COMP%] .message-timestamp[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n.message-bubble.typing-bubble[_ngcontent-%COMP%] {\n padding: 14px 18px;\n}\n\n.message-content[_ngcontent-%COMP%] {\n font-size: 13px;\n line-height: 1.5;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n.message-timestamp[_ngcontent-%COMP%] {\n font-size: 10px;\n margin-top: 4px;\n text-align: right;\n}\n\n\n\n\n\n\n\n\n.typing-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.typing-indicator[_ngcontent-%COMP%] .dot[_ngcontent-%COMP%] {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--mj-text-secondary);\n animation: _ngcontent-%COMP%_typingBounce 1.4s infinite ease-in-out both;\n}\n\n.typing-indicator[_ngcontent-%COMP%] .dot[_ngcontent-%COMP%]:nth-child(1) {\n animation-delay: 0s;\n}\n\n.typing-indicator[_ngcontent-%COMP%] .dot[_ngcontent-%COMP%]:nth-child(2) {\n animation-delay: 0.2s;\n}\n\n.typing-indicator[_ngcontent-%COMP%] .dot[_ngcontent-%COMP%]:nth-child(3) {\n animation-delay: 0.4s;\n}\n\n@keyframes _ngcontent-%COMP%_typingBounce {\n 0%, 60%, 100% {\n transform: translateY(0);\n opacity: 0.4;\n }\n 30% {\n transform: translateY(-6px);\n opacity: 1;\n }\n}\n\n\n\n\n\n\n\n\n.chat-input-area[_ngcontent-%COMP%] {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .input-wrapper[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 12px;\n padding: 4px 4px 4px 12px;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .input-wrapper[_ngcontent-%COMP%]:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.chat-input-area[_ngcontent-%COMP%] .chat-textarea[_ngcontent-%COMP%] {\n flex: 1;\n border: none;\n outline: none;\n resize: none;\n font-size: 13px;\n line-height: 20px;\n color: var(--mj-text-primary);\n background: transparent;\n padding: 6px 0;\n max-height: 80px;\n font-family: inherit;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .chat-textarea[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.chat-input-area[_ngcontent-%COMP%] .chat-textarea[_ngcontent-%COMP%]:disabled {\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .send-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n border-radius: 8px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .send-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .send-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .send-btn.active[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n}\n\n.chat-input-area[_ngcontent-%COMP%] .send-btn[_ngcontent-%COMP%]:disabled {\n cursor: not-allowed;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .input-hint[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n margin-top: 6px;\n}\n\n.chat-input-area[_ngcontent-%COMP%] .input-hint[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-secondary);\n}\n\n.chat-input-area[_ngcontent-%COMP%] .input-hint[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 1px 4px;\n font-size: 9px;\n font-family: inherit;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 3px;\n margin: 0 2px;\n}"] });
|
|
297
|
+
i0.ɵɵconditional(ctx.CurrentUser ? 12 : 13);
|
|
298
|
+
} }, dependencies: [i2.ConversationChatAreaComponent], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.ai-assistant-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n\n\n\n\n\n\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n}\n\n.panel-header[_ngcontent-%COMP%] .header-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-header[_ngcontent-%COMP%] .header-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.panel-header[_ngcontent-%COMP%] .collapse-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n border-radius: 4px;\n cursor: pointer;\n transition: background 0.15s, color 0.15s;\n}\n\n.panel-header[_ngcontent-%COMP%] .collapse-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n\n\n\n\n\n\n\n.quick-actions[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.quick-action-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.quick-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 11px;\n}\n\n.quick-action-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.quick-action-btn[_ngcontent-%COMP%]:disabled, \n.quick-action-btn.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n\n\n\n\n\n\n\n.chat-host[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.chat-host[_ngcontent-%COMP%] mj-conversation-chat-area[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.chat-host__empty[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n font-size: 13px;\n color: var(--mj-text-muted);\n}"], changeDetection: 0 });
|
|
390
299
|
}
|
|
391
300
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AIAssistantPanelComponent, [{
|
|
392
301
|
type: Component,
|
|
393
|
-
args: [{ standalone: false, selector: 'mj-ai-assistant-panel', template: "<div class=\"ai-assistant-panel\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-robot\"></i>\n <span>AI Assistant</span>\n </div>\n <button class=\"collapse-btn\" (click)=\"OnCollapsePanel()\" title=\"Collapse panel\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n </div>\n\n <!-- Model Selector -->\n <div class=\"model-selector\">\n <label class=\"model-label\">Model</label>\n <div class=\"model-dropdown-wrapper\">\n @if (IsLoadingModels) {\n <div class=\"model-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading models...</span>\n </div>\n } @else {\n <select\n class=\"model-dropdown\"\n [(ngModel)]=\"SelectedModelID\"\n [disabled]=\"AvailableModels.length === 0\">\n @for (model of AvailableModels; track model.ID) {\n <option [value]=\"model.ID\">{{ model.DisplayLabel }}</option>\n }\n @if (AvailableModels.length === 0) {\n <option [value]=\"null\" disabled>No models available</option>\n }\n </select>\n }\n </div>\n </div>\n\n <!-- Quick Actions Bar -->\n <div class=\"quick-actions\">\n @for (action of QuickActions; track action.Label) {\n <button\n class=\"quick-action-btn\"\n [class.disabled]=\"!IsQuickActionEnabled(action)\"\n [disabled]=\"!IsQuickActionEnabled(action) || IsWaitingForResponse\"\n (click)=\"OnQuickAction(action)\"\n [title]=\"action.Label\">\n <i class=\"fa-solid {{ action.Icon }}\"></i>\n <span>{{ action.Label }}</span>\n </button>\n }\n </div>\n\n <!-- Chat Thread -->\n <div class=\"chat-thread\" #chatThread>\n @if (Messages.length === 0) {\n <div class=\"empty-thread\">\n <i class=\"fa-solid fa-comments\"></i>\n <p>No messages yet. Start a conversation or use a quick action above.</p>\n </div>\n }\n\n @for (message of Messages; track TrackByTimestamp($index, message)) {\n <div class=\"message-wrapper\" [class.user]=\"message.Role === 'user'\" [class.assistant]=\"message.Role === 'assistant'\" [class.system]=\"message.Role === 'system'\">\n @if (message.Role === 'assistant') {\n <div class=\"message-avatar assistant-avatar\">\n <i class=\"fa-solid fa-robot\"></i>\n </div>\n }\n\n <div class=\"message-bubble\" [class.user-bubble]=\"message.Role === 'user'\" [class.assistant-bubble]=\"message.Role === 'assistant'\" [class.system-bubble]=\"message.Role === 'system'\">\n <div class=\"message-content\">{{ message.Content }}</div>\n <div class=\"message-timestamp\">{{ FormatTimestamp(message.Timestamp) }}</div>\n </div>\n\n @if (message.Role === 'user') {\n <div class=\"message-avatar user-avatar\">\n <i class=\"fa-solid fa-user\"></i>\n </div>\n }\n </div>\n }\n\n <!-- Typing Indicator -->\n @if (IsWaitingForResponse) {\n <div class=\"message-wrapper assistant\">\n <div class=\"message-avatar assistant-avatar\">\n <i class=\"fa-solid fa-robot\"></i>\n </div>\n <div class=\"message-bubble assistant-bubble typing-bubble\">\n <div class=\"typing-indicator\">\n <span class=\"dot\"></span>\n <span class=\"dot\"></span>\n <span class=\"dot\"></span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Chat Input Area -->\n <div class=\"chat-input-area\">\n <div class=\"input-wrapper\">\n <textarea\n #chatInput\n class=\"chat-textarea\"\n [(ngModel)]=\"InputText\"\n (keydown)=\"OnInputKeydown($event)\"\n (input)=\"OnInputChange()\"\n [disabled]=\"IsWaitingForResponse\"\n placeholder=\"Ask the AI assistant...\"\n rows=\"1\"></textarea>\n <button\n class=\"send-btn\"\n [class.active]=\"InputText.trim().length > 0 && !IsWaitingForResponse\"\n [disabled]=\"InputText.trim().length === 0 || IsWaitingForResponse\"\n (click)=\"OnSendMessage()\"\n title=\"Send message\">\n <i class=\"fa-solid fa-paper-plane\"></i>\n </button>\n </div>\n <div class=\"input-hint\">\n <span>Press <kbd>Enter</kbd> to send, <kbd>Shift+Enter</kbd> for new line</span>\n </div>\n </div>\n</div>\n", styles: [":host {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.ai-assistant-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n/* ============================================================ */\n/* HEADER */\n/* ============================================================ */\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n}\n\n.panel-header .header-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-header .header-title i {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.panel-header .collapse-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.panel-header .collapse-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n/* ============================================================ */\n/* MODEL SELECTOR */\n/* ============================================================ */\n\n.model-selector {\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.model-selector .model-label {\n display: block;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n}\n\n.model-selector .model-dropdown-wrapper {\n position: relative;\n}\n\n.model-selector .model-dropdown {\n width: 100%;\n padding: 7px 10px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 12px;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s ease;\n appearance: none;\n -webkit-appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 8px center;\n padding-right: 28px;\n}\n\n.model-selector .model-dropdown:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.model-selector .model-dropdown:disabled {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n}\n\n.model-selector .model-loading {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n padding: 7px 0;\n}\n\n.model-selector .model-loading i {\n font-size: 12px;\n}\n\n/* ============================================================ */\n/* QUICK ACTIONS */\n/* ============================================================ */\n\n.quick-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.quick-actions .quick-action-btn {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 5px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 11px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.quick-actions .quick-action-btn i {\n font-size: 11px;\n}\n\n.quick-actions .quick-action-btn:hover:not(.disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.quick-actions .quick-action-btn.disabled {\n opacity: 0.4;\n cursor: not-allowed;\n background: var(--mj-bg-surface-sunken);\n}\n\n/* ============================================================ */\n/* CHAT THREAD */\n/* ============================================================ */\n\n.chat-thread {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n scroll-behavior: smooth;\n}\n\n/* Custom scrollbar */\n.chat-thread::-webkit-scrollbar {\n width: 6px;\n}\n\n.chat-thread::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.chat-thread::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: 3px;\n}\n\n.chat-thread::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-secondary);\n}\n\n.empty-thread {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n text-align: center;\n color: var(--mj-text-secondary);\n padding: 32px 16px;\n}\n\n.empty-thread i {\n font-size: 36px;\n margin-bottom: 12px;\n opacity: 0.5;\n}\n\n.empty-thread p {\n font-size: 13px;\n line-height: 1.5;\n margin: 0;\n max-width: 220px;\n}\n\n/* ============================================================ */\n/* MESSAGE BUBBLES */\n/* ============================================================ */\n\n.message-wrapper {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n}\n\n.message-wrapper.user {\n justify-content: flex-end;\n}\n\n.message-wrapper.assistant {\n justify-content: flex-start;\n}\n\n.message-wrapper.system {\n justify-content: center;\n}\n\n.message-avatar {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 12px;\n}\n\n.message-avatar.assistant-avatar {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.message-avatar.user-avatar {\n background: color-mix(in srgb, var(--mj-brand-primary) 20%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.message-bubble {\n max-width: 80%;\n padding: 10px 14px;\n border-radius: 16px;\n position: relative;\n}\n\n.message-bubble.user-bubble {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-bottom-right-radius: 4px;\n}\n\n.message-bubble.user-bubble .message-timestamp {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.message-bubble.assistant-bubble {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n border-bottom-left-radius: 4px;\n}\n\n.message-bubble.assistant-bubble .message-timestamp {\n color: var(--mj-text-secondary);\n}\n\n.message-bubble.system-bubble {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n font-style: italic;\n border-radius: 8px;\n max-width: 90%;\n}\n\n.message-bubble.system-bubble .message-timestamp {\n color: var(--mj-status-warning);\n}\n\n.message-bubble.typing-bubble {\n padding: 14px 18px;\n}\n\n.message-content {\n font-size: 13px;\n line-height: 1.5;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n.message-timestamp {\n font-size: 10px;\n margin-top: 4px;\n text-align: right;\n}\n\n/* ============================================================ */\n/* TYPING INDICATOR */\n/* ============================================================ */\n\n.typing-indicator {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.typing-indicator .dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--mj-text-secondary);\n animation: typingBounce 1.4s infinite ease-in-out both;\n}\n\n.typing-indicator .dot:nth-child(1) {\n animation-delay: 0s;\n}\n\n.typing-indicator .dot:nth-child(2) {\n animation-delay: 0.2s;\n}\n\n.typing-indicator .dot:nth-child(3) {\n animation-delay: 0.4s;\n}\n\n@keyframes typingBounce {\n 0%, 60%, 100% {\n transform: translateY(0);\n opacity: 0.4;\n }\n 30% {\n transform: translateY(-6px);\n opacity: 1;\n }\n}\n\n/* ============================================================ */\n/* CHAT INPUT AREA */\n/* ============================================================ */\n\n.chat-input-area {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n}\n\n.chat-input-area .input-wrapper {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 12px;\n padding: 4px 4px 4px 12px;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n\n.chat-input-area .input-wrapper:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.chat-input-area .chat-textarea {\n flex: 1;\n border: none;\n outline: none;\n resize: none;\n font-size: 13px;\n line-height: 20px;\n color: var(--mj-text-primary);\n background: transparent;\n padding: 6px 0;\n max-height: 80px;\n font-family: inherit;\n}\n\n.chat-input-area .chat-textarea::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.chat-input-area .chat-textarea:disabled {\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n}\n\n.chat-input-area .send-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n border-radius: 8px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.chat-input-area .send-btn i {\n font-size: 13px;\n}\n\n.chat-input-area .send-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n}\n\n.chat-input-area .send-btn.active:hover {\n background: var(--mj-brand-primary);\n}\n\n.chat-input-area .send-btn:disabled {\n cursor: not-allowed;\n}\n\n.chat-input-area .input-hint {\n display: flex;\n justify-content: center;\n margin-top: 6px;\n}\n\n.chat-input-area .input-hint span {\n font-size: 10px;\n color: var(--mj-text-secondary);\n}\n\n.chat-input-area .input-hint kbd {\n display: inline-block;\n padding: 1px 4px;\n font-size: 9px;\n font-family: inherit;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 3px;\n margin: 0 2px;\n}\n"] }]
|
|
394
|
-
}], () => [{ type: i1.ComponentStudioStateService },
|
|
395
|
-
|
|
396
|
-
args: ['chatThread']
|
|
397
|
-
}], chatInputEl: [{
|
|
398
|
-
type: ViewChild,
|
|
399
|
-
args: ['chatInput']
|
|
400
|
-
}] }); })();
|
|
401
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AIAssistantPanelComponent, { className: "AIAssistantPanelComponent", filePath: "src/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.ts", lineNumber: 44 }); })();
|
|
302
|
+
args: [{ standalone: false, selector: 'mj-ai-assistant-panel', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ai-assistant-panel\">\n <!-- Header: title + collapse. Style + classes match the prior bespoke\n chat so the panel chrome lines up with the rest of the cockpit. -->\n <div class=\"panel-header\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-robot\"></i>\n <span>AI Assistant</span>\n </div>\n <button class=\"collapse-btn\" (click)=\"OnCollapsePanel()\" title=\"Collapse panel\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n </div>\n\n <!-- Quick Actions: clicking a button stuffs the canned prompt into\n `PendingMessage`, which the chat-area below picks up on its next\n render cycle and sends as if the user typed it. Same mechanism the\n SendErrorToAI handler uses. \"Fix Errors\" disables until an error\n has actually been observed in the runtime preview. -->\n <div class=\"quick-actions\">\n @for (action of QuickActions; track action.Label) {\n <button\n class=\"quick-action-btn\"\n [class.disabled]=\"!IsQuickActionEnabled(action)\"\n [disabled]=\"!IsQuickActionEnabled(action)\"\n (click)=\"OnQuickAction(action)\"\n [title]=\"action.Label\">\n <i class=\"fa-solid {{ action.Icon }}\"></i>\n <span>{{ action.Label }}</span>\n </button>\n }\n </div>\n\n <!-- Embedded chat-area \u2014 same primitive the main Chat app and the Form\n Builder cockpit use. Conversations here are scoped to the\n Component Studio app so they don't pollute main chat; the default\n agent is Codesmith (resolved at init from the AIEngineBase cache);\n and the conversation-header agent picker stays enabled so the user\n can switch on the fly. -->\n <div class=\"chat-host\">\n @if (CurrentUser) {\n <mj-conversation-chat-area\n [Provider]=\"Provider\"\n [environmentId]=\"EnvironmentId\"\n [currentUser]=\"CurrentUser\"\n [conversationId]=\"ChatConversationId\"\n [conversation]=\"ChatConversation\"\n [isNewConversation]=\"ChatIsNewConversation\"\n [pendingMessage]=\"PendingMessage\"\n [pendingAttachments]=\"PendingAttachments\"\n [threadId]=\"ChatThreadId\"\n [pendingArtifactId]=\"ChatPendingArtifactId\"\n [pendingArtifactVersionNumber]=\"ChatPendingArtifactVersionNumber\"\n [overlayMode]=\"true\"\n [showExportButton]=\"false\"\n [showShareButton]=\"false\"\n [showArtifactIndicator]=\"false\"\n [appContext]=\"$any(ChatAppContext)\"\n [defaultAgentId]=\"CodesmithAgentId\"\n [applicationScope]=\"'Application'\"\n [applicationId]=\"CockpitApplicationId\"\n [linkedEntityId]=\"ComponentsEntityID\"\n [linkedRecordId]=\"LinkedComponentID\"\n [emptyStateGreeting]=\"'How can I help with this component?'\"\n (conversationCreated)=\"OnConversationCreated($event)\"\n (pendingMessageConsumed)=\"OnPendingMessageConsumed()\"\n (openEntityRecord)=\"OnOpenEntityRecord($event)\"\n (navigationRequest)=\"OnNavigationRequest($event)\"\n (taskClicked)=\"OnTaskClicked($event)\"\n (artifactLinkClicked)=\"OnArtifactLinkClicked($event)\"\n (conversationRenamed)=\"OnConversationRenamed($event)\"\n (threadOpened)=\"OnThreadOpened($event)\"\n (threadClosed)=\"OnThreadClosed()\"\n (pendingArtifactConsumed)=\"OnPendingArtifactConsumed()\">\n </mj-conversation-chat-area>\n } @else {\n <div class=\"chat-host__empty\">Loading\u2026</div>\n }\n </div>\n</div>\n", styles: [":host {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.ai-assistant-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n/* ============================================================ */\n/* HEADER */\n/* ============================================================ */\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n}\n\n.panel-header .header-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.panel-header .header-title i {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n.panel-header .collapse-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n border-radius: 4px;\n cursor: pointer;\n transition: background 0.15s, color 0.15s;\n}\n\n.panel-header .collapse-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n/* ============================================================ */\n/* QUICK ACTIONS */\n/* ============================================================ */\n\n.quick-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 10px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.quick-action-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.quick-action-btn i {\n color: var(--mj-brand-primary);\n font-size: 11px;\n}\n\n.quick-action-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.quick-action-btn:disabled,\n.quick-action-btn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* ============================================================ */\n/* CHAT HOST */\n/* ============================================================ */\n\n.chat-host {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.chat-host mj-conversation-chat-area {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.chat-host__empty {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n"] }]
|
|
303
|
+
}], () => [{ type: i1.ComponentStudioStateService }], null); })();
|
|
304
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AIAssistantPanelComponent, { className: "AIAssistantPanelComponent", filePath: "src/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.ts", lineNumber: 71 }); })();
|
|
402
305
|
//# sourceMappingURL=ai-assistant-panel.component.js.map
|