@aakash58/chatbot 1.1.16 → 1.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/esm2022/aakash58-chatbot.mjs +5 -0
  2. package/esm2022/lib/app/chat/chat-ui-state.service.mjs +170 -0
  3. package/esm2022/lib/app/chat/chat.service.mjs +445 -0
  4. package/esm2022/lib/app/chat/components/chat-button/chat-button.component.mjs +50 -0
  5. package/esm2022/lib/app/chat/components/chat-footer/chat-footer.component.mjs +12 -0
  6. package/esm2022/lib/app/chat/components/chat-header/chat-header.component.mjs +66 -0
  7. package/esm2022/lib/app/chat/components/chat-history-sidebar/chat-history-sidebar.component.mjs +186 -0
  8. package/esm2022/lib/app/chat/components/chat-window/chat-window.component.mjs +312 -0
  9. package/esm2022/lib/app/chat/components/message-input/message-input.component.mjs +36 -0
  10. package/esm2022/lib/app/chat/components/message-list/message-list.component.mjs +115 -0
  11. package/esm2022/lib/app/chat/model/chat-history.model.mjs +2 -0
  12. package/esm2022/lib/app/chat/model/chat-request.model.mjs +2 -0
  13. package/esm2022/lib/app/chat/model/chat-response.model.mjs +2 -0
  14. package/esm2022/lib/app/chat/model/chat-session.model.mjs +2 -0
  15. package/esm2022/lib/app/chat/model/chat-stream-message.model.mjs +2 -0
  16. package/esm2022/lib/app/chat/model/chat-stream-response.model.mjs +2 -0
  17. package/esm2022/lib/app/chat/services/chat-api.service.mjs +61 -0
  18. package/esm2022/lib/app/chat/services/chat-audio.service.mjs +50 -0
  19. package/esm2022/lib/app/chat/services/chat-history.service.mjs +252 -0
  20. package/esm2022/lib/app/login/login-form.component.mjs +46 -0
  21. package/esm2022/lib/app/personalization/personalization-dialog.component.mjs +194 -0
  22. package/esm2022/lib/app/personalization/personalization.service.mjs +149 -0
  23. package/esm2022/lib/app/personalization/sections/account/account-section.component.mjs +122 -0
  24. package/esm2022/lib/app/personalization/sections/preferences/color-picker-dialog.component.mjs +86 -0
  25. package/esm2022/lib/app/personalization/sections/preferences/preferences-section.component.mjs +115 -0
  26. package/esm2022/lib/app/personalization/sections/profile/profile-section.component.mjs +29 -0
  27. package/esm2022/lib/app/personalization/sections/settings/setting-section.component.mjs +30 -0
  28. package/esm2022/lib/app/personalization/sections/terms/terms-section.component.mjs +12 -0
  29. package/esm2022/lib/constant/doohbot-constant.mjs +28 -0
  30. package/esm2022/lib/constant/html-entities.mjs +9 -0
  31. package/esm2022/lib/constant/utf8.mjs +10 -0
  32. package/esm2022/lib/core/app-const.mjs +61 -0
  33. package/esm2022/lib/core/auth/account-api.service.mjs +40 -0
  34. package/esm2022/lib/core/auth/auth.service.mjs +391 -0
  35. package/esm2022/lib/core/auth/models/auth-result.model.mjs +3 -0
  36. package/esm2022/lib/core/auth/models/federated-login-request.model.mjs +6 -0
  37. package/esm2022/lib/core/auth/models/login-request.model.mjs +6 -0
  38. package/esm2022/lib/core/auth/storage.service.mjs +110 -0
  39. package/esm2022/lib/core/directives/draggable/draggable-dialog.directive.mjs +112 -0
  40. package/esm2022/lib/core/directives/fullscreen/fullscreen.directive.mjs +55 -0
  41. package/esm2022/lib/core/directives/resizable/resizable-dialog.directive.mjs +179 -0
  42. package/esm2022/lib/core/environments/environment.mjs +15 -0
  43. package/esm2022/lib/core/environments/environment.prod.mjs +15 -0
  44. package/esm2022/lib/core/helpers/crypto-helper.service.mjs +52 -0
  45. package/esm2022/lib/core/http/http-stream.service.mjs +97 -0
  46. package/esm2022/lib/core/http/http.service.mjs +103 -0
  47. package/esm2022/lib/core/interceptors/auth.interceptor.mjs +96 -0
  48. package/esm2022/lib/core/interceptors/license.interceptor.mjs +44 -0
  49. package/esm2022/lib/core/models/api-config.model.mjs +18 -0
  50. package/esm2022/lib/core/models/api-request.model.mjs +2 -0
  51. package/esm2022/lib/core/models/api-response.model.mjs +8 -0
  52. package/esm2022/lib/core/models/doohbot-config.model.mjs +18 -0
  53. package/esm2022/lib/core/models/license.model.mjs +2 -0
  54. package/esm2022/lib/core/models/message.mjs +2 -0
  55. package/esm2022/lib/core/models/theme-config.model.mjs +2 -0
  56. package/esm2022/lib/core/services/core-config.service.mjs +52 -0
  57. package/esm2022/lib/core/services/license.service.mjs +145 -0
  58. package/esm2022/lib/core/services/markdown.service.mjs +64 -0
  59. package/esm2022/lib/core/services/theme.service.mjs +248 -0
  60. package/esm2022/lib/core/types/auth-mode.type.mjs +2 -0
  61. package/esm2022/lib/core/types/auth-status.type.mjs +5 -0
  62. package/esm2022/lib/core/types/chat-stream.type.mjs +2 -0
  63. package/esm2022/lib/core/types/message-role.type.mjs +2 -0
  64. package/esm2022/lib/core/types/prompt-mode.type.mjs +5 -0
  65. package/esm2022/lib/core/types/snackbar-error.type.mjs +5 -0
  66. package/esm2022/lib/core/types/tenant-resolution-strategy.type.mjs +2 -0
  67. package/esm2022/lib/core/utils/logger.service.mjs +42 -0
  68. package/esm2022/lib/doohbot-input.mjs +20 -0
  69. package/esm2022/lib/doohbot.component.mjs +444 -0
  70. package/esm2022/lib/predefined_messages.mjs +15 -0
  71. package/esm2022/lib/shared/chips/chips.component.mjs +28 -0
  72. package/esm2022/lib/shared/dialog/dialog.component.mjs +36 -0
  73. package/esm2022/lib/shared/dialog/dialog.service.mjs +64 -0
  74. package/esm2022/lib/shared/dialog/dialog.utils.mjs +85 -0
  75. package/esm2022/lib/shared/dropdown-menu/dropdown-menu.component.mjs +29 -0
  76. package/esm2022/lib/shared/input-dialog/input-dialog.component.mjs +38 -0
  77. package/esm2022/lib/shared/menu-item/menu-item.component.mjs +24 -0
  78. package/esm2022/lib/shared/pipes/simple-markdown.pipe.mjs +27 -0
  79. package/esm2022/lib/shared/snackbar/snackbar.component.mjs +43 -0
  80. package/esm2022/lib/shared/snackbar/snackbar.service.mjs +46 -0
  81. package/esm2022/lib/shared/snackbar/snackbar.utils.mjs +43 -0
  82. package/esm2022/public-api.mjs +37 -0
  83. package/fesm2022/aakash58-chatbot.mjs +1037 -827
  84. package/fesm2022/aakash58-chatbot.mjs.map +1 -1
  85. package/index.d.ts +3 -373
  86. package/lib/app/chat/chat-ui-state.service.d.ts +96 -0
  87. package/lib/app/chat/chat.service.d.ts +88 -0
  88. package/lib/app/chat/components/chat-button/chat-button.component.d.ts +16 -0
  89. package/lib/app/chat/components/chat-footer/chat-footer.component.d.ts +5 -0
  90. package/lib/app/chat/components/chat-header/chat-header.component.d.ts +24 -0
  91. package/lib/app/chat/components/chat-history-sidebar/chat-history-sidebar.component.d.ts +49 -0
  92. package/lib/app/chat/components/chat-window/chat-window.component.d.ts +107 -0
  93. package/lib/app/chat/components/message-input/message-input.component.d.ts +12 -0
  94. package/lib/app/chat/components/message-list/message-list.component.d.ts +40 -0
  95. package/lib/app/chat/model/chat-history.model.d.ts +51 -0
  96. package/lib/app/chat/model/chat-request.model.d.ts +10 -0
  97. package/lib/app/chat/model/chat-response.model.d.ts +9 -0
  98. package/lib/app/chat/model/chat-session.model.d.ts +12 -0
  99. package/lib/app/chat/model/chat-stream-message.model.d.ts +5 -0
  100. package/lib/app/chat/model/chat-stream-response.model.d.ts +10 -0
  101. package/lib/app/chat/services/chat-api.service.d.ts +30 -0
  102. package/lib/app/chat/services/chat-audio.service.d.ts +19 -0
  103. package/lib/app/chat/services/chat-history.service.d.ts +53 -0
  104. package/lib/app/login/login-form.component.d.ts +20 -0
  105. package/lib/app/personalization/personalization-dialog.component.d.ts +53 -0
  106. package/lib/app/personalization/personalization.service.d.ts +66 -0
  107. package/lib/app/personalization/sections/account/account-section.component.d.ts +30 -0
  108. package/lib/app/personalization/sections/preferences/color-picker-dialog.component.d.ts +17 -0
  109. package/lib/app/personalization/sections/preferences/preferences-section.component.d.ts +27 -0
  110. package/lib/app/personalization/sections/profile/profile-section.component.d.ts +17 -0
  111. package/lib/app/personalization/sections/settings/setting-section.component.d.ts +10 -0
  112. package/lib/app/personalization/sections/terms/terms-section.component.d.ts +5 -0
  113. package/lib/constant/doohbot-constant.d.ts +12 -0
  114. package/lib/constant/html-entities.d.ts +8 -0
  115. package/lib/constant/utf8.d.ts +9 -0
  116. package/lib/core/app-const.d.ts +11 -0
  117. package/lib/core/auth/account-api.service.d.ts +20 -0
  118. package/lib/core/auth/auth.service.d.ts +90 -0
  119. package/lib/core/auth/models/auth-result.model.d.ts +4 -0
  120. package/lib/core/auth/models/federated-login-request.model.d.ts +5 -0
  121. package/lib/core/auth/models/login-request.model.d.ts +6 -0
  122. package/lib/core/auth/storage.service.d.ts +21 -0
  123. package/lib/core/directives/draggable/draggable-dialog.directive.d.ts +23 -0
  124. package/lib/core/directives/fullscreen/fullscreen.directive.d.ts +14 -0
  125. package/lib/core/directives/resizable/resizable-dialog.directive.d.ts +30 -0
  126. package/lib/core/environments/environment.d.ts +7 -0
  127. package/lib/core/environments/environment.prod.d.ts +7 -0
  128. package/lib/core/helpers/crypto-helper.service.d.ts +12 -0
  129. package/lib/core/http/http-stream.service.d.ts +18 -0
  130. package/lib/core/http/http.service.d.ts +20 -0
  131. package/lib/core/interceptors/auth.interceptor.d.ts +18 -0
  132. package/lib/core/interceptors/license.interceptor.d.ts +11 -0
  133. package/lib/core/models/api-config.model.d.ts +58 -0
  134. package/lib/core/models/api-request.model.d.ts +77 -0
  135. package/lib/core/models/api-response.model.d.ts +6 -0
  136. package/lib/core/models/doohbot-config.model.d.ts +81 -0
  137. package/lib/core/models/license.model.d.ts +23 -0
  138. package/lib/core/models/message.d.ts +16 -0
  139. package/lib/core/models/theme-config.model.d.ts +28 -0
  140. package/lib/core/services/core-config.service.d.ts +23 -0
  141. package/lib/core/services/license.service.d.ts +33 -0
  142. package/lib/core/services/markdown.service.d.ts +8 -0
  143. package/lib/core/services/theme.service.d.ts +40 -0
  144. package/lib/core/types/auth-mode.type.d.ts +4 -0
  145. package/lib/core/types/auth-status.type.d.ts +4 -0
  146. package/lib/core/types/chat-stream.type.d.ts +4 -0
  147. package/lib/core/types/message-role.type.d.ts +4 -0
  148. package/lib/core/types/prompt-mode.type.d.ts +4 -0
  149. package/lib/core/types/snackbar-error.type.d.ts +4 -0
  150. package/lib/core/types/tenant-resolution-strategy.type.d.ts +4 -0
  151. package/lib/core/utils/logger.service.d.ts +11 -0
  152. package/lib/doohbot-input.d.ts +19 -0
  153. package/lib/doohbot.component.d.ts +108 -0
  154. package/lib/predefined_messages.d.ts +2 -0
  155. package/lib/shared/chips/chips.component.d.ts +10 -0
  156. package/lib/shared/dialog/dialog.component.d.ts +19 -0
  157. package/lib/shared/dialog/dialog.service.d.ts +29 -0
  158. package/lib/shared/dialog/dialog.utils.d.ts +41 -0
  159. package/lib/shared/dropdown-menu/dropdown-menu.component.d.ts +11 -0
  160. package/lib/shared/input-dialog/input-dialog.component.d.ts +20 -0
  161. package/lib/shared/menu-item/menu-item.component.d.ts +9 -0
  162. package/lib/shared/pipes/simple-markdown.pipe.d.ts +10 -0
  163. package/lib/shared/snackbar/snackbar.component.d.ts +14 -0
  164. package/lib/shared/snackbar/snackbar.service.d.ts +19 -0
  165. package/lib/shared/snackbar/snackbar.utils.d.ts +33 -0
  166. package/package.json +4 -2
  167. package/public-api.d.ts +11 -0
