@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.
Files changed (106) hide show
  1. package/dist/lib/components/collection/artifact-create-modal.component.js +1 -1
  2. package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
  3. package/dist/lib/components/collection/collection-artifact-card.component.d.ts +8 -7
  4. package/dist/lib/components/collection/collection-artifact-card.component.d.ts.map +1 -1
  5. package/dist/lib/components/collection/collection-artifact-card.component.js +52 -36
  6. package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -1
  7. package/dist/lib/components/collection/collection-view.component.d.ts +28 -9
  8. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  9. package/dist/lib/components/collection/collection-view.component.js +124 -58
  10. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  11. package/dist/lib/components/collection/collections-full-view.component.d.ts +18 -6
  12. package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
  13. package/dist/lib/components/collection/collections-full-view.component.js +82 -58
  14. package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
  15. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +37 -0
  16. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  17. package/dist/lib/components/conversation/conversation-chat-area.component.js +278 -162
  18. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  19. package/dist/lib/components/conversation/conversation-list.component.d.ts +10 -3
  20. package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
  21. package/dist/lib/components/conversation/conversation-list.component.js +118 -77
  22. package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
  23. package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts +25 -0
  24. package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts.map +1 -0
  25. package/dist/lib/components/global-tasks/global-tasks-panel.component.js +206 -0
  26. package/dist/lib/components/global-tasks/global-tasks-panel.component.js.map +1 -0
  27. package/dist/lib/components/message/conversation-message-rating.component.d.ts +47 -0
  28. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -0
  29. package/dist/lib/components/message/conversation-message-rating.component.js +224 -0
  30. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -0
  31. package/dist/lib/components/message/message-input-box.component.d.ts.map +1 -1
  32. package/dist/lib/components/message/message-input-box.component.js +2 -12
  33. package/dist/lib/components/message/message-input-box.component.js.map +1 -1
  34. package/dist/lib/components/message/message-input.component.d.ts +17 -2
  35. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  36. package/dist/lib/components/message/message-input.component.js +258 -275
  37. package/dist/lib/components/message/message-input.component.js.map +1 -1
  38. package/dist/lib/components/message/message-item.component.d.ts +31 -1
  39. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  40. package/dist/lib/components/message/message-item.component.js +232 -116
  41. package/dist/lib/components/message/message-item.component.js.map +1 -1
  42. package/dist/lib/components/message/message-list.component.d.ts +3 -1
  43. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  44. package/dist/lib/components/message/message-list.component.js +11 -2
  45. package/dist/lib/components/message/message-list.component.js.map +1 -1
  46. package/dist/lib/components/navigation/conversation-navigation.component.d.ts +7 -1
  47. package/dist/lib/components/navigation/conversation-navigation.component.d.ts.map +1 -1
  48. package/dist/lib/components/navigation/conversation-navigation.component.js +24 -14
  49. package/dist/lib/components/navigation/conversation-navigation.component.js.map +1 -1
  50. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +17 -28
  51. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
  52. package/dist/lib/components/tasks/tasks-dropdown.component.js +175 -217
  53. package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
  54. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +14 -8
  55. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  56. package/dist/lib/components/workspace/conversation-workspace.component.js +103 -64
  57. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  58. package/dist/lib/conversations.module.d.ts +54 -52
  59. package/dist/lib/conversations.module.d.ts.map +1 -1
  60. package/dist/lib/conversations.module.js +11 -3
  61. package/dist/lib/conversations.module.js.map +1 -1
  62. package/dist/lib/models/conversation-complete-query.model.d.ts +31 -22
  63. package/dist/lib/models/conversation-complete-query.model.d.ts.map +1 -1
  64. package/dist/lib/models/conversation-complete-query.model.js +5 -2
  65. package/dist/lib/models/conversation-complete-query.model.js.map +1 -1
  66. package/dist/lib/models/lazy-artifact-info.d.ts +3 -0
  67. package/dist/lib/models/lazy-artifact-info.d.ts.map +1 -1
  68. package/dist/lib/models/lazy-artifact-info.js +7 -2
  69. package/dist/lib/models/lazy-artifact-info.js.map +1 -1
  70. package/dist/lib/services/active-tasks.service.d.ts +18 -0
  71. package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
  72. package/dist/lib/services/active-tasks.service.js +53 -3
  73. package/dist/lib/services/active-tasks.service.js.map +1 -1
  74. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  75. package/dist/lib/services/agent-state.service.js +5 -5
  76. package/dist/lib/services/agent-state.service.js.map +1 -1
  77. package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
  78. package/dist/lib/services/artifact-permission.service.js +3 -1
  79. package/dist/lib/services/artifact-permission.service.js.map +1 -1
  80. package/dist/lib/services/artifact-state.service.d.ts +22 -5
  81. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  82. package/dist/lib/services/artifact-state.service.js +118 -30
  83. package/dist/lib/services/artifact-state.service.js.map +1 -1
  84. package/dist/lib/services/artifact-use-tracking.service.d.ts +35 -0
  85. package/dist/lib/services/artifact-use-tracking.service.d.ts.map +1 -0
  86. package/dist/lib/services/artifact-use-tracking.service.js +76 -0
  87. package/dist/lib/services/artifact-use-tracking.service.js.map +1 -0
  88. package/dist/lib/services/conversation-agent.service.d.ts +30 -3
  89. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  90. package/dist/lib/services/conversation-agent.service.js +101 -12
  91. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  92. package/dist/lib/services/conversation-state.service.d.ts +13 -0
  93. package/dist/lib/services/conversation-state.service.d.ts.map +1 -1
  94. package/dist/lib/services/conversation-state.service.js +26 -0
  95. package/dist/lib/services/conversation-state.service.js.map +1 -1
  96. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  97. package/dist/lib/services/mention-autocomplete.service.js +1 -1
  98. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  99. package/dist/lib/services/search.service.d.ts.map +1 -1
  100. package/dist/lib/services/search.service.js +3 -1
  101. package/dist/lib/services/search.service.js.map +1 -1
  102. package/dist/public-api.d.ts +3 -0
  103. package/dist/public-api.d.ts.map +1 -1
  104. package/dist/public-api.js +3 -0
  105. package/dist/public-api.js.map +1 -1
  106. 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;IASd,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;IAa3B,WAAW,IAAI,IAAI;IAWnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA+C1B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA+B/B;;OAEG;IACH,iBAAiB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAsBtD;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAO5B;;OAEG;IACI,KAAK,IAAI,IAAI;yCApNT,wBAAwB;2CAAxB,wBAAwB;CAuNpC"}
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 border: 0 !important;\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}"] });
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 border: 0 !important;\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"] }]
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: [{