@memberjunction/ng-conversations 2.111.1 → 2.113.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/components/collection/artifact-create-modal.component.js +1 -1
- package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
- package/dist/lib/components/collection/collection-artifact-card.component.d.ts +8 -7
- package/dist/lib/components/collection/collection-artifact-card.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-artifact-card.component.js +52 -36
- package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -1
- package/dist/lib/components/collection/collection-view.component.d.ts +28 -9
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +124 -58
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.d.ts +18 -6
- package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collections-full-view.component.js +82 -58
- package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +37 -0
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +278 -162
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.d.ts +10 -3
- package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-list.component.js +118 -77
- package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
- package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts +25 -0
- package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts.map +1 -0
- package/dist/lib/components/global-tasks/global-tasks-panel.component.js +206 -0
- package/dist/lib/components/global-tasks/global-tasks-panel.component.js.map +1 -0
- package/dist/lib/components/message/conversation-message-rating.component.d.ts +47 -0
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -0
- package/dist/lib/components/message/conversation-message-rating.component.js +224 -0
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -0
- package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input-box.component.js +2 -12
- package/dist/lib/components/message/message-input-box.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +17 -2
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +258 -275
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +31 -1
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +232 -116
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +3 -1
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +11 -2
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/navigation/conversation-navigation.component.d.ts +7 -1
- package/dist/lib/components/navigation/conversation-navigation.component.d.ts.map +1 -1
- package/dist/lib/components/navigation/conversation-navigation.component.js +24 -14
- package/dist/lib/components/navigation/conversation-navigation.component.js.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +17 -28
- package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +175 -217
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +14 -8
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +103 -64
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +54 -52
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +11 -3
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/models/conversation-complete-query.model.d.ts +31 -22
- package/dist/lib/models/conversation-complete-query.model.d.ts.map +1 -1
- package/dist/lib/models/conversation-complete-query.model.js +5 -2
- package/dist/lib/models/conversation-complete-query.model.js.map +1 -1
- package/dist/lib/models/lazy-artifact-info.d.ts +3 -0
- package/dist/lib/models/lazy-artifact-info.d.ts.map +1 -1
- package/dist/lib/models/lazy-artifact-info.js +7 -2
- package/dist/lib/models/lazy-artifact-info.js.map +1 -1
- package/dist/lib/services/active-tasks.service.d.ts +18 -0
- package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
- package/dist/lib/services/active-tasks.service.js +53 -3
- package/dist/lib/services/active-tasks.service.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +5 -5
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-permission.service.js +3 -1
- package/dist/lib/services/artifact-permission.service.js.map +1 -1
- package/dist/lib/services/artifact-state.service.d.ts +22 -5
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +118 -30
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/artifact-use-tracking.service.d.ts +35 -0
- package/dist/lib/services/artifact-use-tracking.service.d.ts.map +1 -0
- package/dist/lib/services/artifact-use-tracking.service.js +76 -0
- package/dist/lib/services/artifact-use-tracking.service.js.map +1 -0
- package/dist/lib/services/conversation-agent.service.d.ts +30 -3
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +101 -12
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-state.service.d.ts +13 -0
- package/dist/lib/services/conversation-state.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-state.service.js +26 -0
- package/dist/lib/services/conversation-state.service.js.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
- package/dist/lib/services/mention-autocomplete.service.js +1 -1
- package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +3 -1
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +14 -14
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Component, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { Subject } from 'rxjs';
|
|
3
|
+
import { takeUntil } from 'rxjs/operators';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "../../services/active-tasks.service";
|
|
6
|
+
import * as i2 from "@angular/common";
|
|
7
|
+
function GlobalTasksPanelComponent_div_0_button_1_Template(rf, ctx) { if (rf & 1) {
|
|
8
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
9
|
+
i0.ɵɵelementStart(0, "button", 4);
|
|
10
|
+
i0.ɵɵlistener("click", function GlobalTasksPanelComponent_div_0_button_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.expand()); });
|
|
11
|
+
i0.ɵɵelement(1, "i", 5);
|
|
12
|
+
i0.ɵɵelementStart(2, "span", 6);
|
|
13
|
+
i0.ɵɵtext(3);
|
|
14
|
+
i0.ɵɵelementEnd()();
|
|
15
|
+
} if (rf & 2) {
|
|
16
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
17
|
+
i0.ɵɵadvance(3);
|
|
18
|
+
i0.ɵɵtextInterpolate(ctx_r1.tasks.length);
|
|
19
|
+
} }
|
|
20
|
+
function GlobalTasksPanelComponent_div_0_div_2_div_9_div_5_Template(rf, ctx) { if (rf & 1) {
|
|
21
|
+
i0.ɵɵelementStart(0, "div", 24);
|
|
22
|
+
i0.ɵɵelement(1, "i", 25);
|
|
23
|
+
i0.ɵɵelementStart(2, "span");
|
|
24
|
+
i0.ɵɵtext(3);
|
|
25
|
+
i0.ɵɵelementEnd()();
|
|
26
|
+
} if (rf & 2) {
|
|
27
|
+
const task_r5 = i0.ɵɵnextContext().$implicit;
|
|
28
|
+
i0.ɵɵadvance(3);
|
|
29
|
+
i0.ɵɵtextInterpolate(task_r5.conversationName);
|
|
30
|
+
} }
|
|
31
|
+
function GlobalTasksPanelComponent_div_0_div_2_div_9_Template(rf, ctx) { if (rf & 1) {
|
|
32
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
33
|
+
i0.ɵɵelementStart(0, "div", 15);
|
|
34
|
+
i0.ɵɵlistener("click", function GlobalTasksPanelComponent_div_0_div_2_div_9_Template_div_click_0_listener() { const task_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onTaskClick(task_r5)); });
|
|
35
|
+
i0.ɵɵelementStart(1, "div", 16);
|
|
36
|
+
i0.ɵɵelement(2, "i", 17);
|
|
37
|
+
i0.ɵɵelementStart(3, "span", 18);
|
|
38
|
+
i0.ɵɵtext(4);
|
|
39
|
+
i0.ɵɵelementEnd()();
|
|
40
|
+
i0.ɵɵtemplate(5, GlobalTasksPanelComponent_div_0_div_2_div_9_div_5_Template, 4, 1, "div", 19);
|
|
41
|
+
i0.ɵɵelementStart(6, "div", 20);
|
|
42
|
+
i0.ɵɵelement(7, "span", 21);
|
|
43
|
+
i0.ɵɵelementStart(8, "span", 22);
|
|
44
|
+
i0.ɵɵtext(9);
|
|
45
|
+
i0.ɵɵelementEnd()();
|
|
46
|
+
i0.ɵɵelementStart(10, "div", 23);
|
|
47
|
+
i0.ɵɵtext(11);
|
|
48
|
+
i0.ɵɵelementEnd()();
|
|
49
|
+
} if (rf & 2) {
|
|
50
|
+
const task_r5 = ctx.$implicit;
|
|
51
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
52
|
+
i0.ɵɵadvance(4);
|
|
53
|
+
i0.ɵɵtextInterpolate(task_r5.agentName);
|
|
54
|
+
i0.ɵɵadvance();
|
|
55
|
+
i0.ɵɵproperty("ngIf", task_r5.conversationName);
|
|
56
|
+
i0.ɵɵadvance(4);
|
|
57
|
+
i0.ɵɵtextInterpolate(ctx_r1.getTrimmedStatus(task_r5.status));
|
|
58
|
+
i0.ɵɵadvance(2);
|
|
59
|
+
i0.ɵɵtextInterpolate(ctx_r1.getElapsedTime(task_r5));
|
|
60
|
+
} }
|
|
61
|
+
function GlobalTasksPanelComponent_div_0_div_2_Template(rf, ctx) { if (rf & 1) {
|
|
62
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
63
|
+
i0.ɵɵelementStart(0, "div", 7)(1, "div", 8)(2, "div", 9);
|
|
64
|
+
i0.ɵɵelement(3, "i", 10);
|
|
65
|
+
i0.ɵɵelementStart(4, "span");
|
|
66
|
+
i0.ɵɵtext(5);
|
|
67
|
+
i0.ɵɵelementEnd()();
|
|
68
|
+
i0.ɵɵelementStart(6, "button", 11);
|
|
69
|
+
i0.ɵɵlistener("click", function GlobalTasksPanelComponent_div_0_div_2_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.minimize()); });
|
|
70
|
+
i0.ɵɵelement(7, "i", 12);
|
|
71
|
+
i0.ɵɵelementEnd()();
|
|
72
|
+
i0.ɵɵelementStart(8, "div", 13);
|
|
73
|
+
i0.ɵɵtemplate(9, GlobalTasksPanelComponent_div_0_div_2_div_9_Template, 12, 4, "div", 14);
|
|
74
|
+
i0.ɵɵelementEnd()();
|
|
75
|
+
} if (rf & 2) {
|
|
76
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
77
|
+
i0.ɵɵadvance(5);
|
|
78
|
+
i0.ɵɵtextInterpolate1("Active Tasks (", ctx_r1.tasks.length, ")");
|
|
79
|
+
i0.ɵɵadvance(4);
|
|
80
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.tasks);
|
|
81
|
+
} }
|
|
82
|
+
function GlobalTasksPanelComponent_div_0_Template(rf, ctx) { if (rf & 1) {
|
|
83
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
84
|
+
i0.ɵɵtemplate(1, GlobalTasksPanelComponent_div_0_button_1_Template, 4, 1, "button", 2)(2, GlobalTasksPanelComponent_div_0_div_2_Template, 10, 2, "div", 3);
|
|
85
|
+
i0.ɵɵelementEnd();
|
|
86
|
+
} if (rf & 2) {
|
|
87
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
88
|
+
i0.ɵɵadvance();
|
|
89
|
+
i0.ɵɵproperty("ngIf", ctx_r1.isMinimized);
|
|
90
|
+
i0.ɵɵadvance();
|
|
91
|
+
i0.ɵɵproperty("ngIf", !ctx_r1.isMinimized);
|
|
92
|
+
} }
|
|
93
|
+
/**
|
|
94
|
+
* Global floating tasks panel that shows all active tasks across all conversations
|
|
95
|
+
* Appears in bottom-right corner, minimizable, shows only when tasks > 0
|
|
96
|
+
*/
|
|
97
|
+
export class GlobalTasksPanelComponent {
|
|
98
|
+
activeTasksService;
|
|
99
|
+
tasks = [];
|
|
100
|
+
isMinimized = false;
|
|
101
|
+
destroy$ = new Subject();
|
|
102
|
+
taskClicked = new EventEmitter();
|
|
103
|
+
constructor(activeTasksService) {
|
|
104
|
+
this.activeTasksService = activeTasksService;
|
|
105
|
+
}
|
|
106
|
+
ngOnInit() {
|
|
107
|
+
// Subscribe to active tasks
|
|
108
|
+
this.activeTasksService.tasks$.pipe(takeUntil(this.destroy$)).subscribe(tasks => {
|
|
109
|
+
this.tasks = tasks;
|
|
110
|
+
// Auto-expand if tasks appear and panel was minimized
|
|
111
|
+
if (this.tasks.length > 0 && this.isMinimized) {
|
|
112
|
+
// Keep minimized, let user expand manually
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
ngOnDestroy() {
|
|
117
|
+
this.destroy$.next();
|
|
118
|
+
this.destroy$.complete();
|
|
119
|
+
}
|
|
120
|
+
expand() {
|
|
121
|
+
this.isMinimized = false;
|
|
122
|
+
}
|
|
123
|
+
minimize() {
|
|
124
|
+
this.isMinimized = true;
|
|
125
|
+
}
|
|
126
|
+
onTaskClick(task) {
|
|
127
|
+
this.taskClicked.emit(task);
|
|
128
|
+
}
|
|
129
|
+
getTrimmedStatus(status) {
|
|
130
|
+
// Remove emojis and trim to 50 chars
|
|
131
|
+
const cleaned = status.replace(/[\u{1F600}-\u{1F64F}]/gu, '').trim();
|
|
132
|
+
return cleaned.length > 50 ? cleaned.substring(0, 47) + '...' : cleaned;
|
|
133
|
+
}
|
|
134
|
+
getElapsedTime(task) {
|
|
135
|
+
const elapsed = Date.now() - task.startTime;
|
|
136
|
+
const seconds = Math.floor(elapsed / 1000);
|
|
137
|
+
const minutes = Math.floor(seconds / 60);
|
|
138
|
+
const hours = Math.floor(minutes / 60);
|
|
139
|
+
if (hours > 0) {
|
|
140
|
+
return `${hours}h ${minutes % 60}m`;
|
|
141
|
+
}
|
|
142
|
+
else if (minutes > 0) {
|
|
143
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
return `${seconds}s`;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
static ɵfac = function GlobalTasksPanelComponent_Factory(t) { return new (t || GlobalTasksPanelComponent)(i0.ɵɵdirectiveInject(i1.ActiveTasksService)); };
|
|
150
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: GlobalTasksPanelComponent, selectors: [["mj-global-tasks-panel"]], outputs: { taskClicked: "taskClicked" }, decls: 1, vars: 1, consts: [["class", "global-tasks-panel", 4, "ngIf"], [1, "global-tasks-panel"], ["class", "minimized-badge", "title", "View active tasks", 3, "click", 4, "ngIf"], ["class", "expanded-panel", 4, "ngIf"], ["title", "View active tasks", 1, "minimized-badge", 3, "click"], [1, "fas", "fa-bolt"], [1, "task-count"], [1, "expanded-panel"], [1, "panel-header"], [1, "header-left"], [1, "fas", "fa-circle-notch", "fa-spin"], ["title", "Minimize", 1, "minimize-btn", 3, "click"], [1, "fas", "fa-minus"], [1, "panel-content"], ["class", "task-item", 3, "click", 4, "ngFor", "ngForOf"], [1, "task-item", 3, "click"], [1, "task-header"], [1, "fas", "fa-robot"], [1, "task-agent"], ["class", "task-conversation", 4, "ngIf"], [1, "task-status"], [1, "status-indicator", "active"], [1, "status-text"], [1, "task-elapsed"], [1, "task-conversation"], [1, "fas", "fa-message"]], template: function GlobalTasksPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
151
|
+
i0.ɵɵtemplate(0, GlobalTasksPanelComponent_div_0_Template, 3, 2, "div", 0);
|
|
152
|
+
} if (rf & 2) {
|
|
153
|
+
i0.ɵɵproperty("ngIf", ctx.tasks.length > 0);
|
|
154
|
+
} }, dependencies: [i2.NgForOf, i2.NgIf], styles: [".global-tasks-panel[_ngcontent-%COMP%] {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 9999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n \n\n .minimized-badge[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n border-radius: 50%;\n width: 56px;\n height: 56px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transition: all 0.3s ease;\n position: relative;\n animation: _ngcontent-%COMP%_pulse 2s ease-in-out infinite;\n }\n\n .minimized-badge[_ngcontent-%COMP%]:hover {\n transform: scale(1.1);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);\n }\n\n .minimized-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n margin-right: 4px;\n }\n\n .minimized-badge[_ngcontent-%COMP%] .task-count[_ngcontent-%COMP%] {\n position: absolute;\n top: -4px;\n right: -4px;\n background: #ef4444;\n color: white;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n border: 2px solid white;\n }\n\n @keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n 50% {\n box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4);\n }\n }\n\n \n\n .expanded-panel[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);\n width: 360px;\n max-height: 480px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideIn 0.3s ease-out;\n }\n\n @keyframes _ngcontent-%COMP%_slideIn {\n from {\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n .panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px;\n border-bottom: 1px solid #e5e7eb;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n }\n\n .header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 14px;\n }\n\n .header-left[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .minimize-btn[_ngcontent-%COMP%] {\n background: rgba(255, 255, 255, 0.2);\n color: white;\n border: none;\n border-radius: 6px;\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .minimize-btn[_ngcontent-%COMP%]:hover {\n background: rgba(255, 255, 255, 0.3);\n }\n\n .panel-content[_ngcontent-%COMP%] {\n overflow-y: auto;\n max-height: 420px;\n }\n\n .task-item[_ngcontent-%COMP%] {\n padding: 12px 16px;\n border-bottom: 1px solid #f3f4f6;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .task-item[_ngcontent-%COMP%]:hover {\n background: #f9fafb;\n }\n\n .task-item[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n }\n\n .task-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n }\n\n .task-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #667eea;\n font-size: 14px;\n }\n\n .task-agent[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 13px;\n color: #111827;\n }\n\n .task-conversation[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: #6b7280;\n margin-bottom: 6px;\n }\n\n .task-conversation[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n }\n\n .task-status[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 4px;\n }\n\n .status-indicator[_ngcontent-%COMP%] {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n .status-indicator.active[_ngcontent-%COMP%] {\n background: #10b981;\n animation: _ngcontent-%COMP%_blink 2s ease-in-out infinite;\n }\n\n @keyframes _ngcontent-%COMP%_blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n }\n\n .status-text[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #4b5563;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .task-elapsed[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #9ca3af;\n font-variant-numeric: tabular-nums;\n }\n\n \n\n .panel-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n }\n\n .panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: #f9fafb;\n }\n\n .panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 3px;\n }\n\n .panel-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: #9ca3af;\n }"] });
|
|
155
|
+
}
|
|
156
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GlobalTasksPanelComponent, [{
|
|
157
|
+
type: Component,
|
|
158
|
+
args: [{ selector: 'mj-global-tasks-panel', template: `
|
|
159
|
+
<div class="global-tasks-panel" *ngIf="tasks.length > 0">
|
|
160
|
+
<!-- Minimized State -->
|
|
161
|
+
<button
|
|
162
|
+
*ngIf="isMinimized"
|
|
163
|
+
class="minimized-badge"
|
|
164
|
+
(click)="expand()"
|
|
165
|
+
title="View active tasks">
|
|
166
|
+
<i class="fas fa-bolt"></i>
|
|
167
|
+
<span class="task-count">{{ tasks.length }}</span>
|
|
168
|
+
</button>
|
|
169
|
+
|
|
170
|
+
<!-- Expanded State -->
|
|
171
|
+
<div *ngIf="!isMinimized" class="expanded-panel">
|
|
172
|
+
<div class="panel-header">
|
|
173
|
+
<div class="header-left">
|
|
174
|
+
<i class="fas fa-circle-notch fa-spin"></i>
|
|
175
|
+
<span>Active Tasks ({{ tasks.length }})</span>
|
|
176
|
+
</div>
|
|
177
|
+
<button class="minimize-btn" (click)="minimize()" title="Minimize">
|
|
178
|
+
<i class="fas fa-minus"></i>
|
|
179
|
+
</button>
|
|
180
|
+
</div>
|
|
181
|
+
|
|
182
|
+
<div class="panel-content">
|
|
183
|
+
<div class="task-item" *ngFor="let task of tasks" (click)="onTaskClick(task)">
|
|
184
|
+
<div class="task-header">
|
|
185
|
+
<i class="fas fa-robot"></i>
|
|
186
|
+
<span class="task-agent">{{ task.agentName }}</span>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="task-conversation" *ngIf="task.conversationName">
|
|
189
|
+
<i class="fas fa-message"></i>
|
|
190
|
+
<span>{{ task.conversationName }}</span>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="task-status">
|
|
193
|
+
<span class="status-indicator active"></span>
|
|
194
|
+
<span class="status-text">{{ getTrimmedStatus(task.status) }}</span>
|
|
195
|
+
</div>
|
|
196
|
+
<div class="task-elapsed">{{ getElapsedTime(task) }}</div>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
`, styles: ["\n .global-tasks-panel {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 9999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n /* Minimized Badge */\n .minimized-badge {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n border-radius: 50%;\n width: 56px;\n height: 56px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transition: all 0.3s ease;\n position: relative;\n animation: pulse 2s ease-in-out infinite;\n }\n\n .minimized-badge:hover {\n transform: scale(1.1);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);\n }\n\n .minimized-badge i {\n font-size: 20px;\n margin-right: 4px;\n }\n\n .minimized-badge .task-count {\n position: absolute;\n top: -4px;\n right: -4px;\n background: #ef4444;\n color: white;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n border: 2px solid white;\n }\n\n @keyframes pulse {\n 0%, 100% {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n 50% {\n box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4);\n }\n }\n\n /* Expanded Panel */\n .expanded-panel {\n background: white;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);\n width: 360px;\n max-height: 480px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.3s ease-out;\n }\n\n @keyframes slideIn {\n from {\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n .panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px;\n border-bottom: 1px solid #e5e7eb;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n }\n\n .header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 14px;\n }\n\n .header-left i {\n font-size: 16px;\n }\n\n .minimize-btn {\n background: rgba(255, 255, 255, 0.2);\n color: white;\n border: none;\n border-radius: 6px;\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .minimize-btn:hover {\n background: rgba(255, 255, 255, 0.3);\n }\n\n .panel-content {\n overflow-y: auto;\n max-height: 420px;\n }\n\n .task-item {\n padding: 12px 16px;\n border-bottom: 1px solid #f3f4f6;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .task-item:hover {\n background: #f9fafb;\n }\n\n .task-item:last-child {\n border-bottom: none;\n }\n\n .task-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n }\n\n .task-header i {\n color: #667eea;\n font-size: 14px;\n }\n\n .task-agent {\n font-weight: 600;\n font-size: 13px;\n color: #111827;\n }\n\n .task-conversation {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: #6b7280;\n margin-bottom: 6px;\n }\n\n .task-conversation i {\n font-size: 11px;\n }\n\n .task-status {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 4px;\n }\n\n .status-indicator {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n .status-indicator.active {\n background: #10b981;\n animation: blink 2s ease-in-out infinite;\n }\n\n @keyframes blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n }\n\n .status-text {\n font-size: 12px;\n color: #4b5563;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .task-elapsed {\n font-size: 11px;\n color: #9ca3af;\n font-variant-numeric: tabular-nums;\n }\n\n /* Scrollbar Styling */\n .panel-content::-webkit-scrollbar {\n width: 6px;\n }\n\n .panel-content::-webkit-scrollbar-track {\n background: #f9fafb;\n }\n\n .panel-content::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 3px;\n }\n\n .panel-content::-webkit-scrollbar-thumb:hover {\n background: #9ca3af;\n }\n "] }]
|
|
202
|
+
}], () => [{ type: i1.ActiveTasksService }], { taskClicked: [{
|
|
203
|
+
type: Output
|
|
204
|
+
}] }); })();
|
|
205
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GlobalTasksPanelComponent, { className: "GlobalTasksPanelComponent", filePath: "src/lib/components/global-tasks/global-tasks-panel.component.ts", lineNumber: 292 }); })();
|
|
206
|
+
//# sourceMappingURL=global-tasks-panel.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-tasks-panel.component.js","sourceRoot":"","sources":["../../../../src/lib/components/global-tasks/global-tasks-panel.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { OnInit } from '@angular/core';
|
|
2
|
+
import { UserInfo } from '@memberjunction/core';
|
|
3
|
+
import { RatingJSON } from '../../models/conversation-complete-query.model';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Component for displaying and managing multi-user ratings on conversation messages.
|
|
7
|
+
* Shows aggregate ratings and allows users to provide their own rating.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ConversationMessageRatingComponent implements OnInit {
|
|
10
|
+
conversationDetailId: string;
|
|
11
|
+
currentUser: UserInfo;
|
|
12
|
+
ratingsData?: RatingJSON[];
|
|
13
|
+
thumbsUpCount: number;
|
|
14
|
+
thumbsDownCount: number;
|
|
15
|
+
totalRatings: number;
|
|
16
|
+
currentUserRating: number | null;
|
|
17
|
+
allRatings: RatingJSON[];
|
|
18
|
+
private get currentUserId();
|
|
19
|
+
ngOnInit(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Process ratings data (from query or API)
|
|
22
|
+
*/
|
|
23
|
+
private ProcessRatings;
|
|
24
|
+
/**
|
|
25
|
+
* Get tooltip showing who rated this message
|
|
26
|
+
*/
|
|
27
|
+
getRatingsTooltip(): string;
|
|
28
|
+
/**
|
|
29
|
+
* Load all ratings for this message (fallback if not pre-loaded)
|
|
30
|
+
*/
|
|
31
|
+
LoadRatings(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Rate message as thumbs up (10/10)
|
|
34
|
+
*/
|
|
35
|
+
RateThumbsUp(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Rate message as thumbs down (1/10)
|
|
38
|
+
*/
|
|
39
|
+
RateThumbsDown(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Save or update user's rating for this message
|
|
42
|
+
*/
|
|
43
|
+
private SaveRating;
|
|
44
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ConversationMessageRatingComponent, never>;
|
|
45
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ConversationMessageRatingComponent, "mj-conversation-message-rating", never, { "conversationDetailId": { "alias": "conversationDetailId"; "required": false; }; "currentUser": { "alias": "currentUser"; "required": false; }; "ratingsData": { "alias": "ratingsData"; "required": false; }; }, {}, never, never, false, never>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=conversation-message-rating.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-message-rating.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/message/conversation-message-rating.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,MAAM,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAqB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAC;;AAE5E;;;GAGG;AACH,qBAqHa,kCAAmC,YAAW,MAAM;IACpD,oBAAoB,EAAG,MAAM,CAAC;IAC9B,WAAW,EAAG,QAAQ,CAAC;IACvB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAEpC,aAAa,SAAK;IAClB,eAAe,SAAK;IACpB,YAAY,SAAK;IACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC,UAAU,EAAE,UAAU,EAAE,CAAM;IAE9B,OAAO,KAAK,aAAa,GAExB;IAEK,QAAQ;IAUd;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAoB3B;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBlC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC;;OAEG;YACW,UAAU;yCArGf,kCAAkC;2CAAlC,kCAAkC;CA8I9C"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { Component, Input } from '@angular/core';
|
|
2
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "@angular/common";
|
|
5
|
+
function ConversationMessageRatingComponent_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
6
|
+
i0.ɵɵelementStart(0, "div", 5)(1, "span", 6);
|
|
7
|
+
i0.ɵɵtext(2);
|
|
8
|
+
i0.ɵɵelementEnd();
|
|
9
|
+
i0.ɵɵelementStart(3, "span", 7);
|
|
10
|
+
i0.ɵɵtext(4);
|
|
11
|
+
i0.ɵɵelementEnd();
|
|
12
|
+
i0.ɵɵelementStart(5, "span", 8);
|
|
13
|
+
i0.ɵɵtext(6);
|
|
14
|
+
i0.ɵɵelementEnd()();
|
|
15
|
+
} if (rf & 2) {
|
|
16
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
17
|
+
i0.ɵɵproperty("title", ctx_r0.getRatingsTooltip());
|
|
18
|
+
i0.ɵɵadvance();
|
|
19
|
+
i0.ɵɵclassProp("has-votes", ctx_r0.thumbsUpCount > 0);
|
|
20
|
+
i0.ɵɵadvance();
|
|
21
|
+
i0.ɵɵtextInterpolate1(" \uD83D\uDC4D ", ctx_r0.thumbsUpCount, " ");
|
|
22
|
+
i0.ɵɵadvance();
|
|
23
|
+
i0.ɵɵclassProp("has-votes", ctx_r0.thumbsDownCount > 0);
|
|
24
|
+
i0.ɵɵadvance();
|
|
25
|
+
i0.ɵɵtextInterpolate1(" \uD83D\uDC4E ", ctx_r0.thumbsDownCount, " ");
|
|
26
|
+
i0.ɵɵadvance(2);
|
|
27
|
+
i0.ɵɵtextInterpolate2("(", ctx_r0.totalRatings, " ", ctx_r0.totalRatings === 1 ? "rating" : "ratings", ")");
|
|
28
|
+
} }
|
|
29
|
+
/**
|
|
30
|
+
* Component for displaying and managing multi-user ratings on conversation messages.
|
|
31
|
+
* Shows aggregate ratings and allows users to provide their own rating.
|
|
32
|
+
*/
|
|
33
|
+
export class ConversationMessageRatingComponent {
|
|
34
|
+
conversationDetailId;
|
|
35
|
+
currentUser;
|
|
36
|
+
ratingsData; // Pre-loaded ratings from parent (RatingsJSON from query)
|
|
37
|
+
thumbsUpCount = 0;
|
|
38
|
+
thumbsDownCount = 0;
|
|
39
|
+
totalRatings = 0;
|
|
40
|
+
currentUserRating = null;
|
|
41
|
+
allRatings = [];
|
|
42
|
+
get currentUserId() {
|
|
43
|
+
return this.currentUser?.ID || '';
|
|
44
|
+
}
|
|
45
|
+
async ngOnInit() {
|
|
46
|
+
if (this.ratingsData) {
|
|
47
|
+
// Use pre-loaded ratings (no database query needed)
|
|
48
|
+
this.ProcessRatings(this.ratingsData);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Fallback to loading ratings if not provided
|
|
52
|
+
await this.LoadRatings();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Process ratings data (from query or API)
|
|
57
|
+
*/
|
|
58
|
+
ProcessRatings(ratings) {
|
|
59
|
+
this.allRatings = ratings;
|
|
60
|
+
this.thumbsUpCount = ratings.filter(r => r.Rating ? r.Rating >= 8 : false).length;
|
|
61
|
+
this.thumbsDownCount = ratings.filter(r => r.Rating ? r.Rating <= 3 : false).length;
|
|
62
|
+
this.totalRatings = ratings.length;
|
|
63
|
+
const currentUserRating = ratings.find(r => r.UserID === this.currentUserId);
|
|
64
|
+
this.currentUserRating = currentUserRating?.Rating ?? null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get tooltip showing who rated this message
|
|
68
|
+
*/
|
|
69
|
+
getRatingsTooltip() {
|
|
70
|
+
if (this.allRatings.length === 0)
|
|
71
|
+
return '';
|
|
72
|
+
const thumbsUpUsers = this.allRatings
|
|
73
|
+
.filter(r => r.Rating ? r.Rating >= 8 : false)
|
|
74
|
+
.map(r => r.UserName || 'Unknown')
|
|
75
|
+
.join(', ');
|
|
76
|
+
const thumbsDownUsers = this.allRatings
|
|
77
|
+
.filter(r => r.Rating ? r.Rating <= 3 : false)
|
|
78
|
+
.map(r => r.UserName || 'Unknown')
|
|
79
|
+
.join(', ');
|
|
80
|
+
const parts = [];
|
|
81
|
+
if (thumbsUpUsers)
|
|
82
|
+
parts.push(`👍 ${thumbsUpUsers}`);
|
|
83
|
+
if (thumbsDownUsers)
|
|
84
|
+
parts.push(`👎 ${thumbsDownUsers}`);
|
|
85
|
+
return parts.join('\n');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Load all ratings for this message (fallback if not pre-loaded)
|
|
89
|
+
*/
|
|
90
|
+
async LoadRatings() {
|
|
91
|
+
try {
|
|
92
|
+
const rv = new RunView();
|
|
93
|
+
const result = await rv.RunView({
|
|
94
|
+
EntityName: 'MJ: Conversation Detail Ratings',
|
|
95
|
+
ExtraFilter: `ConversationDetailID='${this.conversationDetailId}'`,
|
|
96
|
+
ResultType: 'entity_object'
|
|
97
|
+
});
|
|
98
|
+
if (!result.Success || !result.Results) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this.ProcessRatings(result.Results);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.error('Failed to load ratings:', error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Rate message as thumbs up (10/10)
|
|
109
|
+
*/
|
|
110
|
+
async RateThumbsUp() {
|
|
111
|
+
await this.SaveRating(10);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Rate message as thumbs down (1/10)
|
|
115
|
+
*/
|
|
116
|
+
async RateThumbsDown() {
|
|
117
|
+
await this.SaveRating(1);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Save or update user's rating for this message
|
|
121
|
+
*/
|
|
122
|
+
async SaveRating(rating) {
|
|
123
|
+
try {
|
|
124
|
+
const md = new Metadata();
|
|
125
|
+
let ratingEntity;
|
|
126
|
+
// Try to load existing rating
|
|
127
|
+
const rv = new RunView();
|
|
128
|
+
const existing = await rv.RunView({
|
|
129
|
+
EntityName: 'MJ: Conversation Detail Ratings',
|
|
130
|
+
ExtraFilter: `ConversationDetailID='${this.conversationDetailId}' AND UserID='${this.currentUserId}'`,
|
|
131
|
+
MaxRows: 1,
|
|
132
|
+
ResultType: 'entity_object'
|
|
133
|
+
});
|
|
134
|
+
if (existing.Success && existing.Results && existing.Results.length > 0) {
|
|
135
|
+
// Update existing
|
|
136
|
+
ratingEntity = existing.Results[0];
|
|
137
|
+
// If clicking same rating, remove it (toggle off)
|
|
138
|
+
if (ratingEntity.Rating === rating) {
|
|
139
|
+
await ratingEntity.Delete();
|
|
140
|
+
await this.LoadRatings();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
ratingEntity.Rating = rating;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Create new
|
|
147
|
+
ratingEntity = await md.GetEntityObject('MJ: Conversation Detail Ratings');
|
|
148
|
+
ratingEntity.ConversationDetailID = this.conversationDetailId;
|
|
149
|
+
ratingEntity.UserID = this.currentUserId;
|
|
150
|
+
ratingEntity.Rating = rating;
|
|
151
|
+
}
|
|
152
|
+
await ratingEntity.Save();
|
|
153
|
+
await this.LoadRatings();
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
console.error('Failed to save rating:', error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
static ɵfac = function ConversationMessageRatingComponent_Factory(t) { return new (t || ConversationMessageRatingComponent)(); };
|
|
160
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ConversationMessageRatingComponent, selectors: [["mj-conversation-message-rating"]], inputs: { conversationDetailId: "conversationDetailId", currentUser: "currentUser", ratingsData: "ratingsData" }, decls: 7, vars: 7, consts: [[1, "rating-container"], ["class", "aggregate-rating", 3, "title", 4, "ngIf"], [1, "user-rating"], ["title", "This was helpful", "type", "button", 1, "rating-button", "thumbs-up-btn", 3, "click"], ["title", "This was not helpful", "type", "button", 1, "rating-button", "thumbs-down-btn", 3, "click"], [1, "aggregate-rating", 3, "title"], [1, "thumbs-up"], [1, "thumbs-down"], [1, "total-count"]], template: function ConversationMessageRatingComponent_Template(rf, ctx) { if (rf & 1) {
|
|
161
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
162
|
+
i0.ɵɵtemplate(1, ConversationMessageRatingComponent_div_1_Template, 7, 9, "div", 1);
|
|
163
|
+
i0.ɵɵelementStart(2, "div", 2)(3, "button", 3);
|
|
164
|
+
i0.ɵɵlistener("click", function ConversationMessageRatingComponent_Template_button_click_3_listener() { return ctx.RateThumbsUp(); });
|
|
165
|
+
i0.ɵɵtext(4, " \uD83D\uDC4D ");
|
|
166
|
+
i0.ɵɵelementEnd();
|
|
167
|
+
i0.ɵɵelementStart(5, "button", 4);
|
|
168
|
+
i0.ɵɵlistener("click", function ConversationMessageRatingComponent_Template_button_click_5_listener() { return ctx.RateThumbsDown(); });
|
|
169
|
+
i0.ɵɵtext(6, " \uD83D\uDC4E ");
|
|
170
|
+
i0.ɵɵelementEnd()()();
|
|
171
|
+
} if (rf & 2) {
|
|
172
|
+
i0.ɵɵadvance();
|
|
173
|
+
i0.ɵɵproperty("ngIf", ctx.totalRatings > 0);
|
|
174
|
+
i0.ɵɵadvance();
|
|
175
|
+
i0.ɵɵclassProp("has-rated", ctx.currentUserRating != null);
|
|
176
|
+
i0.ɵɵadvance();
|
|
177
|
+
i0.ɵɵclassProp("active", ctx.currentUserRating != null && ctx.currentUserRating >= 8);
|
|
178
|
+
i0.ɵɵadvance(2);
|
|
179
|
+
i0.ɵɵclassProp("active", ctx.currentUserRating != null && ctx.currentUserRating <= 3);
|
|
180
|
+
} }, dependencies: [i1.NgIf], styles: [".rating-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .aggregate-rating[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #666;\n }\n\n .thumbs-up[_ngcontent-%COMP%], .thumbs-down[_ngcontent-%COMP%] {\n opacity: 0.5;\n }\n\n .thumbs-up.has-votes[_ngcontent-%COMP%], .thumbs-down.has-votes[_ngcontent-%COMP%] {\n opacity: 1;\n }\n\n .total-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #999;\n }\n\n .user-rating[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #9CA3AF;\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n font-size: 16px;\n opacity: 0.6;\n transition: all 0.2s;\n min-width: 36px;\n }\n\n .rating-button[_ngcontent-%COMP%]:hover {\n opacity: 1;\n border-color: #6B7280;\n }\n\n .rating-button.active[_ngcontent-%COMP%] {\n opacity: 1;\n }\n\n .thumbs-up-btn[_ngcontent-%COMP%] {\n color: #16A34A;\n }\n\n .thumbs-up-btn[_ngcontent-%COMP%]:hover {\n background: #F0FDF4;\n }\n\n .thumbs-up-btn.active[_ngcontent-%COMP%] {\n border-color: #16A34A;\n background: #DCFCE7;\n }\n\n .thumbs-down-btn[_ngcontent-%COMP%] {\n color: #DC2626;\n }\n\n .thumbs-down-btn[_ngcontent-%COMP%]:hover {\n background: #FEF2F2;\n }\n\n .thumbs-down-btn.active[_ngcontent-%COMP%] {\n border-color: #DC2626;\n background: #FEE2E2;\n }"] });
|
|
181
|
+
}
|
|
182
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ConversationMessageRatingComponent, [{
|
|
183
|
+
type: Component,
|
|
184
|
+
args: [{ selector: 'mj-conversation-message-rating', template: `
|
|
185
|
+
<div class="rating-container">
|
|
186
|
+
<div class="aggregate-rating" *ngIf="totalRatings > 0" [title]="getRatingsTooltip()">
|
|
187
|
+
<span class="thumbs-up" [class.has-votes]="thumbsUpCount > 0">
|
|
188
|
+
👍 {{ thumbsUpCount }}
|
|
189
|
+
</span>
|
|
190
|
+
<span class="thumbs-down" [class.has-votes]="thumbsDownCount > 0">
|
|
191
|
+
👎 {{ thumbsDownCount }}
|
|
192
|
+
</span>
|
|
193
|
+
<span class="total-count">({{ totalRatings }} {{ totalRatings === 1 ? 'rating' : 'ratings' }})</span>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div class="user-rating" [class.has-rated]="currentUserRating != null">
|
|
197
|
+
<button
|
|
198
|
+
class="rating-button thumbs-up-btn"
|
|
199
|
+
[class.active]="currentUserRating != null && currentUserRating >= 8"
|
|
200
|
+
(click)="RateThumbsUp()"
|
|
201
|
+
title="This was helpful"
|
|
202
|
+
type="button">
|
|
203
|
+
👍
|
|
204
|
+
</button>
|
|
205
|
+
<button
|
|
206
|
+
class="rating-button thumbs-down-btn"
|
|
207
|
+
[class.active]="currentUserRating != null && currentUserRating <= 3"
|
|
208
|
+
(click)="RateThumbsDown()"
|
|
209
|
+
title="This was not helpful"
|
|
210
|
+
type="button">
|
|
211
|
+
👎
|
|
212
|
+
</button>
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
`, styles: ["\n .rating-container {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n\n .aggregate-rating {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #666;\n }\n\n .thumbs-up, .thumbs-down {\n opacity: 0.5;\n }\n\n .thumbs-up.has-votes, .thumbs-down.has-votes {\n opacity: 1;\n }\n\n .total-count {\n font-size: 12px;\n color: #999;\n }\n\n .user-rating {\n display: flex;\n gap: 4px;\n margin-left: auto;\n }\n\n .rating-button {\n background: white;\n border: 1px solid #9CA3AF;\n border-radius: 6px;\n padding: 6px 10px;\n cursor: pointer;\n font-size: 16px;\n opacity: 0.6;\n transition: all 0.2s;\n min-width: 36px;\n }\n\n .rating-button:hover {\n opacity: 1;\n border-color: #6B7280;\n }\n\n .rating-button.active {\n opacity: 1;\n }\n\n .thumbs-up-btn {\n color: #16A34A;\n }\n\n .thumbs-up-btn:hover {\n background: #F0FDF4;\n }\n\n .thumbs-up-btn.active {\n border-color: #16A34A;\n background: #DCFCE7;\n }\n\n .thumbs-down-btn {\n color: #DC2626;\n }\n\n .thumbs-down-btn:hover {\n background: #FEF2F2;\n }\n\n .thumbs-down-btn.active {\n border-color: #DC2626;\n background: #FEE2E2;\n }\n "] }]
|
|
216
|
+
}], null, { conversationDetailId: [{
|
|
217
|
+
type: Input
|
|
218
|
+
}], currentUser: [{
|
|
219
|
+
type: Input
|
|
220
|
+
}], ratingsData: [{
|
|
221
|
+
type: Input
|
|
222
|
+
}] }); })();
|
|
223
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationMessageRatingComponent, { className: "ConversationMessageRatingComponent", filePath: "src/lib/components/message/conversation-message-rating.component.ts", lineNumber: 127 }); })();
|
|
224
|
+
//# sourceMappingURL=conversation-message-rating.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-message-rating.component.js","sourceRoot":"","sources":["../../../../src/lib/components/message/conversation-message-rating.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-input-box.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/message/message-input-box.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAa,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAChI,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;;AAE5G;;;;;;;;;;;;;GAaG;AACH,qBAKa,wBAAyB,YAAW,MAAM,EAAE,aAAa,EAAE,SAAS;IAuB7E,OAAO,CAAC,mBAAmB;IAtBpB,WAAW,EAAE,MAAM,CAAsD;IACzE,QAAQ,EAAE,OAAO,CAAS;IAC1B,KAAK,EAAE,MAAM,CAAM;IACnB,kBAAkB,EAAE,OAAO,CAAS;IACpC,cAAc,EAAE,OAAO,CAAQ;IAC/B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,IAAI,EAAE,MAAM,CAAK;IAEhB,aAAa,uBAA8B;IAC3C,WAAW,uBAA8B;IAErB,eAAe,CAAC,EAAE,UAAU,CAAC;IAGpD,mBAAmB,EAAE,OAAO,CAAS;IACrC,kBAAkB,EAAE,iBAAiB,EAAE,CAAM;IAC7C,uBAAuB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAuB;IAC7E,wBAAwB,EAAE,OAAO,CAAS;IACjD,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,YAAY,CAAc;gBAGxB,mBAAmB,EAAE,0BAA0B;IAGnD,QAAQ;
|
|
1
|
+
{"version":3,"file":"message-input-box.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/message/message-input-box.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAa,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAChI,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;;AAE5G;;;;;;;;;;;;;GAaG;AACH,qBAKa,wBAAyB,YAAW,MAAM,EAAE,aAAa,EAAE,SAAS;IAuB7E,OAAO,CAAC,mBAAmB;IAtBpB,WAAW,EAAE,MAAM,CAAsD;IACzE,QAAQ,EAAE,OAAO,CAAS;IAC1B,KAAK,EAAE,MAAM,CAAM;IACnB,kBAAkB,EAAE,OAAO,CAAS;IACpC,cAAc,EAAE,OAAO,CAAQ;IAC/B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,IAAI,EAAE,MAAM,CAAK;IAEhB,aAAa,uBAA8B;IAC3C,WAAW,uBAA8B;IAErB,eAAe,CAAC,EAAE,UAAU,CAAC;IAGpD,mBAAmB,EAAE,OAAO,CAAS;IACrC,kBAAkB,EAAE,iBAAiB,EAAE,CAAM;IAC7C,uBAAuB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAuB;IAC7E,wBAAwB,EAAE,OAAO,CAAS;IACjD,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,YAAY,CAAc;gBAGxB,mBAAmB,EAAE,0BAA0B;IAGnD,QAAQ;IAOd,eAAe;IAOf,WAAW;IAIX,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAerC,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAW3B,WAAW,IAAI,IAAI;IAUnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAuC1B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA6B/B;;OAEG;IACH,iBAAiB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAsBtD;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAO5B;;OAEG;IACI,KAAK,IAAI,IAAI;yCArMT,wBAAwB;2CAAxB,wBAAwB;CAwMpC"}
|
|
@@ -52,10 +52,8 @@ export class MessageInputBoxComponent {
|
|
|
52
52
|
}
|
|
53
53
|
async ngOnInit() {
|
|
54
54
|
// Initialize mention autocomplete if enabled and currentUser is available
|
|
55
|
-
console.log('[MessageInputBox] ngOnInit - enableMentions:', this.enableMentions, 'currentUser:', !!this.currentUser);
|
|
56
55
|
if (this.enableMentions && this.currentUser) {
|
|
57
56
|
await this.mentionAutocomplete.initialize(this.currentUser);
|
|
58
|
-
console.log('[MessageInputBox] Mention autocomplete initialized');
|
|
59
57
|
}
|
|
60
58
|
}
|
|
61
59
|
ngAfterViewInit() {
|
|
@@ -87,7 +85,6 @@ export class MessageInputBoxComponent {
|
|
|
87
85
|
const textarea = event.target;
|
|
88
86
|
this.value = textarea.value;
|
|
89
87
|
this.valueChange.emit(this.value);
|
|
90
|
-
console.log('[MessageInputBox] onInput - value:', this.value, 'enableMentions:', this.enableMentions, 'currentUser:', !!this.currentUser);
|
|
91
88
|
// Handle @mention autocomplete
|
|
92
89
|
if (this.enableMentions && this.currentUser) {
|
|
93
90
|
this.handleMentionInput();
|
|
@@ -96,7 +93,6 @@ export class MessageInputBoxComponent {
|
|
|
96
93
|
onSendClick() {
|
|
97
94
|
if (this.canSend) {
|
|
98
95
|
const textToSend = this.value.trim();
|
|
99
|
-
console.log('[MessageInputBox] onSendClick - emitting text:', textToSend);
|
|
100
96
|
this.textSubmitted.emit(textToSend);
|
|
101
97
|
this.value = ''; // Clear input after sending
|
|
102
98
|
this.valueChange.emit(this.value);
|
|
@@ -109,12 +105,10 @@ export class MessageInputBoxComponent {
|
|
|
109
105
|
handleMentionInput() {
|
|
110
106
|
const textarea = this.messageTextarea?.nativeElement;
|
|
111
107
|
if (!textarea) {
|
|
112
|
-
console.log('[MessageInputBox] No textarea element');
|
|
113
108
|
return;
|
|
114
109
|
}
|
|
115
110
|
const cursorPos = textarea.selectionStart;
|
|
116
111
|
const textBeforeCursor = this.value.substring(0, cursorPos);
|
|
117
|
-
console.log('[MessageInputBox] handleMentionInput - textBeforeCursor:', textBeforeCursor);
|
|
118
112
|
// Find the last @ before cursor
|
|
119
113
|
const lastAtIndex = textBeforeCursor.lastIndexOf('@');
|
|
120
114
|
if (lastAtIndex === -1) {
|
|
@@ -130,14 +124,11 @@ export class MessageInputBoxComponent {
|
|
|
130
124
|
// Extract query
|
|
131
125
|
this.mentionQuery = textAfterAt;
|
|
132
126
|
this.mentionStartIndex = lastAtIndex;
|
|
133
|
-
console.log('[MessageInputBox] Mention detected - query:', this.mentionQuery);
|
|
134
127
|
// Get suggestions (include users if we have currentUser)
|
|
135
128
|
this.mentionSuggestions = this.mentionAutocomplete.getSuggestions(this.mentionQuery, !!this.currentUser);
|
|
136
|
-
console.log('[MessageInputBox] Got suggestions:', this.mentionSuggestions.length, this.mentionSuggestions);
|
|
137
129
|
if (this.mentionSuggestions.length > 0) {
|
|
138
130
|
this.showMentionDropdown = true;
|
|
139
131
|
this.positionMentionDropdown();
|
|
140
|
-
console.log('[MessageInputBox] Showing dropdown at position:', this.mentionDropdownPosition);
|
|
141
132
|
}
|
|
142
133
|
else {
|
|
143
134
|
this.closeMentionDropdown();
|
|
@@ -172,7 +163,6 @@ export class MessageInputBoxComponent {
|
|
|
172
163
|
left: textareaRect.left + window.scrollX
|
|
173
164
|
};
|
|
174
165
|
}
|
|
175
|
-
console.log('[MessageInputBox] Dropdown position calculated (viewport coords):', this.mentionDropdownPosition, 'showAbove:', this.mentionDropdownShowAbove);
|
|
176
166
|
}
|
|
177
167
|
/**
|
|
178
168
|
* Insert selected mention into text
|
|
@@ -236,11 +226,11 @@ export class MessageInputBoxComponent {
|
|
|
236
226
|
i0.ɵɵproperty("disabled", !ctx.canSend);
|
|
237
227
|
i0.ɵɵadvance(2);
|
|
238
228
|
i0.ɵɵproperty("ngIf", ctx.showMentionDropdown && ctx.enableMentions);
|
|
239
|
-
} }, dependencies: [i2.NgIf, i3.DefaultValueAccessor, i3.NgControlStatus, i3.NgModel, i4.MentionDropdownComponent], styles: [".message-input-box-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: white;\n border: 2px solid var(--border-color, #e0e0e0);\n border-radius: 12px;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);\n transition: all 0.2s ease;\n overflow: visible; // Allow mention dropdown to escape container\n position: relative;\n\n &:focus-within {\n border-color: var(--primary-color, #007bff);\n box-shadow: 0 4px 16px rgba(0, 123, 255, 0.15);\n }\n}\n\n.input-wrapper[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: flex-end; // Align send button to bottom\n}\n\n.message-input-box-textarea[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 100px;\n padding: 1rem;\n padding-right: 3.5rem; // Space for send button\n border: 0 !important;\n outline: 0 !important;\n box-shadow: none !important;\n -webkit-appearance: none !important;\n -moz-appearance: none !important;\n appearance: none !important;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n resize: vertical;\n background: transparent;\n\n &::placeholder {\n color: var(--text-tertiary, #999);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--background-disabled, #f5f5f5);\n }\n\n &:focus,\n &:active,\n &:focus-visible {\n
|
|
229
|
+
} }, dependencies: [i2.NgIf, i3.DefaultValueAccessor, i3.NgControlStatus, i3.NgModel, i4.MentionDropdownComponent], styles: [".message-input-box-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: white;\n border: 2px solid var(--border-color, #e0e0e0);\n border-radius: 12px;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);\n transition: all 0.2s ease;\n overflow: visible; // Allow mention dropdown to escape container\n position: relative;\n\n &:focus-within {\n border-color: var(--primary-color, #007bff);\n box-shadow: 0 4px 16px rgba(0, 123, 255, 0.15);\n }\n}\n\n.input-wrapper[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: flex-end; // Align send button to bottom\n}\n\n.message-input-box-textarea[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 100px;\n padding: 1rem;\n padding-right: 3.5rem; // Space for send button\n border: 0 !important;\n outline: 0 !important;\n box-shadow: none !important;\n -webkit-appearance: none !important;\n -moz-appearance: none !important;\n appearance: none !important;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n resize: vertical;\n background: transparent;\n border: 0 !important;\n\n &::placeholder {\n color: var(--text-tertiary, #999);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--background-disabled, #f5f5f5);\n }\n\n &:focus,\n &:active,\n &:focus-visible {\n outline: 0 !important;\n box-shadow: none !important;\n }\n}\n\n.send-button-icon[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0.75rem;\n right: 0.75rem;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--primary-color, #007bff);\n color: white;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n\n i {\n font-size: 1rem;\n }\n\n &:hover:not(:disabled) {\n background: var(--primary-color-dark, #0056b3);\n transform: scale(1.05);\n }\n\n &:active:not(:disabled) {\n transform: scale(0.95);\n }\n\n &:disabled {\n background: var(--background-disabled, #d0d0d0);\n color: var(--text-disabled, #999);\n cursor: not-allowed;\n opacity: 0.5;\n }\n}"] });
|
|
240
230
|
}
|
|
241
231
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MessageInputBoxComponent, [{
|
|
242
232
|
type: Component,
|
|
243
|
-
args: [{ selector: 'mj-message-input-box', template: "<div class=\"message-input-box-container\">\n <div class=\"input-wrapper\">\n <textarea\n #messageTextarea\n class=\"message-input-box-textarea\"\n [(ngModel)]=\"value\"\n [disabled]=\"disabled\"\n [placeholder]=\"placeholder\"\n [rows]=\"rows\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n ></textarea>\n\n <!-- Send Button (Icon Only) - Inside textarea area -->\n <button\n class=\"send-button-icon\"\n [disabled]=\"!canSend\"\n (click)=\"onSendClick()\"\n title=\"Send message (Enter)\"\n >\n <i class=\"fa-solid fa-paper-plane\"></i>\n </button>\n </div>\n\n <!-- Mention Dropdown -->\n <mj-mention-dropdown\n *ngIf=\"showMentionDropdown && enableMentions\"\n [suggestions]=\"mentionSuggestions\"\n [position]=\"mentionDropdownPosition\"\n [showAbove]=\"mentionDropdownShowAbove\"\n [useFixedPositioning]=\"true\"\n [visible]=\"true\"\n (suggestionSelected)=\"onMentionSelected($event)\"\n (closed)=\"closeMentionDropdown()\">\n </mj-mention-dropdown>\n</div>\n", styles: [".message-input-box-container {\n display: flex;\n flex-direction: column;\n background: white;\n border: 2px solid var(--border-color, #e0e0e0);\n border-radius: 12px;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);\n transition: all 0.2s ease;\n overflow: visible; // Allow mention dropdown to escape container\n position: relative;\n\n &:focus-within {\n border-color: var(--primary-color, #007bff);\n box-shadow: 0 4px 16px rgba(0, 123, 255, 0.15);\n }\n}\n\n.input-wrapper {\n position: relative;\n display: flex;\n align-items: flex-end; // Align send button to bottom\n}\n\n.message-input-box-textarea {\n flex: 1;\n min-height: 100px;\n padding: 1rem;\n padding-right: 3.5rem; // Space for send button\n border: 0 !important;\n outline: 0 !important;\n box-shadow: none !important;\n -webkit-appearance: none !important;\n -moz-appearance: none !important;\n appearance: none !important;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n resize: vertical;\n background: transparent;\n\n &::placeholder {\n color: var(--text-tertiary, #999);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--background-disabled, #f5f5f5);\n }\n\n &:focus,\n &:active,\n &:focus-visible {\n
|
|
233
|
+
args: [{ selector: 'mj-message-input-box', template: "<div class=\"message-input-box-container\">\n <div class=\"input-wrapper\">\n <textarea\n #messageTextarea\n class=\"message-input-box-textarea\"\n [(ngModel)]=\"value\"\n [disabled]=\"disabled\"\n [placeholder]=\"placeholder\"\n [rows]=\"rows\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n ></textarea>\n\n <!-- Send Button (Icon Only) - Inside textarea area -->\n <button\n class=\"send-button-icon\"\n [disabled]=\"!canSend\"\n (click)=\"onSendClick()\"\n title=\"Send message (Enter)\"\n >\n <i class=\"fa-solid fa-paper-plane\"></i>\n </button>\n </div>\n\n <!-- Mention Dropdown -->\n <mj-mention-dropdown\n *ngIf=\"showMentionDropdown && enableMentions\"\n [suggestions]=\"mentionSuggestions\"\n [position]=\"mentionDropdownPosition\"\n [showAbove]=\"mentionDropdownShowAbove\"\n [useFixedPositioning]=\"true\"\n [visible]=\"true\"\n (suggestionSelected)=\"onMentionSelected($event)\"\n (closed)=\"closeMentionDropdown()\">\n </mj-mention-dropdown>\n</div>\n", styles: [".message-input-box-container {\n display: flex;\n flex-direction: column;\n background: white;\n border: 2px solid var(--border-color, #e0e0e0);\n border-radius: 12px;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);\n transition: all 0.2s ease;\n overflow: visible; // Allow mention dropdown to escape container\n position: relative;\n\n &:focus-within {\n border-color: var(--primary-color, #007bff);\n box-shadow: 0 4px 16px rgba(0, 123, 255, 0.15);\n }\n}\n\n.input-wrapper {\n position: relative;\n display: flex;\n align-items: flex-end; // Align send button to bottom\n}\n\n.message-input-box-textarea {\n flex: 1;\n min-height: 100px;\n padding: 1rem;\n padding-right: 3.5rem; // Space for send button\n border: 0 !important;\n outline: 0 !important;\n box-shadow: none !important;\n -webkit-appearance: none !important;\n -moz-appearance: none !important;\n appearance: none !important;\n font-family: inherit;\n font-size: 1rem;\n line-height: 1.5;\n resize: vertical;\n background: transparent;\n border: 0 !important;\n\n &::placeholder {\n color: var(--text-tertiary, #999);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n background: var(--background-disabled, #f5f5f5);\n }\n\n &:focus,\n &:active,\n &:focus-visible {\n outline: 0 !important;\n box-shadow: none !important;\n }\n}\n\n.send-button-icon {\n position: absolute;\n bottom: 0.75rem;\n right: 0.75rem;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--primary-color, #007bff);\n color: white;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n\n i {\n font-size: 1rem;\n }\n\n &:hover:not(:disabled) {\n background: var(--primary-color-dark, #0056b3);\n transform: scale(1.05);\n }\n\n &:active:not(:disabled) {\n transform: scale(0.95);\n }\n\n &:disabled {\n background: var(--background-disabled, #d0d0d0);\n color: var(--text-disabled, #999);\n cursor: not-allowed;\n opacity: 0.5;\n }\n}\n"] }]
|
|
244
234
|
}], () => [{ type: i1.MentionAutocompleteService }], { placeholder: [{
|
|
245
235
|
type: Input
|
|
246
236
|
}], disabled: [{
|