@@ -0,0 +1,66 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { MatIconModule } from '@angular/material/icon';
4
+ import { MatMenuModule } from '@angular/material/menu';
5
+ import { ThemeService } from '../../../../core/services/theme.service';
6
+ import { inject } from '@angular/core';
7
+ import { ChatService } from '../../chat.service';
8
+ import Logger from '../../../../core/utils/logger.service';
9
+ import { ChatUIStateService } from '../../chat-ui-state.service';
10
+ import * as i0 from "@angular/core";
11
+ import * as i1 from "@angular/material/icon";
12
+ import * as i2 from "@angular/material/menu";
13
+ export class ChatHeaderComponent {
14
+ constructor() {
15
+ this.appHeaderLogoUrl = '';
16
+ this.isAuthenticated = false;
17
+ this.isFullScreen = false;
18
+ this.isNewChatDisabled = false;
19
+ this.toggleChat = new EventEmitter();
20
+ this.toggleFullScreen = new EventEmitter();
21
+ this.toggleHistorySidebar = new EventEmitter();
22
+ this.clearChat = new EventEmitter();
23
+ this.themeService = inject(ThemeService);
24
+ this.chatService = inject(ChatService);
25
+ this.uiState = inject(ChatUIStateService);
26
+ }
27
+ onToggleChat() {
28
+ this.toggleChat.emit();
29
+ }
30
+ onToggleHistorySidebar() {
31
+ this.toggleHistorySidebar.emit();
32
+ }
33
+ onToggleFullScreen() {
34
+ this.toggleFullScreen.emit();
35
+ }
36
+ onStartNewConversation() {
37
+ Logger.warn('Starting new conversation...');
38
+ this.chatService.startNewSession();
39
+ this.uiState.closeHistorySidebar();
40
+ }
41
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
42
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ChatHeaderComponent, isStandalone: true, selector: "app-chat-header", inputs: { appHeaderLogoUrl: "appHeaderLogoUrl", isAuthenticated: "isAuthenticated", isFullScreen: "isFullScreen", settingsMenu: "settingsMenu", isNewChatDisabled: "isNewChatDisabled" }, outputs: { toggleChat: "toggleChat", toggleFullScreen: "toggleFullScreen", toggleHistorySidebar: "toggleHistorySidebar", clearChat: "clearChat" }, ngImport: i0, template: "<div class=\"chat-header\">\r\n <div class=\"chat-title\">\r\n <img class=\"chat-logo\" style=\"width: 150px; height: 50px; margin-left: 0px\" [src]=\"appHeaderLogoUrl\"\r\n alt=\"Text-Logo\" />\r\n </div>\r\n\r\n <div class=\"chat-header-buttons\">\r\n <!-- History Button -->\r\n\r\n <!-- add chat Button -->\r\n @if (isAuthenticated) {\r\n <button class=\"header-button\" (click)=\"onStartNewConversation()\" title=\"Start new conversation\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n\r\n <!-- history Button -->\r\n @if (isAuthenticated) {\r\n <button class=\"header-button\" (click)=\"onToggleHistorySidebar()\" title=\"Chat History\">\r\n <mat-icon>history</mat-icon>\r\n </button>\r\n }\r\n\r\n <!-- more Button -->\r\n <button class=\"header-button\" [matMenuTriggerFor]=\"settingsMenu\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n\r\n <!-- minimize Button -->\r\n <button class=\"header-button\" (click)=\"onToggleChat()\">\r\n <mat-icon>minimize</mat-icon>\r\n </button>\r\n </div>\r\n</div>", styles: [".chat-header{display:flex;justify-content:space-between;align-items:center;padding:10px 20px;background-color:var(--background-color);color:var(--text-alt-color);-webkit-user-select:none;user-select:none}s .chat-title{display:flex;align-items:center;gap:6px;font-family:var(--font-family)}.chat-logo{width:45px;height:45px;object-fit:contain}.chat-header h2{margin:0;font-size:1.2rem;color:var(--mat-sys-on-primary);font-family:var(--font-family);font-weight:700}.chat-header-buttons{display:flex;flex-wrap:nowrap;gap:1px}.header-button{background:var(--background-color);border:1px solid var(--background-color);border-radius:50%;width:32px;height:32px;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text-color);transition:all .2s cubic-bezier(.25,.8,.25,1);outline:none}.header-button mat-icon{font-size:18px;width:18px;height:18px}.header-button:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(var(--black-rgb),.15)}.header-button:active{transform:translateY(0)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }] }); }
43
+ }
44
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatHeaderComponent, decorators: [{
45
+ type: Component,
46
+ args: [{ selector: 'app-chat-header', standalone: true, imports: [CommonModule, MatIconModule, MatMenuModule], template: "<div class=\"chat-header\">\r\n <div class=\"chat-title\">\r\n <img class=\"chat-logo\" style=\"width: 150px; height: 50px; margin-left: 0px\" [src]=\"appHeaderLogoUrl\"\r\n alt=\"Text-Logo\" />\r\n </div>\r\n\r\n <div class=\"chat-header-buttons\">\r\n <!-- History Button -->\r\n\r\n <!-- add chat Button -->\r\n @if (isAuthenticated) {\r\n <button class=\"header-button\" (click)=\"onStartNewConversation()\" title=\"Start new conversation\">\r\n <mat-icon>add</mat-icon>\r\n </button>\r\n }\r\n\r\n <!-- history Button -->\r\n @if (isAuthenticated) {\r\n <button class=\"header-button\" (click)=\"onToggleHistorySidebar()\" title=\"Chat History\">\r\n <mat-icon>history</mat-icon>\r\n </button>\r\n }\r\n\r\n <!-- more Button -->\r\n <button class=\"header-button\" [matMenuTriggerFor]=\"settingsMenu\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n\r\n <!-- minimize Button -->\r\n <button class=\"header-button\" (click)=\"onToggleChat()\">\r\n <mat-icon>minimize</mat-icon>\r\n </button>\r\n </div>\r\n</div>", styles: [".chat-header{display:flex;justify-content:space-between;align-items:center;padding:10px 20px;background-color:var(--background-color);color:var(--text-alt-color);-webkit-user-select:none;user-select:none}s .chat-title{display:flex;align-items:center;gap:6px;font-family:var(--font-family)}.chat-logo{width:45px;height:45px;object-fit:contain}.chat-header h2{margin:0;font-size:1.2rem;color:var(--mat-sys-on-primary);font-family:var(--font-family);font-weight:700}.chat-header-buttons{display:flex;flex-wrap:nowrap;gap:1px}.header-button{background:var(--background-color);border:1px solid var(--background-color);border-radius:50%;width:32px;height:32px;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text-color);transition:all .2s cubic-bezier(.25,.8,.25,1);outline:none}.header-button mat-icon{font-size:18px;width:18px;height:18px}.header-button:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(var(--black-rgb),.15)}.header-button:active{transform:translateY(0)}\n"] }]
47
+ }], propDecorators: { appHeaderLogoUrl: [{
48
+ type: Input
49
+ }], isAuthenticated: [{
50
+ type: Input
51
+ }], isFullScreen: [{
52
+ type: Input
53
+ }], settingsMenu: [{
54
+ type: Input
55
+ }], isNewChatDisabled: [{
56
+ type: Input
57
+ }], toggleChat: [{
58
+ type: Output
59
+ }], toggleFullScreen: [{
60
+ type: Output
61
+ }], toggleHistorySidebar: [{
62
+ type: Output
63
+ }], clearChat: [{
64
+ type: Output
65
+ }] } });
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1oZWFkZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZG9vaGJvdC9zcmMvbGliL2FwcC9jaGF0L2NvbXBvbmVudHMvY2hhdC1oZWFkZXIvY2hhdC1oZWFkZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZG9vaGJvdC9zcmMvbGliL2FwcC9jaGF0L2NvbXBvbmVudHMvY2hhdC1oZWFkZXIvY2hhdC1oZWFkZXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN2RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDdkUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN2QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDakQsT0FBTyxNQUFNLE1BQU0sdUNBQXVDLENBQUM7QUFDM0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7Ozs7QUFVakUsTUFBTSxPQUFPLG1CQUFtQjtJQVBoQztRQVFXLHFCQUFnQixHQUFXLEVBQUUsQ0FBQztRQUM5QixvQkFBZSxHQUFZLEtBQUssQ0FBQztRQUNqQyxpQkFBWSxHQUFZLEtBQUssQ0FBQztRQUU5QixzQkFBaUIsR0FBWSxLQUFLLENBQUM7UUFFbEMsZUFBVSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7UUFDdEMscUJBQWdCLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUM1Qyx5QkFBb0IsR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBQ2hELGNBQVMsR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBRXhDLGlCQUFZLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3BDLGdCQUFXLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ2pDLFlBQU8sR0FBRyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztLQW1COUM7SUFqQkMsWUFBWTtRQUNWLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDekIsQ0FBQztJQUVELHNCQUFzQjtRQUNwQixJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDbkMsQ0FBQztJQUVELGtCQUFrQjtRQUNoQixJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVELHNCQUFzQjtRQUNwQixNQUFNLENBQUMsSUFBSSxDQUFDLDhCQUE4QixDQUFDLENBQUM7UUFDNUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsT0FBTyxDQUFDLG1CQUFtQixFQUFFLENBQUM7SUFDckMsQ0FBQzsrR0FoQ1UsbUJBQW1CO21HQUFuQixtQkFBbUIsd1pDbEJoQyxtbENBaUNNLHlqQ0RuQk0sWUFBWSw4QkFBRSxhQUFhLG1MQUFFLGFBQWE7OzRGQUl6QyxtQkFBbUI7a0JBUC9CLFNBQVM7K0JBQ0UsaUJBQWlCLGNBQ2YsSUFBSSxXQUNQLENBQUMsWUFBWSxFQUFFLGFBQWEsRUFBRSxhQUFhLENBQUM7OEJBSzVDLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxpQkFBaUI7c0JBQXpCLEtBQUs7Z0JBRUksVUFBVTtzQkFBbkIsTUFBTTtnQkFDRyxnQkFBZ0I7c0JBQXpCLE1BQU07Z0JBQ0csb0JBQW9CO3NCQUE3QixNQUFNO2dCQUNHLFNBQVM7c0JBQWxCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE91dHB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQgeyBNYXRJY29uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaWNvbic7XHJcbmltcG9ydCB7IE1hdE1lbnVNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9tZW51JztcclxuaW1wb3J0IHsgVGhlbWVTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9zZXJ2aWNlcy90aGVtZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENoYXRTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vY2hhdC5zZXJ2aWNlJztcclxuaW1wb3J0IExvZ2dlciBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL3V0aWxzL2xvZ2dlci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgQ2hhdFVJU3RhdGVTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vY2hhdC11aS1zdGF0ZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgU25hY2tiYXJVdGlscyB9IGZyb20gJy4uLy4uLy4uLy4uL3NoYXJlZC9zbmFja2Jhci9zbmFja2Jhci51dGlscyc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2FwcC1jaGF0LWhlYWRlcicsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBNYXRJY29uTW9kdWxlLCBNYXRNZW51TW9kdWxlXSxcclxuICB0ZW1wbGF0ZVVybDogJy4vY2hhdC1oZWFkZXIuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL2NoYXQtaGVhZGVyLmNvbXBvbmVudC5zY3NzJ10sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBDaGF0SGVhZGVyQ29tcG9uZW50IHtcclxuICBASW5wdXQoKSBhcHBIZWFkZXJMb2dvVXJsOiBzdHJpbmcgPSAnJztcclxuICBASW5wdXQoKSBpc0F1dGhlbnRpY2F0ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuICBASW5wdXQoKSBpc0Z1bGxTY3JlZW46IGJvb2xlYW4gPSBmYWxzZTtcclxuICBASW5wdXQoKSBzZXR0aW5nc01lbnU6IGFueTtcclxuICBASW5wdXQoKSBpc05ld0NoYXREaXNhYmxlZDogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICBAT3V0cHV0KCkgdG9nZ2xlQ2hhdCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuICBAT3V0cHV0KCkgdG9nZ2xlRnVsbFNjcmVlbiA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuICBAT3V0cHV0KCkgdG9nZ2xlSGlzdG9yeVNpZGViYXIgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcbiAgQE91dHB1dCgpIGNsZWFyQ2hhdCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgcHVibGljIHRoZW1lU2VydmljZSA9IGluamVjdChUaGVtZVNlcnZpY2UpO1xyXG4gIHB1YmxpYyBjaGF0U2VydmljZSA9IGluamVjdChDaGF0U2VydmljZSk7XHJcbiAgcHJpdmF0ZSB1aVN0YXRlID0gaW5qZWN0KENoYXRVSVN0YXRlU2VydmljZSk7XHJcblxyXG4gIG9uVG9nZ2xlQ2hhdCgpIHtcclxuICAgIHRoaXMudG9nZ2xlQ2hhdC5lbWl0KCk7XHJcbiAgfVxyXG5cclxuICBvblRvZ2dsZUhpc3RvcnlTaWRlYmFyKCkge1xyXG4gICAgdGhpcy50b2dnbGVIaXN0b3J5U2lkZWJhci5lbWl0KCk7XHJcbiAgfVxyXG5cclxuICBvblRvZ2dsZUZ1bGxTY3JlZW4oKSB7XHJcbiAgICB0aGlzLnRvZ2dsZUZ1bGxTY3JlZW4uZW1pdCgpO1xyXG4gIH1cclxuXHJcbiAgb25TdGFydE5ld0NvbnZlcnNhdGlvbigpIHtcclxuICAgIExvZ2dlci53YXJuKCdTdGFydGluZyBuZXcgY29udmVyc2F0aW9uLi4uJyk7XHJcbiAgICB0aGlzLmNoYXRTZXJ2aWNlLnN0YXJ0TmV3U2Vzc2lvbigpO1xyXG4gICAgdGhpcy51aVN0YXRlLmNsb3NlSGlzdG9yeVNpZGViYXIoKTtcclxuICB9XHJcbn1cclxuIiwiPGRpdiBjbGFzcz1cImNoYXQtaGVhZGVyXCI+XHJcbiAgPGRpdiBjbGFzcz1cImNoYXQtdGl0bGVcIj5cclxuICAgIDxpbWcgY2xhc3M9XCJjaGF0LWxvZ29cIiBzdHlsZT1cIndpZHRoOiAxNTBweDsgaGVpZ2h0OiA1MHB4OyBtYXJnaW4tbGVmdDogMHB4XCIgW3NyY109XCJhcHBIZWFkZXJMb2dvVXJsXCJcclxuICAgICAgYWx0PVwiVGV4dC1Mb2dvXCIgLz5cclxuICA8L2Rpdj5cclxuXHJcbiAgPGRpdiBjbGFzcz1cImNoYXQtaGVhZGVyLWJ1dHRvbnNcIj5cclxuICAgIDwhLS0gSGlzdG9yeSBCdXR0b24gLS0+XHJcblxyXG4gICAgPCEtLSBhZGQgY2hhdCBCdXR0b24gLS0+XHJcbiAgICBAaWYgKGlzQXV0aGVudGljYXRlZCkge1xyXG4gICAgPGJ1dHRvbiBjbGFzcz1cImhlYWRlci1idXR0b25cIiAoY2xpY2spPVwib25TdGFydE5ld0NvbnZlcnNhdGlvbigpXCIgdGl0bGU9XCJTdGFydCBuZXcgY29udmVyc2F0aW9uXCI+XHJcbiAgICAgIDxtYXQtaWNvbj5hZGQ8L21hdC1pY29uPlxyXG4gICAgPC9idXR0b24+XHJcbiAgICB9XHJcblxyXG4gICAgPCEtLSBoaXN0b3J5IEJ1dHRvbiAtLT5cclxuICAgIEBpZiAoaXNBdXRoZW50aWNhdGVkKSB7XHJcbiAgICA8YnV0dG9uIGNsYXNzPVwiaGVhZGVyLWJ1dHRvblwiIChjbGljayk9XCJvblRvZ2dsZUhpc3RvcnlTaWRlYmFyKClcIiB0aXRsZT1cIkNoYXQgSGlzdG9yeVwiPlxyXG4gICAgICA8bWF0LWljb24+aGlzdG9yeTwvbWF0LWljb24+XHJcbiAgICA8L2J1dHRvbj5cclxuICAgIH1cclxuXHJcbiAgICA8IS0tIG1vcmUgQnV0dG9uIC0tPlxyXG4gICAgPGJ1dHRvbiBjbGFzcz1cImhlYWRlci1idXR0b25cIiBbbWF0TWVudVRyaWdnZXJGb3JdPVwic2V0dGluZ3NNZW51XCI+XHJcbiAgICAgIDxtYXQtaWNvbj5tb3JlX3ZlcnQ8L21hdC1pY29uPlxyXG4gICAgPC9idXR0b24+XHJcblxyXG4gICAgPCEtLSBtaW5pbWl6ZSBCdXR0b24gLS0+XHJcbiAgICA8YnV0dG9uIGNsYXNzPVwiaGVhZGVyLWJ1dHRvblwiIChjbGljayk9XCJvblRvZ2dsZUNoYXQoKVwiPlxyXG4gICAgICA8bWF0LWljb24+bWluaW1pemU8L21hdC1pY29uPlxyXG4gICAgPC9idXR0b24+XHJcbiAgPC9kaXY+XHJcbjwvZGl2PiJdfQ==
@@ -0,0 +1,186 @@
1
+ import { Component, EventEmitter, Input, Output, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { MatIconModule } from '@angular/material/icon';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "../../../../shared/dialog/dialog.service";
6
+ import * as i2 from "@angular/material/icon";
7
+ export class ChatHistorySidebarComponent {
8
+ constructor(dialogService) {
9
+ this.dialogService = dialogService;
10
+ this.sessions = [];
11
+ this.isOpen = false;
12
+ this.userName = 'User';
13
+ this.isLoading = false;
14
+ this.hasMoreSessions = false;
15
+ this.isLoadingMore = false;
16
+ this.processingSessionId = null;
17
+ this.sessionSelected = new EventEmitter();
18
+ this.sessionDeleted = new EventEmitter();
19
+ this.closed = new EventEmitter();
20
+ this.loadMore = new EventEmitter();
21
+ this.refresh = new EventEmitter();
22
+ this.sessionRenamed = new EventEmitter();
23
+ this.deleteAll = new EventEmitter();
24
+ this.chatHistory = [];
25
+ }
26
+ ngOnInit() {
27
+ this.chatHistory = this.groupedSessions();
28
+ }
29
+ ngOnChanges(changes) {
30
+ if (changes['sessions']) {
31
+ this.chatHistory = this.groupedSessions();
32
+ }
33
+ }
34
+ groupedSessions() {
35
+ const now = new Date();
36
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
37
+ const yesterday = new Date(today);
38
+ yesterday.setDate(yesterday.getDate() - 1);
39
+ const weekAgo = new Date(today);
40
+ weekAgo.setDate(weekAgo.getDate() - 7);
41
+ const groups = [
42
+ { label: 'Today', sessions: [] },
43
+ { label: 'Yesterday', sessions: [] },
44
+ { label: 'This Week', sessions: [] },
45
+ { label: 'Older', sessions: [] },
46
+ ];
47
+ // Sort sessions by timestamp (newest first)
48
+ const sortedSessions = [...this.sessions].sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
49
+ sortedSessions.forEach((session) => {
50
+ const sessionDate = new Date(session.timestamp);
51
+ const sessionDayStart = new Date(sessionDate.getFullYear(), sessionDate.getMonth(), sessionDate.getDate());
52
+ if (sessionDayStart.getTime() === today.getTime()) {
53
+ groups[0].sessions.push(session);
54
+ }
55
+ else if (sessionDayStart.getTime() === yesterday.getTime()) {
56
+ groups[1].sessions.push(session);
57
+ }
58
+ else if (sessionDayStart.getTime() >= weekAgo.getTime()) {
59
+ groups[2].sessions.push(session);
60
+ }
61
+ else {
62
+ groups[3].sessions.push(session);
63
+ }
64
+ });
65
+ // Filter out empty groups
66
+ return groups.filter((g) => g.sessions.length > 0);
67
+ }
68
+ onSessionClick(session) {
69
+ this.sessionSelected.emit(session);
70
+ }
71
+ onEditClick(event, session) {
72
+ event.stopPropagation();
73
+ this.dialogService
74
+ .openInput({
75
+ title: 'Rename Conversation',
76
+ message: 'Enter a new title for this conversation:',
77
+ initialValue: session.title,
78
+ placeholder: 'New title...',
79
+ confirmText: 'Rename',
80
+ })
81
+ .subscribe((newTitle) => {
82
+ if (newTitle !== null && newTitle.trim() !== '' && newTitle !== session.title) {
83
+ this.sessionRenamed.emit({ sessionId: session.id, newTitle: newTitle.trim() });
84
+ }
85
+ });
86
+ }
87
+ onDeleteClick(event, sessionId) {
88
+ event.stopPropagation();
89
+ this.dialogService.confirmDelete('this conversation').subscribe((confirmed) => {
90
+ if (confirmed) {
91
+ this.sessionDeleted.emit(sessionId);
92
+ this.chatHistory = this.groupedSessions();
93
+ }
94
+ });
95
+ }
96
+ onClose() {
97
+ this.closed.emit();
98
+ }
99
+ formatTime(date) {
100
+ return new Date(date).toLocaleTimeString('en-US', {
101
+ hour: 'numeric',
102
+ minute: '2-digit',
103
+ hour12: true,
104
+ });
105
+ }
106
+ formatDate(date) {
107
+ return new Date(date).toLocaleDateString('en-US', {
108
+ month: 'short',
109
+ day: 'numeric',
110
+ });
111
+ }
112
+ /**
113
+ * Handle scroll event for infinite scroll
114
+ */
115
+ onScroll(event) {
116
+ const element = event.target;
117
+ const scrollTop = element.scrollTop;
118
+ const scrollHeight = element.scrollHeight;
119
+ const clientHeight = element.clientHeight;
120
+ // Check if scrolled near bottom (within 100px)
121
+ const scrollBottom = scrollHeight - scrollTop - clientHeight;
122
+ if (scrollBottom < 100 && this.hasMoreSessions && !this.isLoadingMore && !this.isLoading) {
123
+ this.loadMore.emit();
124
+ }
125
+ }
126
+ /**
127
+ * Handle manual refresh
128
+ */
129
+ onRefresh() {
130
+ this.refresh.emit();
131
+ }
132
+ /**
133
+ * Handle clear all history
134
+ */
135
+ onClearAllClick() {
136
+ this.dialogService
137
+ .open({
138
+ title: 'Clear All History',
139
+ message: 'Are you sure you want to delete all chat history? This action cannot be undone.',
140
+ confirmText: 'Clear All',
141
+ cancelText: 'Cancel',
142
+ confirmButtonColor: 'warn',
143
+ icon: 'delete_sweep',
144
+ })
145
+ .subscribe((confirmed) => {
146
+ if (confirmed) {
147
+ this.deleteAll.emit();
148
+ }
149
+ });
150
+ }
151
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatHistorySidebarComponent, deps: [{ token: i1.DialogService }], target: i0.ɵɵFactoryTarget.Component }); }
152
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ChatHistorySidebarComponent, isStandalone: true, selector: "app-chat-history-sidebar", inputs: { sessions: "sessions", isOpen: "isOpen", userName: "userName", isLoading: "isLoading", hasMoreSessions: "hasMoreSessions", isLoadingMore: "isLoadingMore", processingSessionId: "processingSessionId" }, outputs: { sessionSelected: "sessionSelected", sessionDeleted: "sessionDeleted", closed: "closed", loadMore: "loadMore", refresh: "refresh", sessionRenamed: "sessionRenamed", deleteAll: "deleteAll" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"history-sidebar\" [class.open]=\"isOpen\">\r\n <div class=\"sidebar-header\">\r\n <div class=\"marquee-container\" style=\"flex: 1; margin-right: 10px\">\r\n <h3 class=\"marquee-text\">{{ userName }}'s Chat History</h3>\r\n </div>\r\n <button class=\"refresh-btn\" (click)=\"onRefresh()\" title=\"Refresh history\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n\r\n <button class=\"close-btn\" (click)=\"onClose()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"sidebar-content\" (scroll)=\"onScroll($event)\">\r\n @if (isLoading) {\r\n <div class=\"loader-container\">\r\n <div class=\"loader\"></div>\r\n <p>Loading history...</p>\r\n </div>\r\n }\r\n\r\n @if (!isLoading && sessions.length === 0) {\r\n <div class=\"empty-state\">\r\n <mat-icon>history</mat-icon>\r\n <p>No chat history yet</p>\r\n <span>Start a conversation to see it here</span>\r\n </div>\r\n }\r\n\r\n @if (!isLoading) {\r\n @for (group of chatHistory; track group.label) {\r\n <div class=\"session-group\">\r\n <div class=\"group-label\">{{ group.label }}</div>\r\n <div class=\"session-list\">\r\n @for (session of group.sessions; track session.id) {\r\n <div class=\"session-item\" (click)=\"onSessionClick(session)\">\r\n <div class=\"session-content\">\r\n <div class=\"session-title\">{{ session.title }}</div>\r\n <div class=\"session-time\">\r\n {{ formatTime(session.timestamp) }} \u00B7 {{ formatDate(session.timestamp) }}\r\n </div>\r\n </div>\r\n <div class=\"session-actions\">\r\n <button class=\"edit-btn\" [disabled]=\"processingSessionId === session.id\"\r\n (click)=\"onEditClick($event, session)\" title=\"Edit title\">\r\n @if (processingSessionId !== session.id) {\r\n <mat-icon>edit</mat-icon>\r\n } @else {\r\n <div class=\"loader-tiny\"></div>\r\n }\r\n </button>\r\n <button class=\"delete-btn\" [disabled]=\"processingSessionId === session.id\"\r\n (click)=\"onDeleteClick($event, session.id)\" title=\"Delete conversation\">\r\n @if (processingSessionId !== session.id) {\r\n <mat-icon>delete</mat-icon>\r\n } @else {\r\n <div class=\"loader-tiny\"></div>\r\n }\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Loading more indicator -->\r\n @if (isLoadingMore) {\r\n <div class=\"loading-more\">\r\n <div class=\"loader-small\"></div>\r\n <p>Loading more...</p>\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;height:100%;width:100%}.history-sidebar{top:0;right:0;display:none;height:100%;width:100%;background:var(--background-color);flex-direction:column}.history-sidebar.open{display:flex}.sidebar-header{display:flex;justify-content:space-between;align-items:center;padding:20px;border-bottom:1px solid var(--border-color)}.sidebar-header h3{margin:0;font-size:16px;font-weight:600;color:var(--text-color);font-family:var(--font-family);display:inline-block}.sidebar-content{flex:1 1 auto;overflow-y:auto;padding:10px 0;scroll-behavior:smooth}.close-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:background .2s}.close-btn:hover{background:var(--bot-message-color)}.close-btn mat-icon{color:var(--text-color);font-size:20px;width:20px;height:20px}.refresh-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:background .2s;margin-right:8px}.refresh-btn:hover{background:var(--bot-message-color)}.refresh-btn mat-icon{color:var(--text-color);font-size:20px;width:20px;height:20px}.clear-all-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:background .2s;margin-right:8px}.clear-all-btn:hover{background:var(--bot-message-color)}.clear-all-btn mat-icon{color:var(--text-color);font-size:20px;width:20px;height:20px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;text-align:center}.empty-state mat-icon{font-size:64px;width:64px;height:64px;color:var(--secondary-text-color);margin-bottom:16px}.empty-state p{margin:0 0 8px;font-size:16px;font-weight:500;color:var(--text-color);font-family:var(--font-family)}.empty-state span{font-size:14px;color:var(--secondary-text-color);font-family:var(--font-family)}.session-group{margin-bottom:24px}.group-label{padding:8px 20px;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--secondary-text-color);font-family:var(--font-family)}.session-list{display:flex;flex-direction:column}.session-item{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;cursor:pointer;transition:background .2s;gap:8px}.session-item:hover{background:var(--bot-message-color)}.session-content{flex:1;min-width:0}.session-title{font-size:14px;font-weight:500;color:var(--text-color);font-family:var(--font-family);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:4px}.session-time{font-size:12px;color:var(--secondary-text-color);font-family:var(--font-family)}.session-actions{display:flex;gap:4px;opacity:0;transition:opacity .2s}.session-item:hover .session-actions{opacity:1}.edit-btn,.delete-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all .2s}.edit-btn:hover{background:var(--bot-message-color)}.delete-btn:hover{background:var(--light-red)}.edit-btn mat-icon,.delete-btn mat-icon{color:var(--secondary-text-color);font-size:18px;width:18px;height:18px}.edit-btn:hover mat-icon{color:var(--primary-color)}.delete-btn:hover mat-icon{color:var(--red)}.sidebar-content::-webkit-scrollbar{width:6px}.sidebar-content::-webkit-scrollbar-track{background:transparent}.sidebar-content::-webkit-scrollbar-thumb{background:rgba(var(--black-rgb),.1);border-radius:10px}.sidebar-content::-webkit-scrollbar-thumb:hover{background:rgba(var(--black-rgb),.1);border-radius:10px}.loader-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;color:var(--secondary-text-color)}.loader-container p{margin-top:15px;font-size:14px;font-weight:500}.loader{width:32px;height:32px;border:3px solid rgba(var(--border-color-rgb),.1);border-radius:50%;border-top-color:var(--primary-color);animation:spin 1s ease-in-out infinite}@keyframes spin{to{transform:rotate(360deg)}}.loading-more{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;color:var(--secondary-text-color)}.loading-more p{margin-top:10px;font-size:13px;font-weight:500}.loader-small{width:24px;height:24px;border:3px solid rgba(var(--border-color-rgb),.1);border-radius:50%;border-top-color:var(--primary-color);animation:spin 1s ease-in-out infinite}.loader-tiny{width:14px;height:14px;border:2px solid rgba(var(--border-color-rgb),.1);border-radius:50%;border-top-color:var(--primary-color);animation:spin 1s ease-in-out infinite}.edit-btn:disabled,.delete-btn:disabled{cursor:not-allowed;opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] }); }
153
+ }
154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatHistorySidebarComponent, decorators: [{
155
+ type: Component,
156
+ args: [{ selector: 'app-chat-history-sidebar', standalone: true, imports: [CommonModule, MatIconModule], template: "<div class=\"history-sidebar\" [class.open]=\"isOpen\">\r\n <div class=\"sidebar-header\">\r\n <div class=\"marquee-container\" style=\"flex: 1; margin-right: 10px\">\r\n <h3 class=\"marquee-text\">{{ userName }}'s Chat History</h3>\r\n </div>\r\n <button class=\"refresh-btn\" (click)=\"onRefresh()\" title=\"Refresh history\">\r\n <mat-icon>refresh</mat-icon>\r\n </button>\r\n\r\n <button class=\"close-btn\" (click)=\"onClose()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"sidebar-content\" (scroll)=\"onScroll($event)\">\r\n @if (isLoading) {\r\n <div class=\"loader-container\">\r\n <div class=\"loader\"></div>\r\n <p>Loading history...</p>\r\n </div>\r\n }\r\n\r\n @if (!isLoading && sessions.length === 0) {\r\n <div class=\"empty-state\">\r\n <mat-icon>history</mat-icon>\r\n <p>No chat history yet</p>\r\n <span>Start a conversation to see it here</span>\r\n </div>\r\n }\r\n\r\n @if (!isLoading) {\r\n @for (group of chatHistory; track group.label) {\r\n <div class=\"session-group\">\r\n <div class=\"group-label\">{{ group.label }}</div>\r\n <div class=\"session-list\">\r\n @for (session of group.sessions; track session.id) {\r\n <div class=\"session-item\" (click)=\"onSessionClick(session)\">\r\n <div class=\"session-content\">\r\n <div class=\"session-title\">{{ session.title }}</div>\r\n <div class=\"session-time\">\r\n {{ formatTime(session.timestamp) }} \u00B7 {{ formatDate(session.timestamp) }}\r\n </div>\r\n </div>\r\n <div class=\"session-actions\">\r\n <button class=\"edit-btn\" [disabled]=\"processingSessionId === session.id\"\r\n (click)=\"onEditClick($event, session)\" title=\"Edit title\">\r\n @if (processingSessionId !== session.id) {\r\n <mat-icon>edit</mat-icon>\r\n } @else {\r\n <div class=\"loader-tiny\"></div>\r\n }\r\n </button>\r\n <button class=\"delete-btn\" [disabled]=\"processingSessionId === session.id\"\r\n (click)=\"onDeleteClick($event, session.id)\" title=\"Delete conversation\">\r\n @if (processingSessionId !== session.id) {\r\n <mat-icon>delete</mat-icon>\r\n } @else {\r\n <div class=\"loader-tiny\"></div>\r\n }\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Loading more indicator -->\r\n @if (isLoadingMore) {\r\n <div class=\"loading-more\">\r\n <div class=\"loader-small\"></div>\r\n <p>Loading more...</p>\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: [":host{display:block;height:100%;width:100%}.history-sidebar{top:0;right:0;display:none;height:100%;width:100%;background:var(--background-color);flex-direction:column}.history-sidebar.open{display:flex}.sidebar-header{display:flex;justify-content:space-between;align-items:center;padding:20px;border-bottom:1px solid var(--border-color)}.sidebar-header h3{margin:0;font-size:16px;font-weight:600;color:var(--text-color);font-family:var(--font-family);display:inline-block}.sidebar-content{flex:1 1 auto;overflow-y:auto;padding:10px 0;scroll-behavior:smooth}.close-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:background .2s}.close-btn:hover{background:var(--bot-message-color)}.close-btn mat-icon{color:var(--text-color);font-size:20px;width:20px;height:20px}.refresh-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:background .2s;margin-right:8px}.refresh-btn:hover{background:var(--bot-message-color)}.refresh-btn mat-icon{color:var(--text-color);font-size:20px;width:20px;height:20px}.clear-all-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:background .2s;margin-right:8px}.clear-all-btn:hover{background:var(--bot-message-color)}.clear-all-btn mat-icon{color:var(--text-color);font-size:20px;width:20px;height:20px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;text-align:center}.empty-state mat-icon{font-size:64px;width:64px;height:64px;color:var(--secondary-text-color);margin-bottom:16px}.empty-state p{margin:0 0 8px;font-size:16px;font-weight:500;color:var(--text-color);font-family:var(--font-family)}.empty-state span{font-size:14px;color:var(--secondary-text-color);font-family:var(--font-family)}.session-group{margin-bottom:24px}.group-label{padding:8px 20px;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--secondary-text-color);font-family:var(--font-family)}.session-list{display:flex;flex-direction:column}.session-item{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;cursor:pointer;transition:background .2s;gap:8px}.session-item:hover{background:var(--bot-message-color)}.session-content{flex:1;min-width:0}.session-title{font-size:14px;font-weight:500;color:var(--text-color);font-family:var(--font-family);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:4px}.session-time{font-size:12px;color:var(--secondary-text-color);font-family:var(--font-family)}.session-actions{display:flex;gap:4px;opacity:0;transition:opacity .2s}.session-item:hover .session-actions{opacity:1}.edit-btn,.delete-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all .2s}.edit-btn:hover{background:var(--bot-message-color)}.delete-btn:hover{background:var(--light-red)}.edit-btn mat-icon,.delete-btn mat-icon{color:var(--secondary-text-color);font-size:18px;width:18px;height:18px}.edit-btn:hover mat-icon{color:var(--primary-color)}.delete-btn:hover mat-icon{color:var(--red)}.sidebar-content::-webkit-scrollbar{width:6px}.sidebar-content::-webkit-scrollbar-track{background:transparent}.sidebar-content::-webkit-scrollbar-thumb{background:rgba(var(--black-rgb),.1);border-radius:10px}.sidebar-content::-webkit-scrollbar-thumb:hover{background:rgba(var(--black-rgb),.1);border-radius:10px}.loader-container{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;color:var(--secondary-text-color)}.loader-container p{margin-top:15px;font-size:14px;font-weight:500}.loader{width:32px;height:32px;border:3px solid rgba(var(--border-color-rgb),.1);border-radius:50%;border-top-color:var(--primary-color);animation:spin 1s ease-in-out infinite}@keyframes spin{to{transform:rotate(360deg)}}.loading-more{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;color:var(--secondary-text-color)}.loading-more p{margin-top:10px;font-size:13px;font-weight:500}.loader-small{width:24px;height:24px;border:3px solid rgba(var(--border-color-rgb),.1);border-radius:50%;border-top-color:var(--primary-color);animation:spin 1s ease-in-out infinite}.loader-tiny{width:14px;height:14px;border:2px solid rgba(var(--border-color-rgb),.1);border-radius:50%;border-top-color:var(--primary-color);animation:spin 1s ease-in-out infinite}.edit-btn:disabled,.delete-btn:disabled{cursor:not-allowed;opacity:.6}\n"] }]
157
+ }], ctorParameters: () => [{ type: i1.DialogService }], propDecorators: { sessions: [{
158
+ type: Input
159
+ }], isOpen: [{
160
+ type: Input
161
+ }], userName: [{
162
+ type: Input
163
+ }], isLoading: [{
164
+ type: Input
165
+ }], hasMoreSessions: [{
166
+ type: Input
167
+ }], isLoadingMore: [{
168
+ type: Input
169
+ }], processingSessionId: [{
170
+ type: Input
171
+ }], sessionSelected: [{
172
+ type: Output
173
+ }], sessionDeleted: [{
174
+ type: Output
175
+ }], closed: [{
176
+ type: Output
177
+ }], loadMore: [{
178
+ type: Output
179
+ }], refresh: [{
180
+ type: Output
181
+ }], sessionRenamed: [{
182
+ type: Output
183
+ }], deleteAll: [{
184
+ type: Output
185
+ }] } });
186
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1oaXN0b3J5LXNpZGViYXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZG9vaGJvdC9zcmMvbGliL2FwcC9jaGF0L2NvbXBvbmVudHMvY2hhdC1oaXN0b3J5LXNpZGViYXIvY2hhdC1oaXN0b3J5LXNpZGViYXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZG9vaGJvdC9zcmMvbGliL2FwcC9jaGF0L2NvbXBvbmVudHMvY2hhdC1oaXN0b3J5LXNpZGViYXIvY2hhdC1oaXN0b3J5LXNpZGViYXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUlMLE1BQU0sR0FDUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDOzs7O0FBV3ZELE1BQU0sT0FBTywyQkFBMkI7SUFtQnRDLFlBQW9CLGFBQTRCO1FBQTVCLGtCQUFhLEdBQWIsYUFBYSxDQUFlO1FBbEJ2QyxhQUFRLEdBQWtCLEVBQUUsQ0FBQztRQUM3QixXQUFNLEdBQVksS0FBSyxDQUFDO1FBQ3hCLGFBQVEsR0FBVyxNQUFNLENBQUM7UUFDMUIsY0FBUyxHQUFZLEtBQUssQ0FBQztRQUMzQixvQkFBZSxHQUFZLEtBQUssQ0FBQztRQUNqQyxrQkFBYSxHQUFZLEtBQUssQ0FBQztRQUMvQix3QkFBbUIsR0FBa0IsSUFBSSxDQUFDO1FBRXpDLG9CQUFlLEdBQUcsSUFBSSxZQUFZLEVBQWUsQ0FBQztRQUNsRCxtQkFBYyxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFDNUMsV0FBTSxHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7UUFDbEMsYUFBUSxH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QUFNO2dCQUNHLE1BQU07c0JBQWYsTUFBTTtnQkFDRyxRQUFRO3NCQUFqQixNQUFNO2dCQUNHLE9BQU87c0JBQWhCLE1BQU07Z0JBQ0csY0FBYztzQkFBdkIsTUFBTTtnQkFDRyxTQUFTO3NCQUFsQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgRXZlbnRFbWl0dGVyLFxyXG4gIElucHV0LFxyXG4gIE9uSW5pdCxcclxuICBPbkNoYW5nZXMsXHJcbiAgU2ltcGxlQ2hhbmdlcyxcclxuICBPdXRwdXQsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IE1hdEljb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pY29uJztcclxuaW1wb3J0IHsgRGlhbG9nU2VydmljZSB9IGZyb20gJy4uLy4uLy4uLy4uL3NoYXJlZC9kaWFsb2cvZGlhbG9nLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBDaGF0U2Vzc2lvbiwgQ2hhdFNlc3Npb25Hcm91cCB9IGZyb20gJy4uLy4uL21vZGVsL2NoYXQtc2Vzc2lvbi5tb2RlbCc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2FwcC1jaGF0LWhpc3Rvcnktc2lkZWJhcicsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBNYXRJY29uTW9kdWxlXSxcclxuICB0ZW1wbGF0ZVVybDogJy4vY2hhdC1oaXN0b3J5LXNpZGViYXIuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL2NoYXQtaGlzdG9yeS1zaWRlYmFyLmNvbXBvbmVudC5zY3NzJ10sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBDaGF0SGlzdG9yeVNpZGViYXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XHJcbiAgQElucHV0KCkgc2Vzc2lvbnM6IENoYXRTZXNzaW9uW10gPSBbXTtcclxuICBASW5wdXQoKSBpc09wZW46IGJvb2xlYW4gPSBmYWxzZTtcclxuICBASW5wdXQoKSB1c2VyTmFtZTogc3RyaW5nID0gJ1VzZXInO1xyXG4gIEBJbnB1dCgpIGlzTG9hZGluZzogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIGhhc01vcmVTZXNzaW9uczogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIGlzTG9hZGluZ01vcmU6IGJvb2xlYW4gPSBmYWxzZTtcclxuICBASW5wdXQoKSBwcm9jZXNzaW5nU2Vzc2lvbklkOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcclxuXHJcbiAgQE91dHB1dCgpIHNlc3Npb25TZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8Q2hhdFNlc3Npb24+KCk7XHJcbiAgQE91dHB1dCgpIHNlc3Npb25EZWxldGVkID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XHJcbiAgQE91dHB1dCgpIGNsb3NlZCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuICBAT3V0cHV0KCkgbG9hZE1vcmUgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcbiAgQE91dHB1dCgpIHJlZnJlc2ggPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcbiAgQE91dHB1dCgpIHNlc3Npb25SZW5hbWVkID0gbmV3IEV2ZW50RW1pdHRlcjx7IHNlc3Npb25JZDogc3RyaW5nOyBuZXdUaXRsZTogc3RyaW5nIH0+KCk7XHJcbiAgQE91dHB1dCgpIGRlbGV0ZUFsbCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuXHJcbiAgY2hhdEhpc3Rvcnk6IENoYXRTZXNzaW9uR3JvdXBbXSA9IFtdO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGRpYWxvZ1NlcnZpY2U6IERpYWxvZ1NlcnZpY2UpIHsgfVxyXG5cclxuICBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgIHRoaXMuY2hhdEhpc3RvcnkgPSB0aGlzLmdyb3VwZWRTZXNzaW9ucygpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xyXG4gICAgaWYgKGNoYW5nZXNbJ3Nlc3Npb25zJ10pIHtcclxuICAgICAgdGhpcy5jaGF0SGlzdG9yeSA9IHRoaXMuZ3JvdXBlZFNlc3Npb25zKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBncm91cGVkU2Vzc2lvbnMoKTogQ2hhdFNlc3Npb25Hcm91cFtdIHtcclxuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XHJcbiAgICBjb25zdCB0b2RheSA9IG5ldyBEYXRlKG5vdy5nZXRGdWxsWWVhcigpLCBub3cuZ2V0TW9udGgoKSwgbm93LmdldERhdGUoKSk7XHJcbiAgICBjb25zdCB5ZXN0ZXJkYXkgPSBuZXcgRGF0ZSh0b2RheSk7XHJcbiAgICB5ZXN0ZXJkYXkuc2V0RGF0ZSh5ZXN0ZXJkYXkuZ2V0RGF0ZSgpIC0gMSk7XHJcbiAgICBjb25zdCB3ZWVrQWdvID0gbmV3IERhdGUodG9kYXkpO1xyXG4gICAgd2Vla0Fnby5zZXREYXRlKHdlZWtBZ28uZ2V0RGF0ZSgpIC0gNyk7XHJcblxyXG4gICAgY29uc3QgZ3JvdXBzOiBDaGF0U2Vzc2lvbkdyb3VwW10gPSBbXHJcbiAgICAgIHsgbGFiZWw6ICdUb2RheScsIHNlc3Npb25zOiBbXSB9LFxyXG4gICAgICB7IGxhYmVsOiAnWWVzdGVyZGF5Jywgc2Vzc2lvbnM6IFtdIH0sXHJcbiAgICAgIHsgbGFiZWw6ICdUaGlzIFdlZWsnLCBzZXNzaW9uczogW10gfSxcclxuICAgICAgeyBsYWJlbDogJ09sZGVyJywgc2Vzc2lvbnM6IFtdIH0sXHJcbiAgICBdO1xyXG5cclxuICAgIC8vIFNvcnQgc2Vzc2lvbnMgYnkgdGltZXN0YW1wIChuZXdlc3QgZmlyc3QpXHJcbiAgICBjb25zdCBzb3J0ZWRTZXNzaW9ucyA9IFsuLi50aGlzLnNlc3Npb25zXS5zb3J0KFxyXG4gICAgICAoYSwgYikgPT4gYi50aW1lc3RhbXAuZ2V0VGltZSgpIC0gYS50aW1lc3RhbXAuZ2V0VGltZSgpLFxyXG4gICAgKTtcclxuXHJcbiAgICBzb3J0ZWRTZXNzaW9ucy5mb3JFYWNoKChzZXNzaW9uKSA9PiB7XHJcbiAgICAgIGNvbnN0IHNlc3Npb25EYXRlID0gbmV3IERhdGUoc2Vzc2lvbi50aW1lc3RhbXApO1xyXG4gICAgICBjb25zdCBzZXNzaW9uRGF5U3RhcnQgPSBuZXcgRGF0ZShcclxuICAgICAgICBzZXNzaW9uRGF0ZS5nZXRGdWxsWWVhcigpLFxyXG4gICAgICAgIHNlc3Npb25EYXRlLmdldE1vbnRoKCksXHJcbiAgICAgICAgc2Vzc2lvbkRhdGUuZ2V0RGF0ZSgpLFxyXG4gICAgICApO1xyXG5cclxuICAgICAgaWYgKHNlc3Npb25EYXlTdGFydC5nZXRUaW1lKCkgPT09IHRvZGF5LmdldFRpbWUoKSkge1xyXG4gICAgICAgIGdyb3Vwc1swXS5zZXNzaW9ucy5wdXNoKHNlc3Npb24pO1xyXG4gICAgICB9IGVsc2UgaWYgKHNlc3Npb25EYXlTdGFydC5nZXRUaW1lKCkgPT09IHllc3RlcmRheS5nZXRUaW1lKCkpIHtcclxuICAgICAgICBncm91cHNbMV0uc2Vzc2lvbnMucHVzaChzZXNzaW9uKTtcclxuICAgICAgfSBlbHNlIGlmIChzZXNzaW9uRGF5U3RhcnQuZ2V0VGltZSgpID49IHdlZWtBZ28uZ2V0VGltZSgpKSB7XHJcbiAgICAgICAgZ3JvdXBzWzJdLnNlc3Npb25zLnB1c2goc2Vzc2lvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZ3JvdXBzWzNdLnNlc3Npb25zLnB1c2goc2Vzc2lvbik7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEZpbHRlciBvdXQgZW1wdHkgZ3JvdXBzXHJcbiAgICByZXR1cm4gZ3JvdXBzLmZpbHRlcigoZykgPT4gZy5zZXNzaW9ucy5sZW5ndGggPiAwKTtcclxuICB9XHJcblxyXG4gIG9uU2Vzc2lvbkNsaWNrKHNlc3Npb246IENoYXRTZXNzaW9uKTogdm9pZCB7XHJcbiAgICB0aGlzLnNlc3Npb25TZWxlY3RlZC5lbWl0KHNlc3Npb24pO1xyXG4gIH1cclxuXHJcbiAgb25FZGl0Q2xpY2soZXZlbnQ6IEV2ZW50LCBzZXNzaW9uOiBDaGF0U2Vzc2lvbik6IHZvaWQge1xyXG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICB0aGlzLmRpYWxvZ1NlcnZpY2VcclxuICAgICAgLm9wZW5JbnB1dCh7XHJcbiAgICAgICAgdGl0bGU6ICdSZW5hbWUgQ29udmVyc2F0aW9uJyxcclxuICAgICAgICBtZXNzYWdlOiAnRW50ZXIgYSBuZXcgdGl0bGUgZm9yIHRoaXMgY29udmVyc2F0aW9uOicsXHJcbiAgICAgICAgaW5pdGlhbFZhbHVlOiBzZXNzaW9uLnRpdGxlLFxyXG4gICAgICAgIHBsYWNlaG9sZGVyOiAnTmV3IHRpdGxlLi4uJyxcclxuICAgICAgICBjb25maXJtVGV4dDogJ1JlbmFtZScsXHJcbiAgICAgIH0pXHJcbiAgICAgIC5zdWJzY3JpYmUoKG5ld1RpdGxlKSA9PiB7XHJcbiAgICAgICAgaWYgKG5ld1RpdGxlICE9PSBudWxsICYmIG5ld1RpdGxlLnRyaW0oKSAhPT0gJycgJiYgbmV3VGl0bGUgIT09IHNlc3Npb24udGl0bGUpIHtcclxuICAgICAgICAgIHRoaXMuc2Vzc2lvblJlbmFtZWQuZW1pdCh7IHNlc3Npb25JZDogc2Vzc2lvbi5pZCwgbmV3VGl0bGU6IG5ld1RpdGxlLnRyaW0oKSB9KTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgb25EZWxldGVDbGljayhldmVudDogRXZlbnQsIHNlc3Npb25JZDogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgIHRoaXMuZGlhbG9nU2VydmljZS5jb25maXJtRGVsZXRlKCd0aGlzIGNvbnZlcnNhdGlvbicpLnN1YnNjcmliZSgoY29uZmlybWVkKSA9PiB7XHJcbiAgICAgIGlmIChjb25maXJtZWQpIHtcclxuICAgICAgICB0aGlzLnNlc3Npb25EZWxldGVkLmVtaXQoc2Vzc2lvbklkKTtcclxuICAgICAgICB0aGlzLmNoYXRIaXN0b3J5ID0gdGhpcy5ncm91cGVkU2Vzc2lvbnMoKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBvbkNsb3NlKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jbG9zZWQuZW1pdCgpO1xyXG4gIH1cclxuXHJcbiAgZm9ybWF0VGltZShkYXRlOiBEYXRlKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBuZXcgRGF0ZShkYXRlKS50b0xvY2FsZVRpbWVTdHJpbmcoJ2VuLVVTJywge1xyXG4gICAgICBob3VyOiAnbnVtZXJpYycsXHJcbiAgICAgIG1pbnV0ZTogJzItZGlnaXQnLFxyXG4gICAgICBob3VyMTI6IHRydWUsXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIGZvcm1hdERhdGUoZGF0ZTogRGF0ZSk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gbmV3IERhdGUoZGF0ZSkudG9Mb2NhbGVEYXRlU3RyaW5nKCdlbi1VUycsIHtcclxuICAgICAgbW9udGg6ICdzaG9ydCcsXHJcbiAgICAgIGRheTogJ251bWVyaWMnLFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBIYW5kbGUgc2Nyb2xsIGV2ZW50IGZvciBpbmZpbml0ZSBzY3JvbGxcclxuICAgKi9cclxuICBvblNjcm9sbChldmVudDogRXZlbnQpOiB2b2lkIHtcclxuICAgIGNvbnN0IGVsZW1lbnQgPSBldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICBjb25zdCBzY3JvbGxUb3AgPSBlbGVtZW50LnNjcm9sbFRvcDtcclxuICAgIGNvbnN0IHNjcm9sbEhlaWdodCA9IGVsZW1lbnQuc2Nyb2xsSGVpZ2h0O1xyXG4gICAgY29uc3QgY2xpZW50SGVpZ2h0ID0gZWxlbWVudC5jbGllbnRIZWlnaHQ7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgc2Nyb2xsZWQgbmVhciBib3R0b20gKHdpdGhpbiAxMDBweClcclxuICAgIGNvbnN0IHNjcm9sbEJvdHRvbSA9IHNjcm9sbEhlaWdodCAtIHNjcm9sbFRvcCAtIGNsaWVudEhlaWdodDtcclxuICAgIGlmIChzY3JvbGxCb3R0b20gPCAxMDAgJiYgdGhpcy5oYXNNb3JlU2Vzc2lvbnMgJiYgIXRoaXMuaXNMb2FkaW5nTW9yZSAmJiAhdGhpcy5pc0xvYWRpbmcpIHtcclxuICAgICAgdGhpcy5sb2FkTW9yZS5lbWl0KCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBIYW5kbGUgbWFudWFsIHJlZnJlc2hcclxuICAgKi9cclxuICBvblJlZnJlc2goKTogdm9pZCB7XHJcbiAgICB0aGlzLnJlZnJlc2guZW1pdCgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlIGNsZWFyIGFsbCBoaXN0b3J5XHJcbiAgICovXHJcbiAgb25DbGVhckFsbENsaWNrKCk6IHZvaWQge1xyXG4gICAgdGhpcy5kaWFsb2dTZXJ2aWNlXHJcbiAgICAgIC5vcGVuKHtcclxuICAgICAgICB0aXRsZTogJ0NsZWFyIEFsbCBIaXN0b3J5JyxcclxuICAgICAgICBtZXNzYWdlOiAnQXJlIHlvdSBzdXJlIHlvdSB3YW50IHRvIGRlbGV0ZSBhbGwgY2hhdCBoaXN0b3J5PyBUaGlzIGFjdGlvbiBjYW5ub3QgYmUgdW5kb25lLicsXHJcbiAgICAgICAgY29uZmlybVRleHQ6ICdDbGVhciBBbGwnLFxyXG4gICAgICAgIGNhbmNlbFRleHQ6ICdDYW5jZWwnLFxyXG4gICAgICAgIGNvbmZpcm1CdXR0b25Db2xvcjogJ3dhcm4nLFxyXG4gICAgICAgIGljb246ICdkZWxldGVfc3dlZXAnLFxyXG4gICAgICB9KVxyXG4gICAgICAuc3Vic2NyaWJlKChjb25maXJtZWQ6IGJvb2xlYW4gfCB1bmRlZmluZWQpID0+IHtcclxuICAgICAgICBpZiAoY29uZmlybWVkKSB7XHJcbiAgICAgICAgICB0aGlzLmRlbGV0ZUFsbC5lbWl0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICB9XHJcbn1cclxuIiwiPGRpdiBjbGFzcz1cImhpc3Rvcnktc2lkZWJhclwiIFtjbGFzcy5vcGVuXT1cImlzT3BlblwiPlxyXG4gIDxkaXYgY2xhc3M9XCJzaWRlYmFyLWhlYWRlclwiPlxyXG4gICAgPGRpdiBjbGFzcz1cIm1hcnF1ZWUtY29udGFpbmVyXCIgc3R5bGU9XCJmbGV4OiAxOyBtYXJnaW4tcmlnaHQ6IDEwcHhcIj5cclxuICAgICAgPGgzIGNsYXNzPVwibWFycXVlZS10ZXh0XCI+e3sgdXNlck5hbWUgfX0ncyBDaGF0IEhpc3Rvcnk8L2gzPlxyXG4gICAgPC9kaXY+XHJcbiAgICA8YnV0dG9uIGNsYXNzPVwicmVmcmVzaC1idG5cIiAoY2xpY2spPVwib25SZWZyZXNoKClcIiB0aXRsZT1cIlJlZnJlc2ggaGlzdG9yeVwiPlxyXG4gICAgICA8bWF0LWljb24+cmVmcmVzaDwvbWF0LWljb24+XHJcbiAgICA8L2J1dHRvbj5cclxuXHJcbiAgICA8YnV0dG9uIGNsYXNzPVwiY2xvc2UtYnRuXCIgKGNsaWNrKT1cIm9uQ2xvc2UoKVwiPlxyXG4gICAgICA8bWF0LWljb24+Y2xvc2U8L21hdC1pY29uPlxyXG4gICAgPC9idXR0b24+XHJcbiAgPC9kaXY+XHJcblxyXG4gIDxkaXYgY2xhc3M9XCJzaWRlYmFyLWNvbnRlbnRcIiAoc2Nyb2xsKT1cIm9uU2Nyb2xsKCRldmVudClcIj5cclxuICAgIEBpZiAoaXNMb2FkaW5nKSB7XHJcbiAgICA8ZGl2IGNsYXNzPVwibG9hZGVyLWNvbnRhaW5lclwiPlxyXG4gICAgICA8ZGl2IGNsYXNzPVwibG9hZGVyXCI+PC9kaXY+XHJcbiAgICAgIDxwPkxvYWRpbmcgaGlzdG9yeS4uLjwvcD5cclxuICAgIDwvZGl2PlxyXG4gICAgfVxyXG5cclxuICAgIEBpZiAoIWlzTG9hZGluZyAmJiBzZXNzaW9ucy5sZW5ndGggPT09IDApIHtcclxuICAgIDxkaXYgY2xhc3M9XCJlbXB0eS1zdGF0ZVwiPlxyXG4gICAgICA8bWF0LWljb24+aGlzdG9yeTwvbWF0LWljb24+XHJcbiAgICAgIDxwPk5vIGNoYXQgaGlzdG9yeSB5ZXQ8L3A+XHJcbiAgICAgIDxzcGFuPlN0YXJ0IGEgY29udmVyc2F0aW9uIHRvIHNlZSBpdCBoZXJlPC9zcGFuPlxyXG4gICAgPC9kaXY+XHJcbiAgICB9XHJcblxyXG4gICAgQGlmICghaXNMb2FkaW5nKSB7XHJcbiAgICBAZm9yIChncm91cCBvZiBjaGF0SGlzdG9yeTsgdHJhY2sgZ3JvdXAubGFiZWwpIHtcclxuICAgIDxkaXYgY2xhc3M9XCJzZXNzaW9uLWdyb3VwXCI+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJncm91cC1sYWJlbFwiPnt7IGdyb3VwLmxhYmVsIH19PC9kaXY+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJzZXNzaW9uLWxpc3RcIj5cclxuICAgICAgICBAZm9yIChzZXNzaW9uIG9mIGdyb3VwLnNlc3Npb25zOyB0cmFjayBzZXNzaW9uLmlkKSB7XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInNlc3Npb24taXRlbVwiIChjbGljayk9XCJvblNlc3Npb25DbGljayhzZXNzaW9uKVwiPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cInNlc3Npb24tY29udGVudFwiPlxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Vzc2lvbi10aXRsZVwiPnt7IHNlc3Npb24udGl0bGUgfX08L2Rpdj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNlc3Npb24tdGltZVwiPlxyXG4gICAgICAgICAgICAgIHt7IGZvcm1hdFRpbWUoc2Vzc2lvbi50aW1lc3RhbXApIH19IMK3IHt7IGZvcm1hdERhdGUoc2Vzc2lvbi50aW1lc3RhbXApIH19XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic2Vzc2lvbi1hY3Rpb25zXCI+XHJcbiAgICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJlZGl0LWJ0blwiIFtkaXNhYmxlZF09XCJwcm9jZXNzaW5nU2Vzc2lvbklkID09PSBzZXNzaW9uLmlkXCJcclxuICAgICAgICAgICAgICAoY2xpY2spPVwib25FZGl0Q2xpY2soJGV2ZW50LCBzZXNzaW9uKVwiIHRpdGxlPVwiRWRpdCB0aXRsZVwiPlxyXG4gICAgICAgICAgICAgIEBpZiAocHJvY2Vzc2luZ1Nlc3Npb25JZCAhPT0gc2Vzc2lvbi5pZCkge1xyXG4gICAgICAgICAgICAgIDxtYXQtaWNvbj5lZGl0PC9tYXQtaWNvbj5cclxuICAgICAgICAgICAgICB9IEBlbHNlIHtcclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibG9hZGVyLXRpbnlcIj48L2Rpdj5cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiZGVsZXRlLWJ0blwiIFtkaXNhYmxlZF09XCJwcm9jZXNzaW5nU2Vzc2lvbklkID09PSBzZXNzaW9uLmlkXCJcclxuICAgICAgICAgICAgICAoY2xpY2spPVwib25EZWxldGVDbGljaygkZXZlbnQsIHNlc3Npb24uaWQpXCIgdGl0bGU9XCJEZWxldGUgY29udmVyc2F0aW9uXCI+XHJcbiAgICAgICAgICAgICAgQGlmIChwcm9jZXNzaW5nU2Vzc2lvbklkICE9PSBzZXNzaW9uLmlkKSB7XHJcbiAgICAgICAgICAgICAgPG1hdC1pY29uPmRlbGV0ZTwvbWF0LWljb24+XHJcbiAgICAgICAgICAgICAgfSBAZWxzZSB7XHJcbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImxvYWRlci10aW55XCI+PC9kaXY+XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIH1cclxuICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuICAgIH1cclxuICAgIH1cclxuXHJcbiAgICA8IS0tIExvYWRpbmcgbW9yZSBpbmRpY2F0b3IgLS0+XHJcbiAgICBAaWYgKGlzTG9hZGluZ01vcmUpIHtcclxuICAgIDxkaXYgY2xhc3M9XCJsb2FkaW5nLW1vcmVcIj5cclxuICAgICAgPGRpdiBjbGFzcz1cImxvYWRlci1zbWFsbFwiPjwvZGl2PlxyXG4gICAgICA8cD5Mb2FkaW5nIG1vcmUuLi48L3A+XHJcbiAgICA8L2Rpdj5cclxuICAgIH1cclxuICA8L2Rpdj5cclxuPC9kaXY+Il19