@aakash58/chatbot 1.1.14 → 1.1.16

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.
@@ -164,11 +164,12 @@ const DOOHBOT_ADVANCED_CONFIG = new InjectionToken('DOOHBOT_ADVANCED_CONFIG', {
164
164
  class DoohbotInput {
165
165
  username = '';
166
166
  password = '';
167
+ rememberMe = false;
167
168
  authToken;
168
169
  license = '';
169
170
  licenseCode = '';
170
171
  licenseKey = '';
171
- filePath = '';
172
+ licenseFilePath = '';
172
173
  apiBaseUrl = '';
173
174
  apiSegment = '';
174
175
  tenancyName = '';
@@ -209,8 +210,11 @@ class CoreConfigService {
209
210
  get licenseKey() {
210
211
  return this.configSignal().licenseKey || '';
211
212
  }
212
- get filePath() {
213
- return this.configSignal().filePath || './assets/const/doohclick_license.json';
213
+ get licenseFilePath() {
214
+ return this.configSignal().licenseFilePath || '';
215
+ }
216
+ get rememberMe() {
217
+ return this.configSignal().rememberMe !== undefined ? this.configSignal().rememberMe : false;
214
218
  }
215
219
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: CoreConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
216
220
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: CoreConfigService, providedIn: 'root' });
@@ -617,7 +621,7 @@ class AuthService {
617
621
  }
618
622
  // If still no token, exit gracefully
619
623
  if (!credentials.accessToken) {
620
- Logger.log('[Auth] No federated token found in storage. Exiting silently.');
624
+ Logger.log('[Auth] No federated token found in storage.');
621
625
  return false;
622
626
  }
623
627
  this.isLoggingIn.set(true);
@@ -1434,6 +1438,7 @@ class MessageListComponent {
1434
1438
  userAvatarUrl = '';
1435
1439
  userName = '';
1436
1440
  isAuthenticated = false;
1441
+ isLoggingIn = false;
1437
1442
  trackByMessageId = (index, item) => item.id ?? index;
1438
1443
  suggestionClick = new EventEmitter();
1439
1444
  loginClick = new EventEmitter();
@@ -1489,11 +1494,11 @@ class MessageListComponent {
1489
1494
  }
1490
1495
  }
1491
1496
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MessageListComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1492
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: MessageListComponent, isStandalone: true, selector: "app-message-list", inputs: { messages: "messages", isBotTyping: "isBotTyping", isStreaming: "isStreaming", appLogoUrl: "appLogoUrl", appSubtitle: "appSubtitle", welcomeDesc: "welcomeDesc", predefinedMessages: "predefinedMessages", botAvatarUrl: "botAvatarUrl", userAvatarUrl: "userAvatarUrl", userName: "userName", isAuthenticated: "isAuthenticated", trackByMessageId: "trackByMessageId" }, outputs: { suggestionClick: "suggestionClick", loginClick: "loginClick" }, viewQueries: [{ propertyName: "chatMessagesContainer", first: true, predicate: ["chatMessages"], descendants: true }], ngImport: i0, template: "<div #chatMessages class=\"chat-messages\">\r\n <!-- Welcome Screen -->\r\n @if (messages.length === 0 && !isBotTyping) {\r\n <div class=\"welcome-screen\">\r\n <img [src]=\"appLogoUrl\" alt=\"Welcome\" class=\"welcome-image\" style=\"border-radius: 0px\" />\r\n\r\n <!-- Only show greeting if authenticated -->\r\n @if (userName && isAuthenticated) {\r\n <div class=\"marquee-container\">\r\n <h2 class=\"welcome-greeting marquee-text\">\r\n Hi, {{ userName }}!\r\n <span class=\"emoji\">{{ appEmoji.waveHand }}</span>\r\n </h2>\r\n </div>\r\n }\r\n\r\n <h3>{{ appSubtitle }}</h3>\r\n <p>{{ welcomeDesc }}</p>\r\n\r\n <!-- Predefined messages chips: Only show when authenticated -->\r\n @if (isAuthenticated) {\r\n <app-chips [messages]=\"predefinedMessages\" [disabled]=\"isBotTyping\"\r\n (chipClick)=\"onPredefinedClick($event)\"></app-chips>\r\n }\r\n\r\n @if (!isAuthenticated) {\r\n <div class=\"auth-buttons-container\" style=\"margin-top: 20px\">\r\n <button (click)=\"loginClick.emit()\" class=\"auth-btn primary\">Login</button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chat Messages -->\r\n <div *ngFor=\"let message of messages; trackBy: trackByMessageId\" class=\"message\"\r\n [class.user]=\"message.sender === 'user'\" [class.assistant]=\"message.sender === 'assistant'\"\r\n [class.streaming]=\"!message.completed && message.sender === 'assistant'\">\r\n <!-- Avatar (Assistant on Left) -->\r\n @if (message.sender === 'assistant') {\r\n <div class=\"avatar-container\">\r\n <img class=\"assistant-avatar\" [src]=\"botAvatarUrl\" alt=\"Bot Avatar\" />\r\n </div>\r\n }\r\n\r\n <!-- Message Bubble -->\r\n <div class=\"message-content\">\r\n <!-- User chat bubble -->\r\n @if (message.sender === 'user') {\r\n <div class=\"user\">\r\n <span>{{ message.text }}</span>\r\n <button class=\"copy-btn\" (click)=\"copyMessage(message)\" title=\"Copy message\">\r\n <mat-icon>{{ message.copied ? 'check' : 'content_copy' }}</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n\r\n <!-- Assistant chat bubble -->\r\n @if (message.sender === 'assistant') {\r\n <div class=\"assistant\">\r\n @if (isStreaming && !message.isHistory) {\r\n <!-- Show text/chunks if they exist -->\r\n @if (message.chunks && message.chunks.length > 0) {\r\n @for (chunk of message.chunks; track $index; let i = $index) {\r\n <span class=\"markdown-content\" [attr.data-index]=\"i\" [innerHTML]=\"chunk | Markdown\">\r\n </span>\r\n }\r\n } @else if (!message.completed) {\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n }\r\n } @else {\r\n <!-- Non-streaming or history -->\r\n @if (message.text) {\r\n <span class=\"markdown-content\" [innerHTML]=\"message.text | Markdown\"></span>\r\n } @else if (!message.completed) {\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n }\r\n }\r\n @if (message.completed) {\r\n <button class=\"copy-btn\" (click)=\"copyMessage(message)\" title=\"Copy message\">\r\n <mat-icon>{{ message.copied ? 'check' : 'content_copy' }}</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Show time below message -->\r\n @if (message.sender === 'assistant' && message.completed) {\r\n <div class=\"message-time\">\r\n {{ message.timestamp | date: 'shortTime' }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Avatar (User on Right) -->\r\n @if (message.sender === 'user') {\r\n <div class=\"avatar-container\">\r\n <img class=\"user-avatar\" [src]=\"userAvatarUrl\" alt=\"User Avatar\" />\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Standalone Typing Indicator (Fallback if no message added yet) -->\r\n @if (isBotTyping && messages[messages.length - 1]?.sender !== 'assistant') {\r\n <div class=\"message assistant\">\r\n <div class=\"avatar-container\">\r\n <img class=\"assistant-avatar\" [src]=\"botAvatarUrl\" alt=\"Bot Avatar\" />\r\n </div>\r\n <div class=\"message-content\">\r\n <div class=\"assistant\">\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n</div>", styles: [":host{display:flex;flex-direction:column;flex-grow:1;overflow:hidden}.login-btn{padding:10px 15px;border:none;border-radius:20px;background-color:var(--primary-color);color:var(--user-text-color);font-size:1em;cursor:pointer;transition:background-color .2s ease}.chat-messages{flex-grow:1;padding:20px;overflow-y:auto;display:flex;flex-direction:column;gap:10px;scroll-behavior:smooth}.chat-messages::-webkit-scrollbar{width:6px}.chat-messages::-webkit-scrollbar-track{background:transparent}.chat-messages::-webkit-scrollbar-thumb{background:rgba(var(--black-rgb),.1);border-radius:10px}.chat-messages::-webkit-scrollbar-thumb:hover{background:rgba(var(--black-rgb),.1)}.chat-messages .message{display:flex;align-items:flex-end;gap:8px;margin-bottom:6px}.chat-messages .message.user{justify-content:flex-end}.chat-messages .message.assistant{justify-content:flex-start}.chat-messages .message .avatar-container{display:flex;flex-direction:column;align-items:center;gap:4px}.chat-messages .message .avatar-container .user-avatar{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1px solid var(--border-color)}.chat-messages .message .avatar-container .assistant-avatar{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1px solid var(--border-color);filter:var(--avatar-filter)}.chat-messages .message .avatar-container .user-avatar.placeholder{filter:var(--avatar-filter)}.chat-messages .message .avatar-container .user-name{font-size:10px;color:var(--secondary-text-color);font-family:var(--font-family);text-align:center;max-width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-messages .message .message-content{max-width:80%;word-wrap:break-word;white-space:pre-wrap;font-family:var(--font-family);-webkit-user-select:text;user-select:text;cursor:text}.chat-messages .message .message-content .user{background-color:var(--primary-color);color:var(--user-text-color);align-self:flex-end;border-radius:20px;padding:10px 15px;position:relative;-webkit-user-select:text;user-select:text;cursor:text}.chat-messages .message .message-content .user .copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity .2s ease;background:var(--background-color);border:none;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;pointer-events:auto}.chat-messages .message .message-content .user .copy-btn mat-icon{font-size:16px;width:16px;height:16px;color:var(--bot-text-color)}.chat-messages .message .message-content .user .copy-btn:hover{background:var(--background-color)}.chat-messages .message .message-content .user:hover .copy-btn{opacity:1}.chat-messages .message .message-content .assistant{background-color:var(--bot-message-color);color:var(--bot-text-color);align-self:flex-start;border-radius:20px;padding:10px 15px;position:relative;-webkit-user-select:text;user-select:text;cursor:text;animation:fadeIn .4s ease-out forwards}.chat-messages .message .message-content .assistant .copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity .2s ease;background:var(--background-color);border:none;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;pointer-events:auto}.chat-messages .message .message-content .assistant .copy-btn mat-icon{font-size:16px;width:16px;height:16px;color:var(--bot-text-color)}.chat-messages .message .message-content .assistant .copy-btn:hover{background:var(--background-color)}.chat-messages .message .message-content .assistant:hover .copy-btn{opacity:1}.chat-messages .message .message-content .assistant .markdown-content h1,.chat-messages .message .message-content .assistant .markdown-content h2,.chat-messages .message .message-content .assistant .markdown-content h3{margin-top:10px;margin-bottom:5px;font-weight:600;line-height:1.25}.chat-messages .message .message-content .assistant .markdown-content h1{font-size:1.25em}.chat-messages .message .message-content .assistant .markdown-content h2{font-size:1.1em}.chat-messages .message .message-content .assistant .markdown-content h3{font-size:1em}.chat-messages .message .message-content .assistant .markdown-content p{margin-bottom:8px;line-height:1.5}.chat-messages .message .message-content .assistant .markdown-content ul,.chat-messages .message .message-content .assistant .markdown-content ol{margin-top:0;margin-bottom:8px;padding-left:20px}.chat-messages .message .message-content .assistant .markdown-content li{margin-bottom:4px;line-height:1.5}.chat-messages .message .message-content .assistant .markdown-content strong{font-weight:700}.chat-messages .message .message-content .assistant .markdown-content em{font-style:italic}.chat-messages .message .message-content .message-time{font-size:12px;color:var(--secondary-text-color);text-align:end;margin-top:6px;line-height:1;-webkit-user-select:none;user-select:none;cursor:default}.chat-messages .message .message-content ::selection{background-color:color-mix(in srgb,var(--primary-color),white 60%)}.chat-messages .message .message-content ::-moz-selection{background-color:color-mix(in srgb,var(--primary-color),white 60%)}.welcome-screen{display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;height:100%;padding:0 20px}.welcome-image{width:80px;margin-bottom:30px}.marquee-container{margin-bottom:12px}.welcome-greeting{margin:0;color:var(--text-color);font-family:var(--font-family);font-size:24px;font-weight:600;background:var(--text-color);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;display:inline-block}.welcome-greeting .emoji{background:none;-webkit-background-clip:initial;-webkit-text-fill-color:initial;background-clip:initial}.welcome-screen h3{margin:0 0 5px;color:var(--text-color);font-family:var(--font-family);font-size:18px}.welcome-screen p{margin:0 0 30px;color:var(--secondary-text-color);font-size:14px;font-family:var(--font-family)}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.message-wrapper.streaming .assistant-avatar{box-shadow:0 0 8px rgba(var(--black-rgb),.1);transition:all .3s ease}.typing-indicator{display:flex;align-items:center;justify-content:flex-start;gap:4px;min-height:20px}.typing-indicator span{width:8px;height:8px;background-color:var(--typing-indicator-color);border-radius:50%;animation:blink 1.4s infinite both}.typing-indicator span:nth-child(2){animation-delay:.2s}.typing-indicator span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.2}40%{opacity:1}}.auth-buttons-container{display:flex;flex-direction:row;justify-content:center;gap:10px}.auth-btn{padding:8px 16px;border-radius:20px;font-size:.9em;font-weight:500;cursor:pointer;transition:all .2s ease}.auth-btn.primary{background:var(--primary-color);color:var(--white);border:1px solid var(--primary-color)}.auth-btn.primary:hover{opacity:.9}.auth-btn.primary:disabled{opacity:.5;cursor:not-allowed}.auth-btn.secondary{background:transparent;color:var(--primary-color);border:1px solid var(--primary-color)}.auth-btn.secondary:hover{opacity:.9}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: Chips, selector: "app-chips", inputs: ["messages", "disabled"], outputs: ["chipClick"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: i1$2.DatePipe, name: "date" }, { kind: "pipe", type: MarkdownPipe, name: "Markdown" }] });
1497
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: MessageListComponent, isStandalone: true, selector: "app-message-list", inputs: { messages: "messages", isBotTyping: "isBotTyping", isStreaming: "isStreaming", appLogoUrl: "appLogoUrl", appSubtitle: "appSubtitle", welcomeDesc: "welcomeDesc", predefinedMessages: "predefinedMessages", botAvatarUrl: "botAvatarUrl", userAvatarUrl: "userAvatarUrl", userName: "userName", isAuthenticated: "isAuthenticated", isLoggingIn: "isLoggingIn", trackByMessageId: "trackByMessageId" }, outputs: { suggestionClick: "suggestionClick", loginClick: "loginClick" }, viewQueries: [{ propertyName: "chatMessagesContainer", first: true, predicate: ["chatMessages"], descendants: true }], ngImport: i0, template: "<div #chatMessages class=\"chat-messages\">\r\n <!-- Welcome Screen -->\r\n @if (messages.length === 0 && !isBotTyping) {\r\n <div class=\"welcome-screen\">\r\n <img [src]=\"appLogoUrl\" alt=\"Welcome\" class=\"welcome-image\" style=\"border-radius: 0px\" />\r\n\r\n <!-- Only show greeting if authenticated -->\r\n @if (userName && isAuthenticated) {\r\n <div class=\"marquee-container\">\r\n <h2 class=\"welcome-greeting marquee-text\">\r\n Hi, {{ userName }}!\r\n <span class=\"emoji\">{{ appEmoji.waveHand }}</span>\r\n </h2>\r\n </div>\r\n }\r\n\r\n <h3>{{ appSubtitle }}</h3>\r\n <p>{{ welcomeDesc }}</p>\r\n\r\n <!-- Predefined messages chips: Only show when authenticated -->\r\n @if (isAuthenticated) {\r\n <app-chips\r\n [messages]=\"predefinedMessages\"\r\n [disabled]=\"isBotTyping\"\r\n (chipClick)=\"onPredefinedClick($event)\"\r\n ></app-chips>\r\n }\r\n\r\n @if (!isAuthenticated) {\r\n <div class=\"auth-buttons-container\" style=\"margin-top: 20px\">\r\n <button (click)=\"loginClick.emit()\" class=\"auth-btn primary\" [disabled]=\"isLoggingIn\">\r\n {{ isLoggingIn ? 'Logging in...' : 'Login' }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chat Messages -->\r\n <div\r\n *ngFor=\"let message of messages; trackBy: trackByMessageId\"\r\n class=\"message\"\r\n [class.user]=\"message.sender === 'user'\"\r\n [class.assistant]=\"message.sender === 'assistant'\"\r\n [class.streaming]=\"!message.completed && message.sender === 'assistant'\"\r\n >\r\n <!-- Avatar (Assistant on Left) -->\r\n @if (message.sender === 'assistant') {\r\n <div class=\"avatar-container\">\r\n <img class=\"assistant-avatar\" [src]=\"botAvatarUrl\" alt=\"Bot Avatar\" />\r\n </div>\r\n }\r\n\r\n <!-- Message Bubble -->\r\n <div class=\"message-content\">\r\n <!-- User chat bubble -->\r\n @if (message.sender === 'user') {\r\n <div class=\"user\">\r\n <span>{{ message.text }}</span>\r\n <button class=\"copy-btn\" (click)=\"copyMessage(message)\" title=\"Copy message\">\r\n <mat-icon>{{ message.copied ? 'check' : 'content_copy' }}</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n\r\n <!-- Assistant chat bubble -->\r\n @if (message.sender === 'assistant') {\r\n <div class=\"assistant\">\r\n @if (isStreaming && !message.isHistory) {\r\n <!-- Show text/chunks if they exist -->\r\n @if (message.chunks && message.chunks.length > 0) {\r\n @for (chunk of message.chunks; track $index; let i = $index) {\r\n <span class=\"markdown-content\" [attr.data-index]=\"i\" [innerHTML]=\"chunk | Markdown\">\r\n </span>\r\n }\r\n } @else if (!message.completed) {\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n }\r\n } @else {\r\n <!-- Non-streaming or history -->\r\n @if (message.text) {\r\n <span class=\"markdown-content\" [innerHTML]=\"message.text | Markdown\"></span>\r\n } @else if (!message.completed) {\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n }\r\n }\r\n @if (message.completed) {\r\n <button class=\"copy-btn\" (click)=\"copyMessage(message)\" title=\"Copy message\">\r\n <mat-icon>{{ message.copied ? 'check' : 'content_copy' }}</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Show time below message -->\r\n @if (message.sender === 'assistant' && message.completed) {\r\n <div class=\"message-time\">\r\n {{ message.timestamp | date: 'shortTime' }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Avatar (User on Right) -->\r\n @if (message.sender === 'user') {\r\n <div class=\"avatar-container\">\r\n <img class=\"user-avatar\" [src]=\"userAvatarUrl\" alt=\"User Avatar\" />\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Standalone Typing Indicator (Fallback if no message added yet) -->\r\n @if (isBotTyping && messages[messages.length - 1]?.sender !== 'assistant') {\r\n <div class=\"message assistant\">\r\n <div class=\"avatar-container\">\r\n <img class=\"assistant-avatar\" [src]=\"botAvatarUrl\" alt=\"Bot Avatar\" />\r\n </div>\r\n <div class=\"message-content\">\r\n <div class=\"assistant\">\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;flex-grow:1;overflow:hidden}.login-btn{padding:10px 15px;border:none;border-radius:20px;background-color:var(--primary-color);color:var(--user-text-color);font-size:1em;cursor:pointer;transition:background-color .2s ease}.chat-messages{flex-grow:1;padding:20px;overflow-y:auto;display:flex;flex-direction:column;gap:10px;scroll-behavior:smooth}.chat-messages::-webkit-scrollbar{width:6px}.chat-messages::-webkit-scrollbar-track{background:transparent}.chat-messages::-webkit-scrollbar-thumb{background:rgba(var(--black-rgb),.1);border-radius:10px}.chat-messages::-webkit-scrollbar-thumb:hover{background:rgba(var(--black-rgb),.1)}.chat-messages .message{display:flex;align-items:flex-end;gap:8px;margin-bottom:6px}.chat-messages .message.user{justify-content:flex-end}.chat-messages .message.assistant{justify-content:flex-start}.chat-messages .message .avatar-container{display:flex;flex-direction:column;align-items:center;gap:4px}.chat-messages .message .avatar-container .user-avatar{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1px solid var(--border-color)}.chat-messages .message .avatar-container .assistant-avatar{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1px solid var(--border-color);filter:var(--avatar-filter)}.chat-messages .message .avatar-container .user-avatar.placeholder{filter:var(--avatar-filter)}.chat-messages .message .avatar-container .user-name{font-size:10px;color:var(--secondary-text-color);font-family:var(--font-family);text-align:center;max-width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-messages .message .message-content{max-width:80%;word-wrap:break-word;white-space:pre-wrap;font-family:var(--font-family);-webkit-user-select:text;user-select:text;cursor:text}.chat-messages .message .message-content .user{background-color:var(--primary-color);color:var(--user-text-color);align-self:flex-end;border-radius:20px;padding:10px 15px;position:relative;-webkit-user-select:text;user-select:text;cursor:text}.chat-messages .message .message-content .user .copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity .2s ease;background:var(--background-color);border:none;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;pointer-events:auto}.chat-messages .message .message-content .user .copy-btn mat-icon{font-size:16px;width:16px;height:16px;color:var(--bot-text-color)}.chat-messages .message .message-content .user .copy-btn:hover{background:var(--background-color)}.chat-messages .message .message-content .user:hover .copy-btn{opacity:1}.chat-messages .message .message-content .assistant{background-color:var(--bot-message-color);color:var(--bot-text-color);align-self:flex-start;border-radius:20px;padding:10px 15px;position:relative;-webkit-user-select:text;user-select:text;cursor:text;animation:fadeIn .4s ease-out forwards}.chat-messages .message .message-content .assistant .copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity .2s ease;background:var(--background-color);border:none;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;pointer-events:auto}.chat-messages .message .message-content .assistant .copy-btn mat-icon{font-size:16px;width:16px;height:16px;color:var(--bot-text-color)}.chat-messages .message .message-content .assistant .copy-btn:hover{background:var(--background-color)}.chat-messages .message .message-content .assistant:hover .copy-btn{opacity:1}.chat-messages .message .message-content .assistant .markdown-content h1,.chat-messages .message .message-content .assistant .markdown-content h2,.chat-messages .message .message-content .assistant .markdown-content h3{margin-top:10px;margin-bottom:5px;font-weight:600;line-height:1.25}.chat-messages .message .message-content .assistant .markdown-content h1{font-size:1.25em}.chat-messages .message .message-content .assistant .markdown-content h2{font-size:1.1em}.chat-messages .message .message-content .assistant .markdown-content h3{font-size:1em}.chat-messages .message .message-content .assistant .markdown-content p{margin-bottom:8px;line-height:1.5}.chat-messages .message .message-content .assistant .markdown-content ul,.chat-messages .message .message-content .assistant .markdown-content ol{margin-top:0;margin-bottom:8px;padding-left:20px}.chat-messages .message .message-content .assistant .markdown-content li{margin-bottom:4px;line-height:1.5}.chat-messages .message .message-content .assistant .markdown-content strong{font-weight:700}.chat-messages .message .message-content .assistant .markdown-content em{font-style:italic}.chat-messages .message .message-content .message-time{font-size:12px;color:var(--secondary-text-color);text-align:end;margin-top:6px;line-height:1;-webkit-user-select:none;user-select:none;cursor:default}.chat-messages .message .message-content ::selection{background-color:color-mix(in srgb,var(--primary-color),white 60%)}.chat-messages .message .message-content ::-moz-selection{background-color:color-mix(in srgb,var(--primary-color),white 60%)}.welcome-screen{display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;height:100%;padding:0 20px}.welcome-image{width:80px;margin-bottom:30px}.marquee-container{margin-bottom:12px}.welcome-greeting{margin:0;color:var(--text-color);font-family:var(--font-family);font-size:24px;font-weight:600;background:var(--text-color);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;display:inline-block}.welcome-greeting .emoji{background:none;-webkit-background-clip:initial;-webkit-text-fill-color:initial;background-clip:initial}.welcome-screen h3{margin:0 0 5px;color:var(--text-color);font-family:var(--font-family);font-size:18px}.welcome-screen p{margin:0 0 30px;color:var(--secondary-text-color);font-size:14px;font-family:var(--font-family)}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.message-wrapper.streaming .assistant-avatar{box-shadow:0 0 8px rgba(var(--black-rgb),.1);transition:all .3s ease}.typing-indicator{display:flex;align-items:center;justify-content:flex-start;gap:4px;min-height:20px}.typing-indicator span{width:8px;height:8px;background-color:var(--typing-indicator-color);border-radius:50%;animation:blink 1.4s infinite both}.typing-indicator span:nth-child(2){animation-delay:.2s}.typing-indicator span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.2}40%{opacity:1}}.auth-buttons-container{display:flex;flex-direction:row;justify-content:center;gap:10px}.auth-btn{padding:8px 16px;border-radius:20px;font-size:.9em;font-weight:500;cursor:pointer;transition:all .2s ease}.auth-btn.primary{background:var(--primary-color);color:var(--white);border:1px solid var(--primary-color)}.auth-btn.primary:hover{opacity:.9}.auth-btn.primary:disabled{opacity:.5;cursor:not-allowed}.auth-btn.secondary{background:transparent;color:var(--primary-color);border:1px solid var(--primary-color)}.auth-btn.secondary:hover{opacity:.9}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: Chips, selector: "app-chips", inputs: ["messages", "disabled"], outputs: ["chipClick"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: i1$2.DatePipe, name: "date" }, { kind: "pipe", type: MarkdownPipe, name: "Markdown" }] });
1493
1498
  }
1494
1499
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: MessageListComponent, decorators: [{
1495
1500
  type: Component,
1496
- args: [{ selector: 'app-message-list', standalone: true, imports: [CommonModule, Chips, MarkdownPipe, MatIconModule], template: "<div #chatMessages class=\"chat-messages\">\r\n <!-- Welcome Screen -->\r\n @if (messages.length === 0 && !isBotTyping) {\r\n <div class=\"welcome-screen\">\r\n <img [src]=\"appLogoUrl\" alt=\"Welcome\" class=\"welcome-image\" style=\"border-radius: 0px\" />\r\n\r\n <!-- Only show greeting if authenticated -->\r\n @if (userName && isAuthenticated) {\r\n <div class=\"marquee-container\">\r\n <h2 class=\"welcome-greeting marquee-text\">\r\n Hi, {{ userName }}!\r\n <span class=\"emoji\">{{ appEmoji.waveHand }}</span>\r\n </h2>\r\n </div>\r\n }\r\n\r\n <h3>{{ appSubtitle }}</h3>\r\n <p>{{ welcomeDesc }}</p>\r\n\r\n <!-- Predefined messages chips: Only show when authenticated -->\r\n @if (isAuthenticated) {\r\n <app-chips [messages]=\"predefinedMessages\" [disabled]=\"isBotTyping\"\r\n (chipClick)=\"onPredefinedClick($event)\"></app-chips>\r\n }\r\n\r\n @if (!isAuthenticated) {\r\n <div class=\"auth-buttons-container\" style=\"margin-top: 20px\">\r\n <button (click)=\"loginClick.emit()\" class=\"auth-btn primary\">Login</button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chat Messages -->\r\n <div *ngFor=\"let message of messages; trackBy: trackByMessageId\" class=\"message\"\r\n [class.user]=\"message.sender === 'user'\" [class.assistant]=\"message.sender === 'assistant'\"\r\n [class.streaming]=\"!message.completed && message.sender === 'assistant'\">\r\n <!-- Avatar (Assistant on Left) -->\r\n @if (message.sender === 'assistant') {\r\n <div class=\"avatar-container\">\r\n <img class=\"assistant-avatar\" [src]=\"botAvatarUrl\" alt=\"Bot Avatar\" />\r\n </div>\r\n }\r\n\r\n <!-- Message Bubble -->\r\n <div class=\"message-content\">\r\n <!-- User chat bubble -->\r\n @if (message.sender === 'user') {\r\n <div class=\"user\">\r\n <span>{{ message.text }}</span>\r\n <button class=\"copy-btn\" (click)=\"copyMessage(message)\" title=\"Copy message\">\r\n <mat-icon>{{ message.copied ? 'check' : 'content_copy' }}</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n\r\n <!-- Assistant chat bubble -->\r\n @if (message.sender === 'assistant') {\r\n <div class=\"assistant\">\r\n @if (isStreaming && !message.isHistory) {\r\n <!-- Show text/chunks if they exist -->\r\n @if (message.chunks && message.chunks.length > 0) {\r\n @for (chunk of message.chunks; track $index; let i = $index) {\r\n <span class=\"markdown-content\" [attr.data-index]=\"i\" [innerHTML]=\"chunk | Markdown\">\r\n </span>\r\n }\r\n } @else if (!message.completed) {\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n }\r\n } @else {\r\n <!-- Non-streaming or history -->\r\n @if (message.text) {\r\n <span class=\"markdown-content\" [innerHTML]=\"message.text | Markdown\"></span>\r\n } @else if (!message.completed) {\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n }\r\n }\r\n @if (message.completed) {\r\n <button class=\"copy-btn\" (click)=\"copyMessage(message)\" title=\"Copy message\">\r\n <mat-icon>{{ message.copied ? 'check' : 'content_copy' }}</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Show time below message -->\r\n @if (message.sender === 'assistant' && message.completed) {\r\n <div class=\"message-time\">\r\n {{ message.timestamp | date: 'shortTime' }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Avatar (User on Right) -->\r\n @if (message.sender === 'user') {\r\n <div class=\"avatar-container\">\r\n <img class=\"user-avatar\" [src]=\"userAvatarUrl\" alt=\"User Avatar\" />\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Standalone Typing Indicator (Fallback if no message added yet) -->\r\n @if (isBotTyping && messages[messages.length - 1]?.sender !== 'assistant') {\r\n <div class=\"message assistant\">\r\n <div class=\"avatar-container\">\r\n <img class=\"assistant-avatar\" [src]=\"botAvatarUrl\" alt=\"Bot Avatar\" />\r\n </div>\r\n <div class=\"message-content\">\r\n <div class=\"assistant\">\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n</div>", styles: [":host{display:flex;flex-direction:column;flex-grow:1;overflow:hidden}.login-btn{padding:10px 15px;border:none;border-radius:20px;background-color:var(--primary-color);color:var(--user-text-color);font-size:1em;cursor:pointer;transition:background-color .2s ease}.chat-messages{flex-grow:1;padding:20px;overflow-y:auto;display:flex;flex-direction:column;gap:10px;scroll-behavior:smooth}.chat-messages::-webkit-scrollbar{width:6px}.chat-messages::-webkit-scrollbar-track{background:transparent}.chat-messages::-webkit-scrollbar-thumb{background:rgba(var(--black-rgb),.1);border-radius:10px}.chat-messages::-webkit-scrollbar-thumb:hover{background:rgba(var(--black-rgb),.1)}.chat-messages .message{display:flex;align-items:flex-end;gap:8px;margin-bottom:6px}.chat-messages .message.user{justify-content:flex-end}.chat-messages .message.assistant{justify-content:flex-start}.chat-messages .message .avatar-container{display:flex;flex-direction:column;align-items:center;gap:4px}.chat-messages .message .avatar-container .user-avatar{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1px solid var(--border-color)}.chat-messages .message .avatar-container .assistant-avatar{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1px solid var(--border-color);filter:var(--avatar-filter)}.chat-messages .message .avatar-container .user-avatar.placeholder{filter:var(--avatar-filter)}.chat-messages .message .avatar-container .user-name{font-size:10px;color:var(--secondary-text-color);font-family:var(--font-family);text-align:center;max-width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-messages .message .message-content{max-width:80%;word-wrap:break-word;white-space:pre-wrap;font-family:var(--font-family);-webkit-user-select:text;user-select:text;cursor:text}.chat-messages .message .message-content .user{background-color:var(--primary-color);color:var(--user-text-color);align-self:flex-end;border-radius:20px;padding:10px 15px;position:relative;-webkit-user-select:text;user-select:text;cursor:text}.chat-messages .message .message-content .user .copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity .2s ease;background:var(--background-color);border:none;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;pointer-events:auto}.chat-messages .message .message-content .user .copy-btn mat-icon{font-size:16px;width:16px;height:16px;color:var(--bot-text-color)}.chat-messages .message .message-content .user .copy-btn:hover{background:var(--background-color)}.chat-messages .message .message-content .user:hover .copy-btn{opacity:1}.chat-messages .message .message-content .assistant{background-color:var(--bot-message-color);color:var(--bot-text-color);align-self:flex-start;border-radius:20px;padding:10px 15px;position:relative;-webkit-user-select:text;user-select:text;cursor:text;animation:fadeIn .4s ease-out forwards}.chat-messages .message .message-content .assistant .copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity .2s ease;background:var(--background-color);border:none;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;pointer-events:auto}.chat-messages .message .message-content .assistant .copy-btn mat-icon{font-size:16px;width:16px;height:16px;color:var(--bot-text-color)}.chat-messages .message .message-content .assistant .copy-btn:hover{background:var(--background-color)}.chat-messages .message .message-content .assistant:hover .copy-btn{opacity:1}.chat-messages .message .message-content .assistant .markdown-content h1,.chat-messages .message .message-content .assistant .markdown-content h2,.chat-messages .message .message-content .assistant .markdown-content h3{margin-top:10px;margin-bottom:5px;font-weight:600;line-height:1.25}.chat-messages .message .message-content .assistant .markdown-content h1{font-size:1.25em}.chat-messages .message .message-content .assistant .markdown-content h2{font-size:1.1em}.chat-messages .message .message-content .assistant .markdown-content h3{font-size:1em}.chat-messages .message .message-content .assistant .markdown-content p{margin-bottom:8px;line-height:1.5}.chat-messages .message .message-content .assistant .markdown-content ul,.chat-messages .message .message-content .assistant .markdown-content ol{margin-top:0;margin-bottom:8px;padding-left:20px}.chat-messages .message .message-content .assistant .markdown-content li{margin-bottom:4px;line-height:1.5}.chat-messages .message .message-content .assistant .markdown-content strong{font-weight:700}.chat-messages .message .message-content .assistant .markdown-content em{font-style:italic}.chat-messages .message .message-content .message-time{font-size:12px;color:var(--secondary-text-color);text-align:end;margin-top:6px;line-height:1;-webkit-user-select:none;user-select:none;cursor:default}.chat-messages .message .message-content ::selection{background-color:color-mix(in srgb,var(--primary-color),white 60%)}.chat-messages .message .message-content ::-moz-selection{background-color:color-mix(in srgb,var(--primary-color),white 60%)}.welcome-screen{display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;height:100%;padding:0 20px}.welcome-image{width:80px;margin-bottom:30px}.marquee-container{margin-bottom:12px}.welcome-greeting{margin:0;color:var(--text-color);font-family:var(--font-family);font-size:24px;font-weight:600;background:var(--text-color);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;display:inline-block}.welcome-greeting .emoji{background:none;-webkit-background-clip:initial;-webkit-text-fill-color:initial;background-clip:initial}.welcome-screen h3{margin:0 0 5px;color:var(--text-color);font-family:var(--font-family);font-size:18px}.welcome-screen p{margin:0 0 30px;color:var(--secondary-text-color);font-size:14px;font-family:var(--font-family)}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.message-wrapper.streaming .assistant-avatar{box-shadow:0 0 8px rgba(var(--black-rgb),.1);transition:all .3s ease}.typing-indicator{display:flex;align-items:center;justify-content:flex-start;gap:4px;min-height:20px}.typing-indicator span{width:8px;height:8px;background-color:var(--typing-indicator-color);border-radius:50%;animation:blink 1.4s infinite both}.typing-indicator span:nth-child(2){animation-delay:.2s}.typing-indicator span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.2}40%{opacity:1}}.auth-buttons-container{display:flex;flex-direction:row;justify-content:center;gap:10px}.auth-btn{padding:8px 16px;border-radius:20px;font-size:.9em;font-weight:500;cursor:pointer;transition:all .2s ease}.auth-btn.primary{background:var(--primary-color);color:var(--white);border:1px solid var(--primary-color)}.auth-btn.primary:hover{opacity:.9}.auth-btn.primary:disabled{opacity:.5;cursor:not-allowed}.auth-btn.secondary{background:transparent;color:var(--primary-color);border:1px solid var(--primary-color)}.auth-btn.secondary:hover{opacity:.9}\n"] }]
1501
+ args: [{ selector: 'app-message-list', standalone: true, imports: [CommonModule, Chips, MarkdownPipe, MatIconModule], template: "<div #chatMessages class=\"chat-messages\">\r\n <!-- Welcome Screen -->\r\n @if (messages.length === 0 && !isBotTyping) {\r\n <div class=\"welcome-screen\">\r\n <img [src]=\"appLogoUrl\" alt=\"Welcome\" class=\"welcome-image\" style=\"border-radius: 0px\" />\r\n\r\n <!-- Only show greeting if authenticated -->\r\n @if (userName && isAuthenticated) {\r\n <div class=\"marquee-container\">\r\n <h2 class=\"welcome-greeting marquee-text\">\r\n Hi, {{ userName }}!\r\n <span class=\"emoji\">{{ appEmoji.waveHand }}</span>\r\n </h2>\r\n </div>\r\n }\r\n\r\n <h3>{{ appSubtitle }}</h3>\r\n <p>{{ welcomeDesc }}</p>\r\n\r\n <!-- Predefined messages chips: Only show when authenticated -->\r\n @if (isAuthenticated) {\r\n <app-chips\r\n [messages]=\"predefinedMessages\"\r\n [disabled]=\"isBotTyping\"\r\n (chipClick)=\"onPredefinedClick($event)\"\r\n ></app-chips>\r\n }\r\n\r\n @if (!isAuthenticated) {\r\n <div class=\"auth-buttons-container\" style=\"margin-top: 20px\">\r\n <button (click)=\"loginClick.emit()\" class=\"auth-btn primary\" [disabled]=\"isLoggingIn\">\r\n {{ isLoggingIn ? 'Logging in...' : 'Login' }}\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Chat Messages -->\r\n <div\r\n *ngFor=\"let message of messages; trackBy: trackByMessageId\"\r\n class=\"message\"\r\n [class.user]=\"message.sender === 'user'\"\r\n [class.assistant]=\"message.sender === 'assistant'\"\r\n [class.streaming]=\"!message.completed && message.sender === 'assistant'\"\r\n >\r\n <!-- Avatar (Assistant on Left) -->\r\n @if (message.sender === 'assistant') {\r\n <div class=\"avatar-container\">\r\n <img class=\"assistant-avatar\" [src]=\"botAvatarUrl\" alt=\"Bot Avatar\" />\r\n </div>\r\n }\r\n\r\n <!-- Message Bubble -->\r\n <div class=\"message-content\">\r\n <!-- User chat bubble -->\r\n @if (message.sender === 'user') {\r\n <div class=\"user\">\r\n <span>{{ message.text }}</span>\r\n <button class=\"copy-btn\" (click)=\"copyMessage(message)\" title=\"Copy message\">\r\n <mat-icon>{{ message.copied ? 'check' : 'content_copy' }}</mat-icon>\r\n </button>\r\n </div>\r\n }\r\n\r\n <!-- Assistant chat bubble -->\r\n @if (message.sender === 'assistant') {\r\n <div class=\"assistant\">\r\n @if (isStreaming && !message.isHistory) {\r\n <!-- Show text/chunks if they exist -->\r\n @if (message.chunks && message.chunks.length > 0) {\r\n @for (chunk of message.chunks; track $index; let i = $index) {\r\n <span class=\"markdown-content\" [attr.data-index]=\"i\" [innerHTML]=\"chunk | Markdown\">\r\n </span>\r\n }\r\n } @else if (!message.completed) {\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n }\r\n } @else {\r\n <!-- Non-streaming or history -->\r\n @if (message.text) {\r\n <span class=\"markdown-content\" [innerHTML]=\"message.text | Markdown\"></span>\r\n } @else if (!message.completed) {\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n }\r\n }\r\n @if (message.completed) {\r\n <button class=\"copy-btn\" (click)=\"copyMessage(message)\" title=\"Copy message\">\r\n <mat-icon>{{ message.copied ? 'check' : 'content_copy' }}</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Show time below message -->\r\n @if (message.sender === 'assistant' && message.completed) {\r\n <div class=\"message-time\">\r\n {{ message.timestamp | date: 'shortTime' }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Avatar (User on Right) -->\r\n @if (message.sender === 'user') {\r\n <div class=\"avatar-container\">\r\n <img class=\"user-avatar\" [src]=\"userAvatarUrl\" alt=\"User Avatar\" />\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Standalone Typing Indicator (Fallback if no message added yet) -->\r\n @if (isBotTyping && messages[messages.length - 1]?.sender !== 'assistant') {\r\n <div class=\"message assistant\">\r\n <div class=\"avatar-container\">\r\n <img class=\"assistant-avatar\" [src]=\"botAvatarUrl\" alt=\"Bot Avatar\" />\r\n </div>\r\n <div class=\"message-content\">\r\n <div class=\"assistant\">\r\n <div class=\"typing-indicator\">\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;flex-grow:1;overflow:hidden}.login-btn{padding:10px 15px;border:none;border-radius:20px;background-color:var(--primary-color);color:var(--user-text-color);font-size:1em;cursor:pointer;transition:background-color .2s ease}.chat-messages{flex-grow:1;padding:20px;overflow-y:auto;display:flex;flex-direction:column;gap:10px;scroll-behavior:smooth}.chat-messages::-webkit-scrollbar{width:6px}.chat-messages::-webkit-scrollbar-track{background:transparent}.chat-messages::-webkit-scrollbar-thumb{background:rgba(var(--black-rgb),.1);border-radius:10px}.chat-messages::-webkit-scrollbar-thumb:hover{background:rgba(var(--black-rgb),.1)}.chat-messages .message{display:flex;align-items:flex-end;gap:8px;margin-bottom:6px}.chat-messages .message.user{justify-content:flex-end}.chat-messages .message.assistant{justify-content:flex-start}.chat-messages .message .avatar-container{display:flex;flex-direction:column;align-items:center;gap:4px}.chat-messages .message .avatar-container .user-avatar{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1px solid var(--border-color)}.chat-messages .message .avatar-container .assistant-avatar{width:24px;height:24px;border-radius:50%;object-fit:cover;border:1px solid var(--border-color);filter:var(--avatar-filter)}.chat-messages .message .avatar-container .user-avatar.placeholder{filter:var(--avatar-filter)}.chat-messages .message .avatar-container .user-name{font-size:10px;color:var(--secondary-text-color);font-family:var(--font-family);text-align:center;max-width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-messages .message .message-content{max-width:80%;word-wrap:break-word;white-space:pre-wrap;font-family:var(--font-family);-webkit-user-select:text;user-select:text;cursor:text}.chat-messages .message .message-content .user{background-color:var(--primary-color);color:var(--user-text-color);align-self:flex-end;border-radius:20px;padding:10px 15px;position:relative;-webkit-user-select:text;user-select:text;cursor:text}.chat-messages .message .message-content .user .copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity .2s ease;background:var(--background-color);border:none;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;pointer-events:auto}.chat-messages .message .message-content .user .copy-btn mat-icon{font-size:16px;width:16px;height:16px;color:var(--bot-text-color)}.chat-messages .message .message-content .user .copy-btn:hover{background:var(--background-color)}.chat-messages .message .message-content .user:hover .copy-btn{opacity:1}.chat-messages .message .message-content .assistant{background-color:var(--bot-message-color);color:var(--bot-text-color);align-self:flex-start;border-radius:20px;padding:10px 15px;position:relative;-webkit-user-select:text;user-select:text;cursor:text;animation:fadeIn .4s ease-out forwards}.chat-messages .message .message-content .assistant .copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity .2s ease;background:var(--background-color);border:none;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;pointer-events:auto}.chat-messages .message .message-content .assistant .copy-btn mat-icon{font-size:16px;width:16px;height:16px;color:var(--bot-text-color)}.chat-messages .message .message-content .assistant .copy-btn:hover{background:var(--background-color)}.chat-messages .message .message-content .assistant:hover .copy-btn{opacity:1}.chat-messages .message .message-content .assistant .markdown-content h1,.chat-messages .message .message-content .assistant .markdown-content h2,.chat-messages .message .message-content .assistant .markdown-content h3{margin-top:10px;margin-bottom:5px;font-weight:600;line-height:1.25}.chat-messages .message .message-content .assistant .markdown-content h1{font-size:1.25em}.chat-messages .message .message-content .assistant .markdown-content h2{font-size:1.1em}.chat-messages .message .message-content .assistant .markdown-content h3{font-size:1em}.chat-messages .message .message-content .assistant .markdown-content p{margin-bottom:8px;line-height:1.5}.chat-messages .message .message-content .assistant .markdown-content ul,.chat-messages .message .message-content .assistant .markdown-content ol{margin-top:0;margin-bottom:8px;padding-left:20px}.chat-messages .message .message-content .assistant .markdown-content li{margin-bottom:4px;line-height:1.5}.chat-messages .message .message-content .assistant .markdown-content strong{font-weight:700}.chat-messages .message .message-content .assistant .markdown-content em{font-style:italic}.chat-messages .message .message-content .message-time{font-size:12px;color:var(--secondary-text-color);text-align:end;margin-top:6px;line-height:1;-webkit-user-select:none;user-select:none;cursor:default}.chat-messages .message .message-content ::selection{background-color:color-mix(in srgb,var(--primary-color),white 60%)}.chat-messages .message .message-content ::-moz-selection{background-color:color-mix(in srgb,var(--primary-color),white 60%)}.welcome-screen{display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;height:100%;padding:0 20px}.welcome-image{width:80px;margin-bottom:30px}.marquee-container{margin-bottom:12px}.welcome-greeting{margin:0;color:var(--text-color);font-family:var(--font-family);font-size:24px;font-weight:600;background:var(--text-color);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;display:inline-block}.welcome-greeting .emoji{background:none;-webkit-background-clip:initial;-webkit-text-fill-color:initial;background-clip:initial}.welcome-screen h3{margin:0 0 5px;color:var(--text-color);font-family:var(--font-family);font-size:18px}.welcome-screen p{margin:0 0 30px;color:var(--secondary-text-color);font-size:14px;font-family:var(--font-family)}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.message-wrapper.streaming .assistant-avatar{box-shadow:0 0 8px rgba(var(--black-rgb),.1);transition:all .3s ease}.typing-indicator{display:flex;align-items:center;justify-content:flex-start;gap:4px;min-height:20px}.typing-indicator span{width:8px;height:8px;background-color:var(--typing-indicator-color);border-radius:50%;animation:blink 1.4s infinite both}.typing-indicator span:nth-child(2){animation-delay:.2s}.typing-indicator span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.2}40%{opacity:1}}.auth-buttons-container{display:flex;flex-direction:row;justify-content:center;gap:10px}.auth-btn{padding:8px 16px;border-radius:20px;font-size:.9em;font-weight:500;cursor:pointer;transition:all .2s ease}.auth-btn.primary{background:var(--primary-color);color:var(--white);border:1px solid var(--primary-color)}.auth-btn.primary:hover{opacity:.9}.auth-btn.primary:disabled{opacity:.5;cursor:not-allowed}.auth-btn.secondary{background:transparent;color:var(--primary-color);border:1px solid var(--primary-color)}.auth-btn.secondary:hover{opacity:.9}\n"] }]
1497
1502
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { messages: [{
1498
1503
  type: Input
1499
1504
  }], isBotTyping: [{
@@ -1516,6 +1521,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
1516
1521
  type: Input
1517
1522
  }], isAuthenticated: [{
1518
1523
  type: Input
1524
+ }], isLoggingIn: [{
1525
+ type: Input
1519
1526
  }], trackByMessageId: [{
1520
1527
  type: Input
1521
1528
  }], suggestionClick: [{
@@ -4009,14 +4016,20 @@ class ChatWindowComponent {
4009
4016
  if (this.isAuthenticated) {
4010
4017
  this.showLoginForm = false;
4011
4018
  }
4012
- else {
4019
+ }
4020
+ //? Handle logging in status changes
4021
+ if (changes['isLoggingIn']) {
4022
+ if (this.isLoggingIn) {
4023
+ this.showLoginForm = false;
4024
+ }
4025
+ else if (!this.isAuthenticated && !changes['isLoggingIn'].firstChange) {
4013
4026
  this.showLoginForm = true;
4014
4027
  }
4015
4028
  }
4016
4029
  }
4017
4030
  ngOnDestroy() { }
4018
4031
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ChatWindowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4019
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: ChatWindowComponent, isStandalone: true, selector: "app-chat-window", inputs: { isChatOpen: "isChatOpen", enableDrag: "enableDrag", enableResize: "enableResize", isFullScreen: "isFullScreen", isStreaming: "isStreaming", isAuthenticated: "isAuthenticated", appTitle: "appTitle", appLogoUrl: "appLogoUrl", appTextLogoUrl: "appTextLogoUrl", appHeaderLogoUrl: "appHeaderLogoUrl", messages: "messages", isBotTyping: "isBotTyping", appSubtitle: "appSubtitle", welcomeDesc: "welcomeDesc", predefinedMessages: "predefinedMessages", suggestedMessages: "suggestedMessages", botAvatarUrl: "botAvatarUrl", userAvatarUrl: "userAvatarUrl", userName: "userName", trackByMessageId: "trackByMessageId", hintText: "hintText", messageError: "messageError", showSuggestionChips: "showSuggestionChips", isHistorySidebarOpen: "isHistorySidebarOpen", chatSessions: "chatSessions", chatHistoryUserName: "chatHistoryUserName", isLoggingIn: "isLoggingIn", authError: "authError", authSuccess: "authSuccess", isLoadingSessions: "isLoadingSessions", hasMoreSessions: "hasMoreSessions", isLoadingMoreSessions: "isLoadingMoreSessions", processingSessionId: "processingSessionId", themeConfig: "themeConfig", buttonStyle: "buttonStyle" }, outputs: { toggleChat: "toggleChat", toggleFullScreen: "toggleFullScreen", toggleHistorySidebar: "toggleHistorySidebar", openSettings: "openSettings", suggestionClick: "suggestionClick", send: "send", stop: "stop", clearMessageError: "clearMessageError", clearChat: "clearChat", sessionSelected: "sessionSelected", sessionDeleted: "sessionDeleted", loadMoreSessions: "loadMoreSessions", refreshSessions: "refreshSessions", sessionRenamed: "sessionRenamed", deleteAllSessions: "deleteAllSessions", loginSubmit: "loginSubmit", logout: "logout" }, usesOnChanges: true, ngImport: i0, template: "@if (isChatOpen) {\r\n<div draggableDialog [enableDrag]=\"enableDrag && !buttonStyle.includes('sidebar')\" [dragHandle]=\"'.chat-header'\"\r\n resizableDialog [enableResize]=\"enableResize && !buttonStyle.includes('sidebar')\" class=\"chat-window\"\r\n [class.fullscreen]=\"isFullScreen\" [class.layout-sidebar]=\"buttonStyle.includes('sidebar')\">\r\n <!-- chat window header -->\r\n <app-chat-header [appHeaderLogoUrl]=\"appHeaderLogoUrl\" [isAuthenticated]=\"isAuthenticated\"\r\n [isFullScreen]=\"isFullScreen\" [settingsMenu]=\"settingsMenu\" [isNewChatDisabled]=\"messages.length === 0\"\r\n (toggleChat)=\"onToggleChat()\" (toggleFullScreen)=\"onToggleFullScreen()\"\r\n (toggleHistorySidebar)=\"onToggleHistorySidebar()\" (clearChat)=\"onClearChat()\"></app-chat-header>\r\n\r\n <!-- Main Content Area: Toggle between Messages and History -->\r\n <div class=\"chat-content-wrapper\">\r\n <!-- Chat History View -->\r\n <app-chat-history-sidebar [class.sidebar-closed]=\"!isHistorySidebarOpen\" [sessions]=\"chatSessions\"\r\n [isOpen]=\"isHistorySidebarOpen\" [userName]=\"chatHistoryUserName\" [isLoading]=\"isLoadingSessions\"\r\n [hasMoreSessions]=\"hasMoreSessions\" [isLoadingMore]=\"isLoadingMoreSessions\"\r\n [processingSessionId]=\"processingSessionId\" (sessionSelected)=\"onSessionSelected($event)\"\r\n (sessionDeleted)=\"onSessionDeleted($event)\" (loadMore)=\"loadMoreSessions.emit()\"\r\n (refresh)=\"refreshSessions.emit()\" (sessionRenamed)=\"onSessionRenamed($event)\" (deleteAll)=\"onDeleteAllSessions()\"\r\n (closed)=\"onToggleHistorySidebar()\">\r\n </app-chat-history-sidebar>\r\n\r\n <!-- Messages View -->\r\n <div class=\"messages-view\" [class.hidden]=\"isHistorySidebarOpen && !isFullScreen\">\r\n <!-- Messages / Welcome Screen -->\r\n @if (!showLoginForm) {\r\n <app-message-list [messages]=\"messages\" [isBotTyping]=\"isBotTyping\" [isStreaming]=\"isStreaming\"\r\n [appLogoUrl]=\"appLogoUrl\" [appSubtitle]=\"appSubtitle\" [welcomeDesc]=\"welcomeDesc\"\r\n [predefinedMessages]=\"predefinedMessages\" [botAvatarUrl]=\"botAvatarUrl\" [userAvatarUrl]=\"userAvatarUrl\"\r\n [userName]=\"userName\" [isAuthenticated]=\"isAuthenticated\" [trackByMessageId]=\"trackByMessageId\"\r\n (suggestionClick)=\"onSuggestionClick($event)\" (loginClick)=\"onLoginClick()\"></app-message-list>\r\n }\r\n\r\n @if (showSuggestionChips && isAuthenticated) {\r\n <app-chips [messages]=\"suggestedMessages\" [disabled]=\"isBotTyping\"\r\n (chipClick)=\"onSuggestionClick($event)\"></app-chips>\r\n }\r\n\r\n <!-- Chat Input: Only show when authenticated -->\r\n @if (isAuthenticated) {\r\n <app-message-input [isBotTyping]=\"isBotTyping\" [hintText]=\"hintText\" (send)=\"onSend($event)\"\r\n (stop)=\"onStop()\"></app-message-input>\r\n }\r\n\r\n <!-- Login Form -->\r\n @if (showLoginForm && !isAuthenticated) {\r\n <app-login-form [isLoggingIn]=\"isLoggingIn\" (loginSubmit)=\"onLoginSubmit($event)\"\r\n (cancel)=\"onCancelLogin()\"></app-login-form>\r\n }\r\n\r\n <!-- Auth error snackbar (login/logout errors only) -->\r\n <!-- <app-snackbar\r\n *ngIf=\"authError\"\r\n [message]=\"authError\"\r\n (closed)=\"onClearAuthError()\"\r\n ></app-snackbar> -->\r\n\r\n\r\n <!-- footer -->\r\n <app-chat-footer></app-chat-footer>\r\n </div>\r\n </div>\r\n</div>\r\n}\r\n\r\n<mat-menu #settingsMenu=\"matMenu\">\r\n <!-- Personalization -->\r\n @if (isAuthenticated) {\r\n <button mat-menu-item (click)=\"onOpenPersonalization()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>settings_suggest</mat-icon>\r\n <span>Personalization</span>\r\n </button>\r\n }\r\n\r\n\r\n <!-- Change Theme -->\r\n\r\n <!-- Full-Screen Button -->\r\n <button mat-menu-item (click)=\"onToggleFullScreen()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>{{ isFullScreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>\r\n <span> {{ isFullScreen ? 'Minimize' : 'Expand' }}</span>\r\n </button>\r\n\r\n <!-- Clear Chat -->\r\n @if (isAuthenticated && messages.length > 0) {\r\n <button mat-menu-item (click)=\"onClearChat()\" style=\"display: flex; align-items: center\">\r\n <mat-icon> clear_all</mat-icon>\r\n <span>End Chat</span>\r\n </button>\r\n }\r\n\r\n <!-- Logout -->\r\n @if (isAuthenticated) {\r\n <button mat-menu-item (click)=\"onLogout()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>logout</mat-icon>\r\n <span>Logout</span>\r\n </button>\r\n }\r\n</mat-menu>", styles: [".doohbot-container{position:fixed;bottom:20px;right:20px;z-index:1000}.chat-window{width:clamp(400px,30vw,450px);height:clamp(620px,70vh,660px);background-color:var(--background-color);border-radius:20px;border-color:var(--border-color);box-shadow:var(--border-shadow-color);display:flex;flex-direction:column;overflow:hidden;animation:slide-in .5s ease;position:fixed;right:20px;bottom:20px;-webkit-user-select:none;user-select:none}@media (max-width: 768px){.chat-window{width:95%;height:calc(100vh - 20px)}}.chat-window.layout-sidebar{height:100vh;top:0;bottom:0;right:0;width:clamp(400px,25vw,450px);border-radius:20px 0 0 20px;animation:slide-in-sidebar .4s ease-out}.chat-window.layout-sidebar.fullscreen{width:100vw;height:100vh;border-radius:0;transform:none;top:0;left:0}@keyframes slide-in-sidebar{0%{transform:translate(100%)}to{transform:translate(0)}}@media (max-width: 480px){.chat-window{width:90%;height:calc(100vh - 40px)}}.chat-window.fullscreen{width:100vw;height:100vh;border-radius:0;position:fixed;top:0;left:0;transform:none;-webkit-user-select:none;user-select:none}.chat-content-wrapper{flex:1;display:flex;flex-direction:column;overflow:hidden;position:relative}.chat-content-wrapper app-chat-history-sidebar{height:100%;width:100%;display:flex;flex-direction:column;flex:1;min-height:0}.chat-window.fullscreen .chat-content-wrapper{flex-direction:row}.chat-window.fullscreen app-chat-history-sidebar{width:260px;flex:0 0 260px;border-right:1px solid var(--border-color)}.chat-window.fullscreen app-chat-history-sidebar.sidebar-closed{display:none}.messages-view{display:flex;flex-direction:column;height:100%;width:100%}.messages-view.hidden{display:none}.messages-view app-message-list,.messages-view app-login-form{flex:1;min-height:0}.messages-view app-snackbar{flex-shrink:0;margin-top:auto}.messages-view app-message-input{flex-shrink:0}.theme-selector{display:flex;align-items:center;padding:4px 12px;gap:8px}.theme-btn{background:none;border:none;color:var(--white);transition:color .2s ease}.theme-btn.selected{color:var(--primary-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "component", type: Chips, selector: "app-chips", inputs: ["messages", "disabled"], outputs: ["chipClick"] }, { kind: "component", type: MessageListComponent, selector: "app-message-list", inputs: ["messages", "isBotTyping", "isStreaming", "appLogoUrl", "appSubtitle", "welcomeDesc", "predefinedMessages", "botAvatarUrl", "userAvatarUrl", "userName", "isAuthenticated", "trackByMessageId"], outputs: ["suggestionClick", "loginClick"] }, { kind: "component", type: MessageInputComponent, selector: "app-message-input", inputs: ["isBotTyping", "hintText"], outputs: ["send", "stop"] }, { kind: "directive", type: DraggableDialogDirective, selector: "[draggableDialog]", inputs: ["dragHandle", "enableDrag"] }, { kind: "directive", type: ResizableDialogDirective, selector: "[resizableDialog]", inputs: ["enableResize"] }, { kind: "component", type: ChatHistorySidebarComponent, selector: "app-chat-history-sidebar", inputs: ["sessions", "isOpen", "userName", "isLoading", "hasMoreSessions", "isLoadingMore", "processingSessionId"], outputs: ["sessionSelected", "sessionDeleted", "closed", "loadMore", "refresh", "sessionRenamed", "deleteAll"] }, { kind: "component", type: ChatHeaderComponent, selector: "app-chat-header", inputs: ["appHeaderLogoUrl", "isAuthenticated", "isFullScreen", "settingsMenu", "isNewChatDisabled"], outputs: ["toggleChat", "toggleFullScreen", "toggleHistorySidebar", "clearChat"] }, { kind: "component", type: LoginFormComponent, selector: "app-login-form", inputs: ["isLoggingIn"], outputs: ["loginSubmit", "cancel"] }, { kind: "component", type: ChatFooterComponent, selector: "app-chat-footer" }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatDialogModule }] });
4032
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.14", type: ChatWindowComponent, isStandalone: true, selector: "app-chat-window", inputs: { isChatOpen: "isChatOpen", enableDrag: "enableDrag", enableResize: "enableResize", isFullScreen: "isFullScreen", isStreaming: "isStreaming", isAuthenticated: "isAuthenticated", appTitle: "appTitle", appLogoUrl: "appLogoUrl", appTextLogoUrl: "appTextLogoUrl", appHeaderLogoUrl: "appHeaderLogoUrl", messages: "messages", isBotTyping: "isBotTyping", appSubtitle: "appSubtitle", welcomeDesc: "welcomeDesc", predefinedMessages: "predefinedMessages", suggestedMessages: "suggestedMessages", botAvatarUrl: "botAvatarUrl", userAvatarUrl: "userAvatarUrl", userName: "userName", trackByMessageId: "trackByMessageId", hintText: "hintText", messageError: "messageError", showSuggestionChips: "showSuggestionChips", isHistorySidebarOpen: "isHistorySidebarOpen", chatSessions: "chatSessions", chatHistoryUserName: "chatHistoryUserName", isLoggingIn: "isLoggingIn", authError: "authError", authSuccess: "authSuccess", isLoadingSessions: "isLoadingSessions", hasMoreSessions: "hasMoreSessions", isLoadingMoreSessions: "isLoadingMoreSessions", processingSessionId: "processingSessionId", themeConfig: "themeConfig", buttonStyle: "buttonStyle" }, outputs: { toggleChat: "toggleChat", toggleFullScreen: "toggleFullScreen", toggleHistorySidebar: "toggleHistorySidebar", openSettings: "openSettings", suggestionClick: "suggestionClick", send: "send", stop: "stop", clearMessageError: "clearMessageError", clearChat: "clearChat", sessionSelected: "sessionSelected", sessionDeleted: "sessionDeleted", loadMoreSessions: "loadMoreSessions", refreshSessions: "refreshSessions", sessionRenamed: "sessionRenamed", deleteAllSessions: "deleteAllSessions", loginSubmit: "loginSubmit", logout: "logout" }, usesOnChanges: true, ngImport: i0, template: "@if (isChatOpen) {\r\n <div\r\n draggableDialog\r\n [enableDrag]=\"enableDrag && !buttonStyle.includes('sidebar')\"\r\n [dragHandle]=\"'.chat-header'\"\r\n resizableDialog\r\n [enableResize]=\"enableResize && !buttonStyle.includes('sidebar')\"\r\n class=\"chat-window\"\r\n [class.fullscreen]=\"isFullScreen\"\r\n [class.layout-sidebar]=\"buttonStyle.includes('sidebar')\"\r\n >\r\n <!-- chat window header -->\r\n <app-chat-header\r\n [appHeaderLogoUrl]=\"appHeaderLogoUrl\"\r\n [isAuthenticated]=\"isAuthenticated\"\r\n [isFullScreen]=\"isFullScreen\"\r\n [settingsMenu]=\"settingsMenu\"\r\n [isNewChatDisabled]=\"messages.length === 0\"\r\n (toggleChat)=\"onToggleChat()\"\r\n (toggleFullScreen)=\"onToggleFullScreen()\"\r\n (toggleHistorySidebar)=\"onToggleHistorySidebar()\"\r\n (clearChat)=\"onClearChat()\"\r\n ></app-chat-header>\r\n\r\n <!-- Main Content Area: Toggle between Messages and History -->\r\n <div class=\"chat-content-wrapper\">\r\n <!-- Chat History View -->\r\n <app-chat-history-sidebar\r\n [class.sidebar-closed]=\"!isHistorySidebarOpen\"\r\n [sessions]=\"chatSessions\"\r\n [isOpen]=\"isHistorySidebarOpen\"\r\n [userName]=\"chatHistoryUserName\"\r\n [isLoading]=\"isLoadingSessions\"\r\n [hasMoreSessions]=\"hasMoreSessions\"\r\n [isLoadingMore]=\"isLoadingMoreSessions\"\r\n [processingSessionId]=\"processingSessionId\"\r\n (sessionSelected)=\"onSessionSelected($event)\"\r\n (sessionDeleted)=\"onSessionDeleted($event)\"\r\n (loadMore)=\"loadMoreSessions.emit()\"\r\n (refresh)=\"refreshSessions.emit()\"\r\n (sessionRenamed)=\"onSessionRenamed($event)\"\r\n (deleteAll)=\"onDeleteAllSessions()\"\r\n (closed)=\"onToggleHistorySidebar()\"\r\n >\r\n </app-chat-history-sidebar>\r\n\r\n <!-- Messages View -->\r\n <div class=\"messages-view\" [class.hidden]=\"isHistorySidebarOpen && !isFullScreen\">\r\n <!-- Messages / Welcome Screen -->\r\n @if (!showLoginForm) {\r\n <app-message-list\r\n [messages]=\"messages\"\r\n [isBotTyping]=\"isBotTyping\"\r\n [isStreaming]=\"isStreaming\"\r\n [appLogoUrl]=\"appLogoUrl\"\r\n [appSubtitle]=\"appSubtitle\"\r\n [welcomeDesc]=\"welcomeDesc\"\r\n [predefinedMessages]=\"predefinedMessages\"\r\n [botAvatarUrl]=\"botAvatarUrl\"\r\n [userAvatarUrl]=\"userAvatarUrl\"\r\n [userName]=\"userName\"\r\n [isAuthenticated]=\"isAuthenticated\"\r\n [isLoggingIn]=\"isLoggingIn\"\r\n [trackByMessageId]=\"trackByMessageId\"\r\n (suggestionClick)=\"onSuggestionClick($event)\"\r\n (loginClick)=\"onLoginClick()\"\r\n ></app-message-list>\r\n }\r\n\r\n @if (showSuggestionChips && isAuthenticated) {\r\n <app-chips\r\n [messages]=\"suggestedMessages\"\r\n [disabled]=\"isBotTyping\"\r\n (chipClick)=\"onSuggestionClick($event)\"\r\n ></app-chips>\r\n }\r\n\r\n <!-- Chat Input: Only show when authenticated -->\r\n @if (isAuthenticated) {\r\n <app-message-input\r\n [isBotTyping]=\"isBotTyping\"\r\n [hintText]=\"hintText\"\r\n (send)=\"onSend($event)\"\r\n (stop)=\"onStop()\"\r\n ></app-message-input>\r\n }\r\n\r\n <!-- Login Form -->\r\n @if (showLoginForm && !isAuthenticated) {\r\n <app-login-form\r\n [isLoggingIn]=\"isLoggingIn\"\r\n (loginSubmit)=\"onLoginSubmit($event)\"\r\n (cancel)=\"onCancelLogin()\"\r\n ></app-login-form>\r\n }\r\n\r\n <!-- Auth error snackbar (login/logout errors only) -->\r\n <!-- <app-snackbar\r\n *ngIf=\"authError\"\r\n [message]=\"authError\"\r\n (closed)=\"onClearAuthError()\"\r\n ></app-snackbar> -->\r\n\r\n <!-- footer -->\r\n <app-chat-footer></app-chat-footer>\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n\r\n<mat-menu #settingsMenu=\"matMenu\">\r\n <!-- Personalization -->\r\n @if (isAuthenticated) {\r\n <button\r\n mat-menu-item\r\n (click)=\"onOpenPersonalization()\"\r\n style=\"display: flex; align-items: center\"\r\n >\r\n <mat-icon>settings_suggest</mat-icon>\r\n <span>Personalization</span>\r\n </button>\r\n }\r\n\r\n <!-- Change Theme -->\r\n\r\n <!-- Full-Screen Button -->\r\n <button mat-menu-item (click)=\"onToggleFullScreen()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>{{ isFullScreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>\r\n <span> {{ isFullScreen ? 'Minimize' : 'Expand' }}</span>\r\n </button>\r\n\r\n <!-- Clear Chat -->\r\n @if (isAuthenticated && messages.length > 0) {\r\n <button mat-menu-item (click)=\"onClearChat()\" style=\"display: flex; align-items: center\">\r\n <mat-icon> clear_all</mat-icon>\r\n <span>End Chat</span>\r\n </button>\r\n }\r\n\r\n <!-- Logout -->\r\n @if (isAuthenticated) {\r\n <button mat-menu-item (click)=\"onLogout()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>logout</mat-icon>\r\n <span>Logout</span>\r\n </button>\r\n }\r\n</mat-menu>\r\n", styles: [".doohbot-container{position:fixed;bottom:20px;right:20px;z-index:1000}.chat-window{width:clamp(400px,30vw,450px);height:clamp(620px,70vh,660px);background-color:var(--background-color);border-radius:20px;border-color:var(--border-color);box-shadow:var(--border-shadow-color);display:flex;flex-direction:column;overflow:hidden;animation:slide-in .5s ease;position:fixed;right:20px;bottom:20px;-webkit-user-select:none;user-select:none}@media (max-width: 768px){.chat-window{width:95%;height:calc(100vh - 20px)}}.chat-window.layout-sidebar{height:100vh;top:0;bottom:0;right:0;width:clamp(400px,25vw,450px);border-radius:20px 0 0 20px;animation:slide-in-sidebar .4s ease-out}.chat-window.layout-sidebar.fullscreen{width:100vw;height:100vh;border-radius:0;transform:none;top:0;left:0}@keyframes slide-in-sidebar{0%{transform:translate(100%)}to{transform:translate(0)}}@media (max-width: 480px){.chat-window{width:90%;height:calc(100vh - 40px)}}.chat-window.fullscreen{width:100vw;height:100vh;border-radius:0;position:fixed;top:0;left:0;transform:none;-webkit-user-select:none;user-select:none}.chat-content-wrapper{flex:1;display:flex;flex-direction:column;overflow:hidden;position:relative}.chat-content-wrapper app-chat-history-sidebar{height:100%;width:100%;display:flex;flex-direction:column;flex:1;min-height:0}.chat-window.fullscreen .chat-content-wrapper{flex-direction:row}.chat-window.fullscreen app-chat-history-sidebar{width:260px;flex:0 0 260px;border-right:1px solid var(--border-color)}.chat-window.fullscreen app-chat-history-sidebar.sidebar-closed{display:none}.messages-view{display:flex;flex-direction:column;height:100%;width:100%}.messages-view.hidden{display:none}.messages-view app-message-list,.messages-view app-login-form{flex:1;min-height:0}.messages-view app-snackbar{flex-shrink:0;margin-top:auto}.messages-view app-message-input{flex-shrink:0}.theme-selector{display:flex;align-items:center;padding:4px 12px;gap:8px}.theme-btn{background:none;border:none;color:var(--white);transition:color .2s ease}.theme-btn.selected{color:var(--primary-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "component", type: Chips, selector: "app-chips", inputs: ["messages", "disabled"], outputs: ["chipClick"] }, { kind: "component", type: MessageListComponent, selector: "app-message-list", inputs: ["messages", "isBotTyping", "isStreaming", "appLogoUrl", "appSubtitle", "welcomeDesc", "predefinedMessages", "botAvatarUrl", "userAvatarUrl", "userName", "isAuthenticated", "isLoggingIn", "trackByMessageId"], outputs: ["suggestionClick", "loginClick"] }, { kind: "component", type: MessageInputComponent, selector: "app-message-input", inputs: ["isBotTyping", "hintText"], outputs: ["send", "stop"] }, { kind: "directive", type: DraggableDialogDirective, selector: "[draggableDialog]", inputs: ["dragHandle", "enableDrag"] }, { kind: "directive", type: ResizableDialogDirective, selector: "[resizableDialog]", inputs: ["enableResize"] }, { kind: "component", type: ChatHistorySidebarComponent, selector: "app-chat-history-sidebar", inputs: ["sessions", "isOpen", "userName", "isLoading", "hasMoreSessions", "isLoadingMore", "processingSessionId"], outputs: ["sessionSelected", "sessionDeleted", "closed", "loadMore", "refresh", "sessionRenamed", "deleteAll"] }, { kind: "component", type: ChatHeaderComponent, selector: "app-chat-header", inputs: ["appHeaderLogoUrl", "isAuthenticated", "isFullScreen", "settingsMenu", "isNewChatDisabled"], outputs: ["toggleChat", "toggleFullScreen", "toggleHistorySidebar", "clearChat"] }, { kind: "component", type: LoginFormComponent, selector: "app-login-form", inputs: ["isLoggingIn"], outputs: ["loginSubmit", "cancel"] }, { kind: "component", type: ChatFooterComponent, selector: "app-chat-footer" }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatDialogModule }] });
4020
4033
  }
4021
4034
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ChatWindowComponent, decorators: [{
4022
4035
  type: Component,
@@ -4035,7 +4048,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
4035
4048
  ChatFooterComponent,
4036
4049
  FormsModule,
4037
4050
  MatDialogModule,
4038
- ], template: "@if (isChatOpen) {\r\n<div draggableDialog [enableDrag]=\"enableDrag && !buttonStyle.includes('sidebar')\" [dragHandle]=\"'.chat-header'\"\r\n resizableDialog [enableResize]=\"enableResize && !buttonStyle.includes('sidebar')\" class=\"chat-window\"\r\n [class.fullscreen]=\"isFullScreen\" [class.layout-sidebar]=\"buttonStyle.includes('sidebar')\">\r\n <!-- chat window header -->\r\n <app-chat-header [appHeaderLogoUrl]=\"appHeaderLogoUrl\" [isAuthenticated]=\"isAuthenticated\"\r\n [isFullScreen]=\"isFullScreen\" [settingsMenu]=\"settingsMenu\" [isNewChatDisabled]=\"messages.length === 0\"\r\n (toggleChat)=\"onToggleChat()\" (toggleFullScreen)=\"onToggleFullScreen()\"\r\n (toggleHistorySidebar)=\"onToggleHistorySidebar()\" (clearChat)=\"onClearChat()\"></app-chat-header>\r\n\r\n <!-- Main Content Area: Toggle between Messages and History -->\r\n <div class=\"chat-content-wrapper\">\r\n <!-- Chat History View -->\r\n <app-chat-history-sidebar [class.sidebar-closed]=\"!isHistorySidebarOpen\" [sessions]=\"chatSessions\"\r\n [isOpen]=\"isHistorySidebarOpen\" [userName]=\"chatHistoryUserName\" [isLoading]=\"isLoadingSessions\"\r\n [hasMoreSessions]=\"hasMoreSessions\" [isLoadingMore]=\"isLoadingMoreSessions\"\r\n [processingSessionId]=\"processingSessionId\" (sessionSelected)=\"onSessionSelected($event)\"\r\n (sessionDeleted)=\"onSessionDeleted($event)\" (loadMore)=\"loadMoreSessions.emit()\"\r\n (refresh)=\"refreshSessions.emit()\" (sessionRenamed)=\"onSessionRenamed($event)\" (deleteAll)=\"onDeleteAllSessions()\"\r\n (closed)=\"onToggleHistorySidebar()\">\r\n </app-chat-history-sidebar>\r\n\r\n <!-- Messages View -->\r\n <div class=\"messages-view\" [class.hidden]=\"isHistorySidebarOpen && !isFullScreen\">\r\n <!-- Messages / Welcome Screen -->\r\n @if (!showLoginForm) {\r\n <app-message-list [messages]=\"messages\" [isBotTyping]=\"isBotTyping\" [isStreaming]=\"isStreaming\"\r\n [appLogoUrl]=\"appLogoUrl\" [appSubtitle]=\"appSubtitle\" [welcomeDesc]=\"welcomeDesc\"\r\n [predefinedMessages]=\"predefinedMessages\" [botAvatarUrl]=\"botAvatarUrl\" [userAvatarUrl]=\"userAvatarUrl\"\r\n [userName]=\"userName\" [isAuthenticated]=\"isAuthenticated\" [trackByMessageId]=\"trackByMessageId\"\r\n (suggestionClick)=\"onSuggestionClick($event)\" (loginClick)=\"onLoginClick()\"></app-message-list>\r\n }\r\n\r\n @if (showSuggestionChips && isAuthenticated) {\r\n <app-chips [messages]=\"suggestedMessages\" [disabled]=\"isBotTyping\"\r\n (chipClick)=\"onSuggestionClick($event)\"></app-chips>\r\n }\r\n\r\n <!-- Chat Input: Only show when authenticated -->\r\n @if (isAuthenticated) {\r\n <app-message-input [isBotTyping]=\"isBotTyping\" [hintText]=\"hintText\" (send)=\"onSend($event)\"\r\n (stop)=\"onStop()\"></app-message-input>\r\n }\r\n\r\n <!-- Login Form -->\r\n @if (showLoginForm && !isAuthenticated) {\r\n <app-login-form [isLoggingIn]=\"isLoggingIn\" (loginSubmit)=\"onLoginSubmit($event)\"\r\n (cancel)=\"onCancelLogin()\"></app-login-form>\r\n }\r\n\r\n <!-- Auth error snackbar (login/logout errors only) -->\r\n <!-- <app-snackbar\r\n *ngIf=\"authError\"\r\n [message]=\"authError\"\r\n (closed)=\"onClearAuthError()\"\r\n ></app-snackbar> -->\r\n\r\n\r\n <!-- footer -->\r\n <app-chat-footer></app-chat-footer>\r\n </div>\r\n </div>\r\n</div>\r\n}\r\n\r\n<mat-menu #settingsMenu=\"matMenu\">\r\n <!-- Personalization -->\r\n @if (isAuthenticated) {\r\n <button mat-menu-item (click)=\"onOpenPersonalization()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>settings_suggest</mat-icon>\r\n <span>Personalization</span>\r\n </button>\r\n }\r\n\r\n\r\n <!-- Change Theme -->\r\n\r\n <!-- Full-Screen Button -->\r\n <button mat-menu-item (click)=\"onToggleFullScreen()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>{{ isFullScreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>\r\n <span> {{ isFullScreen ? 'Minimize' : 'Expand' }}</span>\r\n </button>\r\n\r\n <!-- Clear Chat -->\r\n @if (isAuthenticated && messages.length > 0) {\r\n <button mat-menu-item (click)=\"onClearChat()\" style=\"display: flex; align-items: center\">\r\n <mat-icon> clear_all</mat-icon>\r\n <span>End Chat</span>\r\n </button>\r\n }\r\n\r\n <!-- Logout -->\r\n @if (isAuthenticated) {\r\n <button mat-menu-item (click)=\"onLogout()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>logout</mat-icon>\r\n <span>Logout</span>\r\n </button>\r\n }\r\n</mat-menu>", styles: [".doohbot-container{position:fixed;bottom:20px;right:20px;z-index:1000}.chat-window{width:clamp(400px,30vw,450px);height:clamp(620px,70vh,660px);background-color:var(--background-color);border-radius:20px;border-color:var(--border-color);box-shadow:var(--border-shadow-color);display:flex;flex-direction:column;overflow:hidden;animation:slide-in .5s ease;position:fixed;right:20px;bottom:20px;-webkit-user-select:none;user-select:none}@media (max-width: 768px){.chat-window{width:95%;height:calc(100vh - 20px)}}.chat-window.layout-sidebar{height:100vh;top:0;bottom:0;right:0;width:clamp(400px,25vw,450px);border-radius:20px 0 0 20px;animation:slide-in-sidebar .4s ease-out}.chat-window.layout-sidebar.fullscreen{width:100vw;height:100vh;border-radius:0;transform:none;top:0;left:0}@keyframes slide-in-sidebar{0%{transform:translate(100%)}to{transform:translate(0)}}@media (max-width: 480px){.chat-window{width:90%;height:calc(100vh - 40px)}}.chat-window.fullscreen{width:100vw;height:100vh;border-radius:0;position:fixed;top:0;left:0;transform:none;-webkit-user-select:none;user-select:none}.chat-content-wrapper{flex:1;display:flex;flex-direction:column;overflow:hidden;position:relative}.chat-content-wrapper app-chat-history-sidebar{height:100%;width:100%;display:flex;flex-direction:column;flex:1;min-height:0}.chat-window.fullscreen .chat-content-wrapper{flex-direction:row}.chat-window.fullscreen app-chat-history-sidebar{width:260px;flex:0 0 260px;border-right:1px solid var(--border-color)}.chat-window.fullscreen app-chat-history-sidebar.sidebar-closed{display:none}.messages-view{display:flex;flex-direction:column;height:100%;width:100%}.messages-view.hidden{display:none}.messages-view app-message-list,.messages-view app-login-form{flex:1;min-height:0}.messages-view app-snackbar{flex-shrink:0;margin-top:auto}.messages-view app-message-input{flex-shrink:0}.theme-selector{display:flex;align-items:center;padding:4px 12px;gap:8px}.theme-btn{background:none;border:none;color:var(--white);transition:color .2s ease}.theme-btn.selected{color:var(--primary-color)}\n"] }]
4051
+ ], template: "@if (isChatOpen) {\r\n <div\r\n draggableDialog\r\n [enableDrag]=\"enableDrag && !buttonStyle.includes('sidebar')\"\r\n [dragHandle]=\"'.chat-header'\"\r\n resizableDialog\r\n [enableResize]=\"enableResize && !buttonStyle.includes('sidebar')\"\r\n class=\"chat-window\"\r\n [class.fullscreen]=\"isFullScreen\"\r\n [class.layout-sidebar]=\"buttonStyle.includes('sidebar')\"\r\n >\r\n <!-- chat window header -->\r\n <app-chat-header\r\n [appHeaderLogoUrl]=\"appHeaderLogoUrl\"\r\n [isAuthenticated]=\"isAuthenticated\"\r\n [isFullScreen]=\"isFullScreen\"\r\n [settingsMenu]=\"settingsMenu\"\r\n [isNewChatDisabled]=\"messages.length === 0\"\r\n (toggleChat)=\"onToggleChat()\"\r\n (toggleFullScreen)=\"onToggleFullScreen()\"\r\n (toggleHistorySidebar)=\"onToggleHistorySidebar()\"\r\n (clearChat)=\"onClearChat()\"\r\n ></app-chat-header>\r\n\r\n <!-- Main Content Area: Toggle between Messages and History -->\r\n <div class=\"chat-content-wrapper\">\r\n <!-- Chat History View -->\r\n <app-chat-history-sidebar\r\n [class.sidebar-closed]=\"!isHistorySidebarOpen\"\r\n [sessions]=\"chatSessions\"\r\n [isOpen]=\"isHistorySidebarOpen\"\r\n [userName]=\"chatHistoryUserName\"\r\n [isLoading]=\"isLoadingSessions\"\r\n [hasMoreSessions]=\"hasMoreSessions\"\r\n [isLoadingMore]=\"isLoadingMoreSessions\"\r\n [processingSessionId]=\"processingSessionId\"\r\n (sessionSelected)=\"onSessionSelected($event)\"\r\n (sessionDeleted)=\"onSessionDeleted($event)\"\r\n (loadMore)=\"loadMoreSessions.emit()\"\r\n (refresh)=\"refreshSessions.emit()\"\r\n (sessionRenamed)=\"onSessionRenamed($event)\"\r\n (deleteAll)=\"onDeleteAllSessions()\"\r\n (closed)=\"onToggleHistorySidebar()\"\r\n >\r\n </app-chat-history-sidebar>\r\n\r\n <!-- Messages View -->\r\n <div class=\"messages-view\" [class.hidden]=\"isHistorySidebarOpen && !isFullScreen\">\r\n <!-- Messages / Welcome Screen -->\r\n @if (!showLoginForm) {\r\n <app-message-list\r\n [messages]=\"messages\"\r\n [isBotTyping]=\"isBotTyping\"\r\n [isStreaming]=\"isStreaming\"\r\n [appLogoUrl]=\"appLogoUrl\"\r\n [appSubtitle]=\"appSubtitle\"\r\n [welcomeDesc]=\"welcomeDesc\"\r\n [predefinedMessages]=\"predefinedMessages\"\r\n [botAvatarUrl]=\"botAvatarUrl\"\r\n [userAvatarUrl]=\"userAvatarUrl\"\r\n [userName]=\"userName\"\r\n [isAuthenticated]=\"isAuthenticated\"\r\n [isLoggingIn]=\"isLoggingIn\"\r\n [trackByMessageId]=\"trackByMessageId\"\r\n (suggestionClick)=\"onSuggestionClick($event)\"\r\n (loginClick)=\"onLoginClick()\"\r\n ></app-message-list>\r\n }\r\n\r\n @if (showSuggestionChips && isAuthenticated) {\r\n <app-chips\r\n [messages]=\"suggestedMessages\"\r\n [disabled]=\"isBotTyping\"\r\n (chipClick)=\"onSuggestionClick($event)\"\r\n ></app-chips>\r\n }\r\n\r\n <!-- Chat Input: Only show when authenticated -->\r\n @if (isAuthenticated) {\r\n <app-message-input\r\n [isBotTyping]=\"isBotTyping\"\r\n [hintText]=\"hintText\"\r\n (send)=\"onSend($event)\"\r\n (stop)=\"onStop()\"\r\n ></app-message-input>\r\n }\r\n\r\n <!-- Login Form -->\r\n @if (showLoginForm && !isAuthenticated) {\r\n <app-login-form\r\n [isLoggingIn]=\"isLoggingIn\"\r\n (loginSubmit)=\"onLoginSubmit($event)\"\r\n (cancel)=\"onCancelLogin()\"\r\n ></app-login-form>\r\n }\r\n\r\n <!-- Auth error snackbar (login/logout errors only) -->\r\n <!-- <app-snackbar\r\n *ngIf=\"authError\"\r\n [message]=\"authError\"\r\n (closed)=\"onClearAuthError()\"\r\n ></app-snackbar> -->\r\n\r\n <!-- footer -->\r\n <app-chat-footer></app-chat-footer>\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n\r\n<mat-menu #settingsMenu=\"matMenu\">\r\n <!-- Personalization -->\r\n @if (isAuthenticated) {\r\n <button\r\n mat-menu-item\r\n (click)=\"onOpenPersonalization()\"\r\n style=\"display: flex; align-items: center\"\r\n >\r\n <mat-icon>settings_suggest</mat-icon>\r\n <span>Personalization</span>\r\n </button>\r\n }\r\n\r\n <!-- Change Theme -->\r\n\r\n <!-- Full-Screen Button -->\r\n <button mat-menu-item (click)=\"onToggleFullScreen()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>{{ isFullScreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>\r\n <span> {{ isFullScreen ? 'Minimize' : 'Expand' }}</span>\r\n </button>\r\n\r\n <!-- Clear Chat -->\r\n @if (isAuthenticated && messages.length > 0) {\r\n <button mat-menu-item (click)=\"onClearChat()\" style=\"display: flex; align-items: center\">\r\n <mat-icon> clear_all</mat-icon>\r\n <span>End Chat</span>\r\n </button>\r\n }\r\n\r\n <!-- Logout -->\r\n @if (isAuthenticated) {\r\n <button mat-menu-item (click)=\"onLogout()\" style=\"display: flex; align-items: center\">\r\n <mat-icon>logout</mat-icon>\r\n <span>Logout</span>\r\n </button>\r\n }\r\n</mat-menu>\r\n", styles: [".doohbot-container{position:fixed;bottom:20px;right:20px;z-index:1000}.chat-window{width:clamp(400px,30vw,450px);height:clamp(620px,70vh,660px);background-color:var(--background-color);border-radius:20px;border-color:var(--border-color);box-shadow:var(--border-shadow-color);display:flex;flex-direction:column;overflow:hidden;animation:slide-in .5s ease;position:fixed;right:20px;bottom:20px;-webkit-user-select:none;user-select:none}@media (max-width: 768px){.chat-window{width:95%;height:calc(100vh - 20px)}}.chat-window.layout-sidebar{height:100vh;top:0;bottom:0;right:0;width:clamp(400px,25vw,450px);border-radius:20px 0 0 20px;animation:slide-in-sidebar .4s ease-out}.chat-window.layout-sidebar.fullscreen{width:100vw;height:100vh;border-radius:0;transform:none;top:0;left:0}@keyframes slide-in-sidebar{0%{transform:translate(100%)}to{transform:translate(0)}}@media (max-width: 480px){.chat-window{width:90%;height:calc(100vh - 40px)}}.chat-window.fullscreen{width:100vw;height:100vh;border-radius:0;position:fixed;top:0;left:0;transform:none;-webkit-user-select:none;user-select:none}.chat-content-wrapper{flex:1;display:flex;flex-direction:column;overflow:hidden;position:relative}.chat-content-wrapper app-chat-history-sidebar{height:100%;width:100%;display:flex;flex-direction:column;flex:1;min-height:0}.chat-window.fullscreen .chat-content-wrapper{flex-direction:row}.chat-window.fullscreen app-chat-history-sidebar{width:260px;flex:0 0 260px;border-right:1px solid var(--border-color)}.chat-window.fullscreen app-chat-history-sidebar.sidebar-closed{display:none}.messages-view{display:flex;flex-direction:column;height:100%;width:100%}.messages-view.hidden{display:none}.messages-view app-message-list,.messages-view app-login-form{flex:1;min-height:0}.messages-view app-snackbar{flex-shrink:0;margin-top:auto}.messages-view app-message-input{flex-shrink:0}.theme-selector{display:flex;align-items:center;padding:4px 12px;gap:8px}.theme-btn{background:none;border:none;color:var(--white);transition:color .2s ease}.theme-btn.selected{color:var(--primary-color)}\n"] }]
4039
4052
  }], ctorParameters: () => [], propDecorators: { isChatOpen: [{
4040
4053
  type: Input
4041
4054
  }], enableDrag: [{
@@ -4208,7 +4221,7 @@ class LicenseService {
4208
4221
  */
4209
4222
  async loadLicenseFile(filePath) {
4210
4223
  try {
4211
- const finalPath = filePath || this.coreConfig.filePath;
4224
+ const finalPath = filePath || this.coreConfig.licenseFilePath;
4212
4225
  const data = await firstValueFrom(this.http.get(finalPath));
4213
4226
  if (!data) {
4214
4227
  throw new Error('Empty license file');
@@ -4241,17 +4254,20 @@ class LicenseService {
4241
4254
  Logger.log(`[LicenseService] Hierarchical Registry loaded for account: ${data.accountId}`);
4242
4255
  }
4243
4256
  processFlatMapLicense(data) {
4244
- // If it's a flat map, we treat it as global defaults for this registry
4245
- // We can map it to a "tenant:*" subject if we want, or just store it in a special way.
4246
- // Industry pattern: Flat maps in external files are often treated as "Environment Overrides"
4247
- // For now, lets store it as a special registry that doesn't enforce accountId
4257
+ // Flat-map format: { "tenantName": "license_key" }
4258
+ // Convert each entry to: tenant:tenantName -> { doohbot: license_key }
4248
4259
  const subjectMap = new Map();
4249
- subjectMap.set('tenant:default', data);
4260
+ Object.entries(data).forEach(([tenantName, licenseKey]) => {
4261
+ const tenantKey = `tenant:${tenantName}`;
4262
+ subjectMap.set(tenantKey, {
4263
+ doohbot: licenseKey,
4264
+ });
4265
+ });
4250
4266
  this.registry.set({
4251
- accountId: 'EXTERNAL_OVERRIDE',
4267
+ accountId: 'FLAT_MAP_REGISTRY',
4252
4268
  subjectLicenses: subjectMap,
4253
4269
  });
4254
- Logger.log('[LicenseService] Flat-map License Registry loaded from external file');
4270
+ Logger.log(`[LicenseService] Flat-map registry loaded with ${subjectMap.size} tenant(s)`);
4255
4271
  }
4256
4272
  /**
4257
4273
  * Resolve the correct license key based on context and requested package
@@ -4295,28 +4311,23 @@ class LicenseService {
4295
4311
  * Resolves the license key for the current tenant.
4296
4312
  */
4297
4313
  resolveTenantLicenseKey(tenancyName) {
4298
- // Explicit tenancy name (param or coreConfig)
4299
- const finalTenancyName = tenancyName || this.coreConfig.tenancyName;
4300
- if (finalTenancyName) {
4301
- Logger.info(`[LicenseService] Using tenancy name: ${finalTenancyName}`);
4302
- tenancyName = finalTenancyName;
4303
- }
4304
- else {
4305
- Logger.error('[LicenseService] Error resolving tenancy name from globals:');
4306
- }
4307
- if (!tenancyName) {
4308
- Logger.warn('[LicenseService] Could not resolve tenancy name.');
4314
+ const activeTenancy = tenancyName || this.coreConfig.tenancyName;
4315
+ if (!activeTenancy) {
4316
+ Logger.warn('[LicenseService] No tenancy name found.');
4309
4317
  return null;
4310
4318
  }
4311
- Logger.debug(`[LicenseService] Resolving license for tenant: ${tenancyName}`);
4312
- // Lookup license key in registry
4313
4319
  const reg = this.registry();
4314
- if (!reg)
4320
+ if (!reg) {
4321
+ Logger.error('[LicenseService] License registry not loaded.');
4315
4322
  return null;
4316
- const tenantLicenses = reg.subjectLicenses.get(`tenant:${tenancyName}`);
4323
+ }
4324
+ const tenantLicenses = reg.subjectLicenses.get(`tenant:${activeTenancy}`);
4317
4325
  const licenseKey = tenantLicenses?.['doohbot'] || null;
4318
4326
  if (licenseKey) {
4319
- Logger.info(`[LicenseService] Found Doohbot license for tenant: ${tenancyName}`);
4327
+ Logger.info(`[LicenseService] Resolved Doohbot license for: ${activeTenancy}`);
4328
+ }
4329
+ else {
4330
+ Logger.warn(`[LicenseService] No license key found for tenant: ${activeTenancy}`);
4320
4331
  }
4321
4332
  return licenseKey;
4322
4333
  }
@@ -4413,8 +4424,12 @@ class Doohbot extends DoohbotInput {
4413
4424
  }
4414
4425
  //! ====================== LIFECYCLE HOOKS =====================
4415
4426
  // Corrected structural integrity.
4416
- ngOnInit() {
4427
+ async ngOnInit() {
4417
4428
  Logger.log('Initializing Doohbot component...');
4429
+ // Load license registry from file and wait for it to complete
4430
+ if (this.config.licenseFilePath) {
4431
+ await this.licenseService.loadLicenseFile(this.config.licenseFilePath);
4432
+ }
4418
4433
  // Run validation once on startup
4419
4434
  this.authService.validateStoredToken().subscribe();
4420
4435
  // React to auth status changes
@@ -4431,10 +4446,27 @@ class Doohbot extends DoohbotInput {
4431
4446
  this.initializeUI();
4432
4447
  }
4433
4448
  else {
4434
- //! Always attempt silent federated login on startup if not authenticated
4435
- this.onFederatedLogin();
4449
+ //! STRICT VALIDATION: Only attempt federated login if we have the necessary configuration
4450
+ const hasAuthToken = !!this.config.authToken;
4451
+ // STRICT VALIDATION: We need both Token AND Valid License Context to proceed
4452
+ if (this.canAttemptFederatedLogin()) {
4453
+ Logger.log('Attempting federated login...');
4454
+ await this.onFederatedLogin();
4455
+ // If federated login failed, the login screen will be shown automatically
4456
+ // via the auth status subscription above
4457
+ }
4458
+ else {
4459
+ Logger.info('Insufficient config for federated login (Need Token + TenancyName/LicenseKey). Waiting for user login.');
4460
+ }
4436
4461
  }
4437
4462
  }
4463
+ canAttemptFederatedLogin() {
4464
+ const hasAuthToken = !!this.config.authToken;
4465
+ const hasDirectLicenseKey = !!this.config.licenseKey;
4466
+ const hasTenantLicenseLookup = !!this.config.tenancyName && !!this.config.licenseFilePath;
4467
+ const hasValidLicenseContext = hasDirectLicenseKey || hasTenantLicenseLookup;
4468
+ return hasAuthToken && hasValidLicenseContext;
4469
+ }
4438
4470
  initializeUI() {
4439
4471
  // Apply theme
4440
4472
  this.themeService.applyCssVariables(this.elementRef.nativeElement, this.themeConfig);
@@ -4473,7 +4505,8 @@ class Doohbot extends DoohbotInput {
4473
4505
  // Handle dynamic config updates for authentication
4474
4506
  if (!this.isAuthenticated()) {
4475
4507
  const token = this.config.authToken;
4476
- if (token) {
4508
+ // Validate Config before attempting
4509
+ if (token && this.canAttemptFederatedLogin()) {
4477
4510
  this.onFederatedLogin(token);
4478
4511
  }
4479
4512
  }
@@ -4491,12 +4524,12 @@ class Doohbot extends DoohbotInput {
4491
4524
  //! ====================== AUTHENTICATION ==================
4492
4525
  // Logic moved to ChatFacadeService.initialize()
4493
4526
  onNormalLogin(credentials) {
4494
- // Try Tenancy Name from Config Input
4527
+ // Use Tenancy Name from Config Input
4495
4528
  let tenancy = this.config.tenancyName;
4496
- // fallback: Try to resolve from global utility (Auto-detect)
4497
- if (!tenancy) {
4498
- tenancy = window.AppPreBootstrap?.resolveTenancyName(window.AppConsts?.appBaseUrl);
4499
- }
4529
+ //! fallback: Try to resolve from global utility (Auto-detect)
4530
+ // if (!tenancy) {
4531
+ // tenancy = window.AppPreBootstrap?.resolveTenancyName(window.AppConsts?.appBaseUrl);
4532
+ // }
4500
4533
  // Resolve key from whatever tenancy we found
4501
4534
  let autoKey = this.licenseService.resolveTenantLicenseKey(tenancy || undefined);
4502
4535
  // Inject for strict validation
@@ -4507,8 +4540,8 @@ class Doohbot extends DoohbotInput {
4507
4540
  }
4508
4541
  this.authService.login(credentials, false);
4509
4542
  }
4510
- onFederatedLogin(token) {
4511
- // Try to resolve Key from Subdomain
4543
+ async onFederatedLogin(token) {
4544
+ // Resolve Key from tenancy name
4512
4545
  let autoKey = this.licenseService.resolveTenantLicenseKey();
4513
4546
  // Fallback to Config Input
4514
4547
  if (!autoKey) {
@@ -4519,10 +4552,14 @@ class Doohbot extends DoohbotInput {
4519
4552
  }
4520
4553
  const request = {
4521
4554
  accessToken: token,
4522
- rememberMe: true,
4555
+ rememberMe: this.config.rememberMe,
4523
4556
  license: autoKey,
4524
4557
  };
4525
- this.authService.federatedLogin(request);
4558
+ // Await the federated login result
4559
+ const success = await this.authService.federatedLogin(request);
4560
+ if (!success) {
4561
+ Logger.info('Federated login failed. User can proceed with normal login.');
4562
+ }
4526
4563
  }
4527
4564
  performLogout() {
4528
4565
  DialogUtils.confirmLogout(this.dialogService).subscribe((confirmed) => {
@@ -4564,7 +4601,7 @@ class Doohbot extends DoohbotInput {
4564
4601
  this.uiState.toggleHistorySidebar();
4565
4602
  }
4566
4603
  loadChatSession(session) {
4567
- Logger.log(`[Doohbot] Session selected: ${session.id}. continuing session...`);
4604
+ Logger.log(`Session selected: ${session.id}. continuing session...`);
4568
4605
  this.chatService.continueSession(session.id);
4569
4606
  this.uiState.closeHistorySidebar();
4570
4607
  }
@@ -4880,7 +4917,7 @@ class LicenseInterceptor {
4880
4917
  // Resolve License Key for Authenticated Request
4881
4918
  const context = authService.getLicensingContext();
4882
4919
  // Post-login, context.tenantId should be company_id
4883
- const licenseKey = licenseService.resolveLicenseKey(context, 'doohbot');
4920
+ const licenseKey = licenseService.resolveLicenseKey(context, '');
4884
4921
  if (licenseKey) {
4885
4922
  const clonedReq = req.clone({
4886
4923
  headers: req.headers.set('x-license-key', licenseKey),
@@ -4913,9 +4950,9 @@ function provideDoohbot() {
4913
4950
  }
4914
4951
 
4915
4952
  // /*
4916
- // * Public API Surface of chatbot
4917
- // */
4918
- // // Main component
4953
+ /* Public API Surface of chatbot
4954
+ */
4955
+ // Main component
4919
4956
  // // Services
4920
4957
  // export * from './lib/core/services/doohbot-api.service';
4921
4958
  // export * from './lib/core/auth/auth.service';