@c8y/ngx-components 1024.16.6 → 1024.16.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs +2 -2
- package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-register-device.mjs +5 -6
- package/fesm2022/c8y-ngx-components-register-device.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +48 -7
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/package.json +1 -1
- package/types/c8y-ngx-components-register-device.d.ts.map +1 -1
- package/types/c8y-ngx-components.d.ts +21 -3
- package/types/c8y-ngx-components.d.ts.map +1 -1
|
@@ -942,7 +942,7 @@ class AiChatComponent {
|
|
|
942
942
|
this.chatInput()?.nativeElement.focus();
|
|
943
943
|
}
|
|
944
944
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AiChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
945
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: AiChatComponent, isStandalone: true, selector: "c8y-ai-chat", inputs: { isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, prompt: { classPropertyName: "prompt", publicName: "prompt", isSignal: false, isRequired: false, transformFunction: null }, suggestionsTemplate: { classPropertyName: "suggestionsTemplate", publicName: "suggestionsTemplate", isSignal: false, isRequired: false, transformFunction: null }, welcomeTemplate: { classPropertyName: "welcomeTemplate", publicName: "welcomeTemplate", isSignal: false, isRequired: false, transformFunction: null }, cumulativeUsage: { classPropertyName: "cumulativeUsage", publicName: "cumulativeUsage", isSignal: false, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onMessage: "onMessage", onCancel: "onCancel" }, host: { classAttribute: "d-contents" }, queries: [{ propertyName: "messages", predicate: AiChatMessageComponent, isSignal: true }, { propertyName: "projectedActions", predicate: AiChatActionComponent, isSignal: true }], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["chatScrollContainer"], descendants: true, isSignal: true }, { propertyName: "chatInput", first: true, predicate: ["chatInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"d-col fit-w flex-grow min-height-0\"\n [attr.aria-label]=\"config.headline | translate\"\n role=\"region\"\n>\n <!-- Streamed tokens are withheld while the log is busy, so announce start and end here. -->\n <div\n class=\"sr-only\"\n aria-live=\"polite\"\n role=\"status\"\n >\n {{ statusAnnouncement() | translate }}\n </div>\n @if (messages().length > 0) {\n <div\n [attr.aria-label]=\"'Chat conversation' | translate\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n [attr.aria-busy]=\"isLoading\"\n role=\"log\"\n #chatScrollContainer\n [ngClass]=\"{\n 'inner-scroll': true,\n 'd-col-reverse': true,\n 'scrollbar-only-on-hover': config.scrollbarOnlyOnHover,\n 'flex-grow': true,\n 'min-height-0': true,\n 'bg-level-0': true\n }\"\n >\n <div class=\"d-col p-l-16 p-r-16\">\n <ng-content select=\"[slot='before-messages']\"></ng-content>\n <ng-content select=\"c8y-ai-chat-message\"></ng-content>\n <ng-content select=\"[slot='after-messages']\"></ng-content>\n </div>\n </div>\n }\n <div\n [ngClass]=\"{\n 'd-col fit-h': messages().length === 0\n }\"\n >\n @if (messages().length === 0) {\n <div\n class=\"p-24 d-col fit-h inner-scroll\"\n aria-live=\"polite\"\n role=\"status\"\n [ngClass]=\"{\n 'j-c-start': config.welcomePosition === 'top',\n 'j-c-center': config.welcomePosition === 'center',\n 'j-c-end': config.welcomePosition === 'bottom'\n }\"\n >\n <h4 class=\"m-b-16 text-medium\">{{ config.headline | translate }}</h4>\n @if (config.title.length > 0) {\n <p class=\"p-b-8 text-pretty\">{{ config.title | translate }}</p>\n }\n <div class=\"text-pretty chat-message min-height-0\">\n <div\n class=\"text-muted\"\n [innerHTML]=\"config.welcomeText | translate | markdownToHtml | async\"\n ></div>\n @if (welcomeTemplate) {\n <ng-container *ngTemplateOutlet=\"welcomeTemplate\"></ng-container>\n }\n </div>\n </div>\n }\n <div\n class=\"chat-input\"\n [class.bg-level-1]=\"config.appearance !== 'flat'\"\n >\n <!-- For simple cases allow ng-content projection; however this doesn't seem to work with dynamic \n suggestion lists from a signal (e.g. returned from the AI) so also support `suggestionsTemplate` for that. \n -->\n @if (!isLoading) {\n <div\n [class]=\"\n 'd-flex inner-scroll gap-8 p-l-16 p-r-16 p-b-16 ' +\n (config.suggestionsLayout === 'vertical' ? 'flex-wrap' : 'a-i-center')\n \"\n [attr.aria-label]=\"'Suggested prompts' | translate\"\n role=\"group\"\n >\n <ng-content select=\"c8y-ai-chat-suggestion\"></ng-content>\n\n @if (suggestionsTemplate) {\n <ng-container *ngTemplateOutlet=\"suggestionsTemplate\"></ng-container>\n }\n </div>\n }\n <div class=\"chat-input-group\">\n <label\n class=\"sr-only\"\n for=\"chat-input-{{ componentId }}\"\n >\n {{ config.placeholder | translate }}\n </label>\n <textarea\n class=\"form-control no-resize\"\n [class.text-muted]=\"isLoading\"\n style=\"max-height: 200px !important\"\n [attr.aria-label]=\"config.placeholder | translate\"\n id=\"chat-input-{{ componentId }}\"\n placeholder=\"{{\n (isListeningForSpeech() && config.listeningPlaceholder\n ? config.listeningPlaceholder\n : config.placeholder\n ) | translate\n }}\"\n [attr.aria-describedby]=\"config.disclaimerText ? 'chat-disclaimer-' + componentId : null\"\n [attr.aria-busy]=\"isLoading\"\n [(ngModel)]=\"prompt\"\n (keydown.enter)=\"!isLoading && sendMessage($event)\"\n [disabled]=\"disabled\"\n c8y-textarea-autoresize\n #chatInput\n ></textarea>\n <div class=\"chat-input-group-btn\">\n <ng-content select=\"[slot='input-actions']\"></ng-content>\n @if (config.enableSpeechToText !== false) {\n <c8y-ai-chat-speech-to-text\n [(prompt)]=\"prompt\"\n [disabled]=\"disabled || isLoading\"\n (listeningChange)=\"isListeningForSpeech.set($event)\"\n ></c8y-ai-chat-speech-to-text>\n }\n </div>\n </div>\n <div class=\"chat-action-bar d-flex a-i-center gap-4 bg-level-0\">\n <div class=\"d-flex a-i-center gap-4\">\n @if (moreActions().length > 0) {\n <div\n class=\"dropdown\"\n dropdown\n #moreChatActions=\"bs-dropdown\"\n [cdkTrapFocus]=\"moreChatActions.isOpen\"\n [dropup]=\"true\"\n >\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"'More actions' | translate\"\n [attr.aria-label]=\"'More actions' | translate\"\n aria-haspopup=\"true\"\n type=\"button\"\n dropdownToggle\n >\n <i [c8yIcon]=\"'ellipsis-h'\"></i>\n </button>\n <ul\n class=\"dropdown-menu dropup\"\n role=\"menu\"\n *dropdownMenu\n >\n @for (action of moreActions(); track action) {\n <li>\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n </li>\n }\n </ul>\n </div>\n }\n @for (action of leftActions(); track action) {\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n }\n </div>\n <div class=\"d-flex a-i-center gap-4 m-l-auto\">\n @for (action of rightActions(); track action) {\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n }\n @if (!isLoading) {\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"config.sendButtonText || '' | translate\"\n [attr.aria-label]=\"config.sendButtonText || '' | translate\"\n type=\"button\"\n (click)=\"sendMessage($event)\"\n [disabled]=\"disabled || prompt.trim().length === 0\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.send || 'arrow-circle-right'\"></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.title]=\"config.cancelButtonText || '' | translate\"\n [attr.aria-label]=\"config.cancelButtonText || '' | translate\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.cancel || 'stop'\"></i>\n </button>\n }\n </div>\n </div>\n <div class=\"d-flex p-t-8 p-l-16 p-r-16 p-b-8 gap-8\">\n @if (config.disclaimerText) {\n <div\n class=\"text-muted text-10\"\n id=\"chat-disclaimer-{{ componentId }}\"\n role=\"note\"\n >\n {{ config.disclaimerText | translate }}\n </div>\n }\n @if (cumulativeUsage) {\n <button\n class=\"btn-clean m-l-auto d-flex a-s-center\"\n [attr.aria-label]=\"\n 'Input tokens: {{ input }}\\nOutput tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n tabindex=\"0\"\n [tooltip]=\"\n 'Input tokens: {{ input }}\\nOutput tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n >\n <span class=\"tag tag--info a-s-center\">\n {{ 'Tokens used: {{total}}' | translate: { total: (cumulativeUsage?.totalTokens || 0)\n | c8yNumber : 'floor':'1.0-0' } }}\n </span>\n </button>\n }\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TextareaAutoresizeDirective, selector: "[c8y-textarea-autoresize]" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$1.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "directive", type: i2.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i2.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i2.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "component", type: AiChatSpeechToTextComponent, selector: "c8y-ai-chat-speech-to-text", inputs: ["disabled", "lang", "prompt"], outputs: ["promptChange", "listeningChange"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: NumberPipe, name: "c8yNumber" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
945
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: AiChatComponent, isStandalone: true, selector: "c8y-ai-chat", inputs: { isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, prompt: { classPropertyName: "prompt", publicName: "prompt", isSignal: false, isRequired: false, transformFunction: null }, suggestionsTemplate: { classPropertyName: "suggestionsTemplate", publicName: "suggestionsTemplate", isSignal: false, isRequired: false, transformFunction: null }, welcomeTemplate: { classPropertyName: "welcomeTemplate", publicName: "welcomeTemplate", isSignal: false, isRequired: false, transformFunction: null }, cumulativeUsage: { classPropertyName: "cumulativeUsage", publicName: "cumulativeUsage", isSignal: false, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onMessage: "onMessage", onCancel: "onCancel" }, host: { classAttribute: "d-contents" }, queries: [{ propertyName: "messages", predicate: AiChatMessageComponent, isSignal: true }, { propertyName: "projectedActions", predicate: AiChatActionComponent, isSignal: true }], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["chatScrollContainer"], descendants: true, isSignal: true }, { propertyName: "chatInput", first: true, predicate: ["chatInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"d-col fit-h fit-w flex-grow min-height-0\"\n [attr.aria-label]=\"config.headline | translate\"\n role=\"region\"\n>\n <!-- Streamed tokens are withheld while the log is busy, so announce start and end here. -->\n <div\n class=\"sr-only\"\n aria-live=\"polite\"\n role=\"status\"\n >\n {{ statusAnnouncement() | translate }}\n </div>\n @if (messages().length > 0) {\n <div\n [attr.aria-label]=\"'Chat conversation' | translate\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n [attr.aria-busy]=\"isLoading\"\n role=\"log\"\n #chatScrollContainer\n [ngClass]=\"{\n 'inner-scroll': true,\n 'd-col-reverse': true,\n 'scrollbar-only-on-hover': config.scrollbarOnlyOnHover,\n 'flex-grow': true,\n 'min-height-0': true,\n 'bg-level-0': true\n }\"\n >\n <div class=\"d-col p-l-16 p-r-16\">\n <ng-content select=\"[slot='before-messages']\"></ng-content>\n <ng-content select=\"c8y-ai-chat-message\"></ng-content>\n <ng-content select=\"[slot='after-messages']\"></ng-content>\n </div>\n </div>\n }\n <div\n [ngClass]=\"{\n 'd-col fit-h': messages().length === 0\n }\"\n >\n @if (messages().length === 0) {\n <div\n class=\"p-24 d-col fit-h inner-scroll\"\n aria-live=\"polite\"\n role=\"status\"\n [ngClass]=\"{\n 'j-c-start': config.welcomePosition === 'top',\n 'j-c-center': config.welcomePosition === 'center',\n 'j-c-end': config.welcomePosition === 'bottom'\n }\"\n >\n <h4 class=\"m-b-16 text-medium\">{{ config.headline | translate }}</h4>\n @if (config.title.length > 0) {\n <p class=\"p-b-8 text-pretty\">{{ config.title | translate }}</p>\n }\n <div class=\"text-pretty chat-message min-height-0\">\n <div\n class=\"text-muted\"\n [innerHTML]=\"config.welcomeText | translate | markdownToHtml | async\"\n ></div>\n @if (welcomeTemplate) {\n <ng-container *ngTemplateOutlet=\"welcomeTemplate\"></ng-container>\n }\n </div>\n </div>\n }\n <div\n class=\"chat-input\"\n [class.bg-level-1]=\"config.appearance !== 'flat'\"\n >\n <!-- For simple cases allow ng-content projection; however this doesn't seem to work with dynamic \n suggestion lists from a signal (e.g. returned from the AI) so also support `suggestionsTemplate` for that. \n -->\n @if (!isLoading) {\n <div\n [class]=\"\n 'd-flex inner-scroll gap-8 p-l-16 p-r-16 p-b-16 ' +\n (config.suggestionsLayout === 'vertical' ? 'flex-wrap' : 'a-i-center')\n \"\n [attr.aria-label]=\"'Suggested prompts' | translate\"\n role=\"group\"\n >\n <ng-content select=\"c8y-ai-chat-suggestion\"></ng-content>\n\n @if (suggestionsTemplate) {\n <ng-container *ngTemplateOutlet=\"suggestionsTemplate\"></ng-container>\n }\n </div>\n }\n <div class=\"chat-input-group\">\n <label\n class=\"sr-only\"\n for=\"chat-input-{{ componentId }}\"\n >\n {{ config.placeholder | translate }}\n </label>\n <textarea\n class=\"form-control no-resize\"\n [class.text-muted]=\"isLoading\"\n style=\"max-height: 200px !important\"\n [attr.aria-label]=\"config.placeholder | translate\"\n id=\"chat-input-{{ componentId }}\"\n placeholder=\"{{\n (isListeningForSpeech() && config.listeningPlaceholder\n ? config.listeningPlaceholder\n : config.placeholder\n ) | translate\n }}\"\n [attr.aria-describedby]=\"config.disclaimerText ? 'chat-disclaimer-' + componentId : null\"\n [attr.aria-busy]=\"isLoading\"\n [(ngModel)]=\"prompt\"\n (keydown.enter)=\"!isLoading && sendMessage($event)\"\n [disabled]=\"disabled\"\n c8y-textarea-autoresize\n #chatInput\n ></textarea>\n <div class=\"chat-input-group-btn\">\n <ng-content select=\"[slot='input-actions']\"></ng-content>\n @if (config.enableSpeechToText !== false) {\n <c8y-ai-chat-speech-to-text\n [(prompt)]=\"prompt\"\n [disabled]=\"disabled || isLoading\"\n (listeningChange)=\"isListeningForSpeech.set($event)\"\n ></c8y-ai-chat-speech-to-text>\n }\n </div>\n </div>\n <div class=\"chat-action-bar d-flex a-i-center gap-4 bg-level-0\">\n <div class=\"d-flex a-i-center gap-4\">\n @if (moreActions().length > 0) {\n <div\n class=\"dropdown\"\n dropdown\n #moreChatActions=\"bs-dropdown\"\n [cdkTrapFocus]=\"moreChatActions.isOpen\"\n [dropup]=\"true\"\n >\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"'More actions' | translate\"\n [attr.aria-label]=\"'More actions' | translate\"\n aria-haspopup=\"true\"\n type=\"button\"\n dropdownToggle\n >\n <i [c8yIcon]=\"'ellipsis-h'\"></i>\n </button>\n <ul\n class=\"dropdown-menu dropup\"\n role=\"menu\"\n *dropdownMenu\n >\n @for (action of moreActions(); track action) {\n <li>\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n </li>\n }\n </ul>\n </div>\n }\n @for (action of leftActions(); track action) {\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n }\n </div>\n <div class=\"d-flex a-i-center gap-4 m-l-auto\">\n @for (action of rightActions(); track action) {\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n }\n @if (!isLoading) {\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"config.sendButtonText || '' | translate\"\n [attr.aria-label]=\"config.sendButtonText || '' | translate\"\n type=\"button\"\n (click)=\"sendMessage($event)\"\n [disabled]=\"disabled || prompt.trim().length === 0\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.send || 'arrow-circle-right'\"></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.title]=\"config.cancelButtonText || '' | translate\"\n [attr.aria-label]=\"config.cancelButtonText || '' | translate\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.cancel || 'stop'\"></i>\n </button>\n }\n </div>\n </div>\n <div class=\"d-flex p-t-8 p-l-16 p-r-16 p-b-8 gap-8\">\n @if (config.disclaimerText) {\n <div\n class=\"text-muted text-10\"\n id=\"chat-disclaimer-{{ componentId }}\"\n role=\"note\"\n >\n {{ config.disclaimerText | translate }}\n </div>\n }\n @if (cumulativeUsage) {\n <button\n class=\"btn-clean m-l-auto d-flex a-s-center\"\n [attr.aria-label]=\"\n 'Input tokens: {{ input }}\\nOutput tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n tabindex=\"0\"\n [tooltip]=\"\n 'Input tokens: {{ input }}\\nOutput tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n >\n <span class=\"tag tag--info a-s-center\">\n {{ 'Tokens used: {{total}}' | translate: { total: (cumulativeUsage?.totalTokens || 0)\n | c8yNumber : 'floor':'1.0-0' } }}\n </span>\n </button>\n }\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: TextareaAutoresizeDirective, selector: "[c8y-textarea-autoresize]" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$1.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "directive", type: i2.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i2.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i2.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "component", type: AiChatSpeechToTextComponent, selector: "c8y-ai-chat-speech-to-text", inputs: ["disabled", "lang", "prompt"], outputs: ["promptChange", "listeningChange"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: NumberPipe, name: "c8yNumber" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
946
946
|
}
|
|
947
947
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AiChatComponent, decorators: [{
|
|
948
948
|
type: Component,
|
|
@@ -960,7 +960,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
960
960
|
NumberPipe,
|
|
961
961
|
AiChatSpeechToTextComponent,
|
|
962
962
|
CdkTrapFocus
|
|
963
|
-
], standalone: true, host: { class: 'd-contents' }, template: "<div\n class=\"d-col fit-w flex-grow min-height-0\"\n [attr.aria-label]=\"config.headline | translate\"\n role=\"region\"\n>\n <!-- Streamed tokens are withheld while the log is busy, so announce start and end here. -->\n <div\n class=\"sr-only\"\n aria-live=\"polite\"\n role=\"status\"\n >\n {{ statusAnnouncement() | translate }}\n </div>\n @if (messages().length > 0) {\n <div\n [attr.aria-label]=\"'Chat conversation' | translate\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n [attr.aria-busy]=\"isLoading\"\n role=\"log\"\n #chatScrollContainer\n [ngClass]=\"{\n 'inner-scroll': true,\n 'd-col-reverse': true,\n 'scrollbar-only-on-hover': config.scrollbarOnlyOnHover,\n 'flex-grow': true,\n 'min-height-0': true,\n 'bg-level-0': true\n }\"\n >\n <div class=\"d-col p-l-16 p-r-16\">\n <ng-content select=\"[slot='before-messages']\"></ng-content>\n <ng-content select=\"c8y-ai-chat-message\"></ng-content>\n <ng-content select=\"[slot='after-messages']\"></ng-content>\n </div>\n </div>\n }\n <div\n [ngClass]=\"{\n 'd-col fit-h': messages().length === 0\n }\"\n >\n @if (messages().length === 0) {\n <div\n class=\"p-24 d-col fit-h inner-scroll\"\n aria-live=\"polite\"\n role=\"status\"\n [ngClass]=\"{\n 'j-c-start': config.welcomePosition === 'top',\n 'j-c-center': config.welcomePosition === 'center',\n 'j-c-end': config.welcomePosition === 'bottom'\n }\"\n >\n <h4 class=\"m-b-16 text-medium\">{{ config.headline | translate }}</h4>\n @if (config.title.length > 0) {\n <p class=\"p-b-8 text-pretty\">{{ config.title | translate }}</p>\n }\n <div class=\"text-pretty chat-message min-height-0\">\n <div\n class=\"text-muted\"\n [innerHTML]=\"config.welcomeText | translate | markdownToHtml | async\"\n ></div>\n @if (welcomeTemplate) {\n <ng-container *ngTemplateOutlet=\"welcomeTemplate\"></ng-container>\n }\n </div>\n </div>\n }\n <div\n class=\"chat-input\"\n [class.bg-level-1]=\"config.appearance !== 'flat'\"\n >\n <!-- For simple cases allow ng-content projection; however this doesn't seem to work with dynamic \n suggestion lists from a signal (e.g. returned from the AI) so also support `suggestionsTemplate` for that. \n -->\n @if (!isLoading) {\n <div\n [class]=\"\n 'd-flex inner-scroll gap-8 p-l-16 p-r-16 p-b-16 ' +\n (config.suggestionsLayout === 'vertical' ? 'flex-wrap' : 'a-i-center')\n \"\n [attr.aria-label]=\"'Suggested prompts' | translate\"\n role=\"group\"\n >\n <ng-content select=\"c8y-ai-chat-suggestion\"></ng-content>\n\n @if (suggestionsTemplate) {\n <ng-container *ngTemplateOutlet=\"suggestionsTemplate\"></ng-container>\n }\n </div>\n }\n <div class=\"chat-input-group\">\n <label\n class=\"sr-only\"\n for=\"chat-input-{{ componentId }}\"\n >\n {{ config.placeholder | translate }}\n </label>\n <textarea\n class=\"form-control no-resize\"\n [class.text-muted]=\"isLoading\"\n style=\"max-height: 200px !important\"\n [attr.aria-label]=\"config.placeholder | translate\"\n id=\"chat-input-{{ componentId }}\"\n placeholder=\"{{\n (isListeningForSpeech() && config.listeningPlaceholder\n ? config.listeningPlaceholder\n : config.placeholder\n ) | translate\n }}\"\n [attr.aria-describedby]=\"config.disclaimerText ? 'chat-disclaimer-' + componentId : null\"\n [attr.aria-busy]=\"isLoading\"\n [(ngModel)]=\"prompt\"\n (keydown.enter)=\"!isLoading && sendMessage($event)\"\n [disabled]=\"disabled\"\n c8y-textarea-autoresize\n #chatInput\n ></textarea>\n <div class=\"chat-input-group-btn\">\n <ng-content select=\"[slot='input-actions']\"></ng-content>\n @if (config.enableSpeechToText !== false) {\n <c8y-ai-chat-speech-to-text\n [(prompt)]=\"prompt\"\n [disabled]=\"disabled || isLoading\"\n (listeningChange)=\"isListeningForSpeech.set($event)\"\n ></c8y-ai-chat-speech-to-text>\n }\n </div>\n </div>\n <div class=\"chat-action-bar d-flex a-i-center gap-4 bg-level-0\">\n <div class=\"d-flex a-i-center gap-4\">\n @if (moreActions().length > 0) {\n <div\n class=\"dropdown\"\n dropdown\n #moreChatActions=\"bs-dropdown\"\n [cdkTrapFocus]=\"moreChatActions.isOpen\"\n [dropup]=\"true\"\n >\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"'More actions' | translate\"\n [attr.aria-label]=\"'More actions' | translate\"\n aria-haspopup=\"true\"\n type=\"button\"\n dropdownToggle\n >\n <i [c8yIcon]=\"'ellipsis-h'\"></i>\n </button>\n <ul\n class=\"dropdown-menu dropup\"\n role=\"menu\"\n *dropdownMenu\n >\n @for (action of moreActions(); track action) {\n <li>\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n </li>\n }\n </ul>\n </div>\n }\n @for (action of leftActions(); track action) {\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n }\n </div>\n <div class=\"d-flex a-i-center gap-4 m-l-auto\">\n @for (action of rightActions(); track action) {\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n }\n @if (!isLoading) {\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"config.sendButtonText || '' | translate\"\n [attr.aria-label]=\"config.sendButtonText || '' | translate\"\n type=\"button\"\n (click)=\"sendMessage($event)\"\n [disabled]=\"disabled || prompt.trim().length === 0\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.send || 'arrow-circle-right'\"></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.title]=\"config.cancelButtonText || '' | translate\"\n [attr.aria-label]=\"config.cancelButtonText || '' | translate\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.cancel || 'stop'\"></i>\n </button>\n }\n </div>\n </div>\n <div class=\"d-flex p-t-8 p-l-16 p-r-16 p-b-8 gap-8\">\n @if (config.disclaimerText) {\n <div\n class=\"text-muted text-10\"\n id=\"chat-disclaimer-{{ componentId }}\"\n role=\"note\"\n >\n {{ config.disclaimerText | translate }}\n </div>\n }\n @if (cumulativeUsage) {\n <button\n class=\"btn-clean m-l-auto d-flex a-s-center\"\n [attr.aria-label]=\"\n 'Input tokens: {{ input }}\\nOutput tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n tabindex=\"0\"\n [tooltip]=\"\n 'Input tokens: {{ input }}\\nOutput tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n >\n <span class=\"tag tag--info a-s-center\">\n {{ 'Tokens used: {{total}}' | translate: { total: (cumulativeUsage?.totalTokens || 0)\n | c8yNumber : 'floor':'1.0-0' } }}\n </span>\n </button>\n }\n </div>\n </div>\n </div>\n</div>\n" }]
|
|
963
|
+
], standalone: true, host: { class: 'd-contents' }, template: "<div\n class=\"d-col fit-h fit-w flex-grow min-height-0\"\n [attr.aria-label]=\"config.headline | translate\"\n role=\"region\"\n>\n <!-- Streamed tokens are withheld while the log is busy, so announce start and end here. -->\n <div\n class=\"sr-only\"\n aria-live=\"polite\"\n role=\"status\"\n >\n {{ statusAnnouncement() | translate }}\n </div>\n @if (messages().length > 0) {\n <div\n [attr.aria-label]=\"'Chat conversation' | translate\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n [attr.aria-busy]=\"isLoading\"\n role=\"log\"\n #chatScrollContainer\n [ngClass]=\"{\n 'inner-scroll': true,\n 'd-col-reverse': true,\n 'scrollbar-only-on-hover': config.scrollbarOnlyOnHover,\n 'flex-grow': true,\n 'min-height-0': true,\n 'bg-level-0': true\n }\"\n >\n <div class=\"d-col p-l-16 p-r-16\">\n <ng-content select=\"[slot='before-messages']\"></ng-content>\n <ng-content select=\"c8y-ai-chat-message\"></ng-content>\n <ng-content select=\"[slot='after-messages']\"></ng-content>\n </div>\n </div>\n }\n <div\n [ngClass]=\"{\n 'd-col fit-h': messages().length === 0\n }\"\n >\n @if (messages().length === 0) {\n <div\n class=\"p-24 d-col fit-h inner-scroll\"\n aria-live=\"polite\"\n role=\"status\"\n [ngClass]=\"{\n 'j-c-start': config.welcomePosition === 'top',\n 'j-c-center': config.welcomePosition === 'center',\n 'j-c-end': config.welcomePosition === 'bottom'\n }\"\n >\n <h4 class=\"m-b-16 text-medium\">{{ config.headline | translate }}</h4>\n @if (config.title.length > 0) {\n <p class=\"p-b-8 text-pretty\">{{ config.title | translate }}</p>\n }\n <div class=\"text-pretty chat-message min-height-0\">\n <div\n class=\"text-muted\"\n [innerHTML]=\"config.welcomeText | translate | markdownToHtml | async\"\n ></div>\n @if (welcomeTemplate) {\n <ng-container *ngTemplateOutlet=\"welcomeTemplate\"></ng-container>\n }\n </div>\n </div>\n }\n <div\n class=\"chat-input\"\n [class.bg-level-1]=\"config.appearance !== 'flat'\"\n >\n <!-- For simple cases allow ng-content projection; however this doesn't seem to work with dynamic \n suggestion lists from a signal (e.g. returned from the AI) so also support `suggestionsTemplate` for that. \n -->\n @if (!isLoading) {\n <div\n [class]=\"\n 'd-flex inner-scroll gap-8 p-l-16 p-r-16 p-b-16 ' +\n (config.suggestionsLayout === 'vertical' ? 'flex-wrap' : 'a-i-center')\n \"\n [attr.aria-label]=\"'Suggested prompts' | translate\"\n role=\"group\"\n >\n <ng-content select=\"c8y-ai-chat-suggestion\"></ng-content>\n\n @if (suggestionsTemplate) {\n <ng-container *ngTemplateOutlet=\"suggestionsTemplate\"></ng-container>\n }\n </div>\n }\n <div class=\"chat-input-group\">\n <label\n class=\"sr-only\"\n for=\"chat-input-{{ componentId }}\"\n >\n {{ config.placeholder | translate }}\n </label>\n <textarea\n class=\"form-control no-resize\"\n [class.text-muted]=\"isLoading\"\n style=\"max-height: 200px !important\"\n [attr.aria-label]=\"config.placeholder | translate\"\n id=\"chat-input-{{ componentId }}\"\n placeholder=\"{{\n (isListeningForSpeech() && config.listeningPlaceholder\n ? config.listeningPlaceholder\n : config.placeholder\n ) | translate\n }}\"\n [attr.aria-describedby]=\"config.disclaimerText ? 'chat-disclaimer-' + componentId : null\"\n [attr.aria-busy]=\"isLoading\"\n [(ngModel)]=\"prompt\"\n (keydown.enter)=\"!isLoading && sendMessage($event)\"\n [disabled]=\"disabled\"\n c8y-textarea-autoresize\n #chatInput\n ></textarea>\n <div class=\"chat-input-group-btn\">\n <ng-content select=\"[slot='input-actions']\"></ng-content>\n @if (config.enableSpeechToText !== false) {\n <c8y-ai-chat-speech-to-text\n [(prompt)]=\"prompt\"\n [disabled]=\"disabled || isLoading\"\n (listeningChange)=\"isListeningForSpeech.set($event)\"\n ></c8y-ai-chat-speech-to-text>\n }\n </div>\n </div>\n <div class=\"chat-action-bar d-flex a-i-center gap-4 bg-level-0\">\n <div class=\"d-flex a-i-center gap-4\">\n @if (moreActions().length > 0) {\n <div\n class=\"dropdown\"\n dropdown\n #moreChatActions=\"bs-dropdown\"\n [cdkTrapFocus]=\"moreChatActions.isOpen\"\n [dropup]=\"true\"\n >\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"'More actions' | translate\"\n [attr.aria-label]=\"'More actions' | translate\"\n aria-haspopup=\"true\"\n type=\"button\"\n dropdownToggle\n >\n <i [c8yIcon]=\"'ellipsis-h'\"></i>\n </button>\n <ul\n class=\"dropdown-menu dropup\"\n role=\"menu\"\n *dropdownMenu\n >\n @for (action of moreActions(); track action) {\n <li>\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n </li>\n }\n </ul>\n </div>\n }\n @for (action of leftActions(); track action) {\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n }\n </div>\n <div class=\"d-flex a-i-center gap-4 m-l-auto\">\n @for (action of rightActions(); track action) {\n <ng-container *ngTemplateOutlet=\"action.template()\"></ng-container>\n }\n @if (!isLoading) {\n <button\n class=\"btn btn-dot\"\n [attr.title]=\"config.sendButtonText || '' | translate\"\n [attr.aria-label]=\"config.sendButtonText || '' | translate\"\n type=\"button\"\n (click)=\"sendMessage($event)\"\n [disabled]=\"disabled || prompt.trim().length === 0\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.send || 'arrow-circle-right'\"></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot btn-dot--danger\"\n [attr.title]=\"config.cancelButtonText || '' | translate\"\n [attr.aria-label]=\"config.cancelButtonText || '' | translate\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n <i [c8yIcon]=\"config.userInterfaceIcons.cancel || 'stop'\"></i>\n </button>\n }\n </div>\n </div>\n <div class=\"d-flex p-t-8 p-l-16 p-r-16 p-b-8 gap-8\">\n @if (config.disclaimerText) {\n <div\n class=\"text-muted text-10\"\n id=\"chat-disclaimer-{{ componentId }}\"\n role=\"note\"\n >\n {{ config.disclaimerText | translate }}\n </div>\n }\n @if (cumulativeUsage) {\n <button\n class=\"btn-clean m-l-auto d-flex a-s-center\"\n [attr.aria-label]=\"\n 'Input tokens: {{ input }}\\nOutput tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n tabindex=\"0\"\n [tooltip]=\"\n 'Input tokens: {{ input }}\\nOutput tokens: {{ output }}'\n | translate\n : {\n input: cumulativeUsage?.inputTokens || 0 | c8yNumber: 'floor' : '1.0-0',\n output: cumulativeUsage?.outputTokens || 0 | c8yNumber: 'floor' : '1.0-0'\n }\n \"\n >\n <span class=\"tag tag--info a-s-center\">\n {{ 'Tokens used: {{total}}' | translate: { total: (cumulativeUsage?.totalTokens || 0)\n | c8yNumber : 'floor':'1.0-0' } }}\n </span>\n </button>\n }\n </div>\n </div>\n </div>\n</div>\n" }]
|
|
964
964
|
}], ctorParameters: () => [], propDecorators: { isLoading: [{
|
|
965
965
|
type: Input
|
|
966
966
|
}], disabled: [{
|