UNPKG

@progress/kendo-angular-grid

Version:

Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.

306 lines (305 loc) 15.6 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Component, ViewChild } from '@angular/core'; import { AIPromptComponent, OutputViewComponent, PromptViewComponent, AIPromptCustomMessagesComponent, AIPromptOutputTemplateDirective, AIPromptOutputBodyTemplateDirective } from '@progress/kendo-angular-conversational-ui'; import { HttpClient, HttpRequest } from '@angular/common/http'; import { ContextService } from './../../../../common/provider.service'; import { ColumnInfoService } from './../../../../common/column-info.service'; import { convertDateStringsInFilter, GridToolbarAIResponseSuccessEvent, GridToolbarAIResponseErrorEvent } from './utils'; import { NgIf } from '@angular/common'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common/http"; import * as i2 from "./../../../../common/provider.service"; import * as i3 from "./../../../../common/column-info.service"; /** * @hidden */ export class AiAssistantComponent { http; ctx; columnInfoService; aiPrompt; activeView = 0; requestUrl; requestOptions; aiPromptSettings; aiToolDirective; streaming = false; disabledGenerateButton = false; lastMessage; requestData; currentRequestSubscription = null; //Remove this when the AI Assistant has a built-in loading indicator loadingOutput = { id: 'k-loading-item', output: '', prompt: '' }; columns = []; idCounter = 0; constructor(http, ctx, columnInfoService) { this.http = http; this.ctx = ctx; this.columnInfoService = columnInfoService; } ngAfterViewInit() { this.columns = this.columnInfoService.leafNamedColumns.map((col) => ({ field: col.field, title: col.title || col.field })); } ngOnDestroy() { this.unsubscribeCurrentRequest(); } message(message) { return this.ctx.localization.get(message); } cancelRequest() { this.aiToolDirective.cancelRequest.emit(); this.unsubscribeCurrentRequest(); this.streaming = false; } onPromptRequest(ev) { if (this.aiToolDirective.promptOutputs.length === 0) { this.aiToolDirective.promptOutputs.push(this.loadingOutput); } this.unsubscribeCurrentRequest(); this.streaming = true; this.activeView = 1; if (ev.prompt) { this.lastMessage = ev.prompt; } this.requestData = { columns: this.columns, promptMessage: ev.prompt, url: this.requestUrl, requestOptions: { ...this.requestOptions } }; if (!this.requestOptions.body) { const requestBody = { role: this.requestData.requestOptions.role, contents: [ { text: this.requestData.promptMessage } ], columns: this.requestData.columns }; this.requestData.requestOptions.body = requestBody; } this.aiToolDirective.promptRequest.emit({ requestData: this.requestData, isRetry: ev.isRetry }); if (!this.requestUrl) { return; } this.currentRequestSubscription = this.sendPromptRequest().subscribe((res) => { if (res.body) { this.processResponse(res); this.streaming = false; } this.currentRequestSubscription = null; }, (error) => { this.handleError(error); this.streaming = false; this.currentRequestSubscription = null; }); } sendPromptRequest() { const request = new HttpRequest(this.requestData.requestOptions.method, this.requestData.url, this.requestData.requestOptions.body, this.requestData.requestOptions); return this.http.request(request); } processResponse(response) { if (this.aiToolDirective.autoClose) { this.aiToolDirective.emitOpenClose = true; this.aiToolDirective.toggleWindow(); } const responseBody = response.body; const responseSuccessEvent = new GridToolbarAIResponseSuccessEvent(response); this.aiToolDirective.responseSuccess.emit(responseSuccessEvent); if (responseSuccessEvent.isDefaultPrevented()) { this.deleteLoadingOutput(); return; } const isFilterable = Boolean(this.ctx.grid.filterable); const isSortable = Boolean(this.ctx.grid.sortable); const isGroupable = Boolean(this.ctx.grid.groupable); if (isFilterable && responseBody.filter) { this.processFilterResponse(responseBody.filter); } if (isSortable && responseBody.sort) { this.processArrayResponse(responseBody.sort, this.ctx.grid.currentState.sort || [], (item) => item.field, (mergedArray) => this.ctx.grid.sortChange.next(mergedArray)); } if (isGroupable && responseBody.group) { this.processArrayResponse(responseBody.group, this.ctx.grid.currentState.group || [], (item) => item.field, (mergedArray) => this.ctx.grid.groupChange.next(mergedArray)); } const responseContentStart = [`${this.ctx.localization.get('aiAssistantOutputCardBodyContent')} \n`]; const responseContentBody = responseBody.messages .map((output, idx) => `${idx + 1} ${output}`) .join('\n'); const output = { id: this.idCounter++, title: this.ctx.localization.get('aiAssistantOutputCardTitle'), prompt: this.lastMessage, output: responseContentStart.concat(responseContentBody).join(''), }; this.deleteLoadingOutput(); this.aiToolDirective.promptOutputs.unshift(output); } handleError(error) { const responseErrorEvent = new GridToolbarAIResponseErrorEvent(error); this.aiToolDirective.responseError.emit(responseErrorEvent); if (responseErrorEvent.isDefaultPrevented()) { this.deleteLoadingOutput(); return; } const output = { id: this.idCounter++, prompt: this.lastMessage, output: error.message }; this.deleteLoadingOutput(); this.aiToolDirective.promptOutputs.unshift(output); } deleteLoadingOutput() { if (this.aiToolDirective.promptOutputs[0]?.id === this.loadingOutput.id) { this.aiToolDirective.promptOutputs.splice(0, 1); } } unsubscribeCurrentRequest() { if (this.currentRequestSubscription) { this.currentRequestSubscription.unsubscribe(); this.currentRequestSubscription = null; } } processArrayResponse(newItems, currentItems, getField, updateGrid) { if (newItems?.length === 0) { updateGrid([]); } else if (newItems?.length) { let mergedArray = [...newItems]; const newFields = newItems.map(getField); const existingItemsToKeep = currentItems.filter(item => !newFields.includes(getField(item))); mergedArray = [...mergedArray, ...existingItemsToKeep]; updateGrid(mergedArray); } } processFilterResponse(filter) { const processedFilter = convertDateStringsInFilter(filter, this.columnInfoService.leafNamedColumns); const clearFilter = Object.keys(processedFilter).length === 0; if (clearFilter) { this.ctx.grid.filterChange.next(undefined); } else if (processedFilter?.filters.length) { const currentFilter = this.ctx.grid.currentState.filter; let mergedFilter = processedFilter; if (currentFilter && currentFilter.filters?.length > 0) { mergedFilter = { logic: 'and', filters: [ currentFilter, processedFilter ] }; } this.ctx.grid.filterChange.next(mergedFilter); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AiAssistantComponent, deps: [{ token: i1.HttpClient }, { token: i2.ContextService }, { token: i3.ColumnInfoService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: AiAssistantComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "aiPrompt", first: true, predicate: AIPromptComponent, descendants: true }], ngImport: i0, template: ` <kendo-aiprompt #aiPrompt [promptSuggestions]="aiPromptSettings?.promptSuggestions" [showOutputRating]="aiPromptSettings?.showOutputRating" [streaming]="streaming" [speechToTextButton]="aiPromptSettings?.speechToTextButton" [(activeView)]="activeView" [generateButtonSVGIcon]="aiPromptSettings?.generateButtonSVGIcon" [generateButtonIcon]="aiPromptSettings?.generateButtonIcon" [disabledGenerateButton]="disabledGenerateButton || promptView.textAreaValue?.length === 0" [promptOutputs]="aiPromptSettings?.promptOutputs" [textAreaSettings]="aiPromptSettings?.textAreaSettings" (promptRequest)="onPromptRequest($event)" (promptRequestCancel)="cancelRequest()" > <kendo-aiprompt-prompt-view #promptView></kendo-aiprompt-prompt-view> <kendo-aiprompt-output-view></kendo-aiprompt-output-view> <ng-template *ngIf="streaming && aiPrompt.streaming" kendoAIPromptOutputTemplate let-output> <div class="k-card"> <div class="k-card-header"> <div class="k-card-title"> <span class="k-skeleton k-skeleton-text k-skeleton-pulse" [style.width.px]="200"></span> </div> <div class="k-card-subtitle"> <span class="k-skeleton k-skeleton-text k-skeleton-pulse" style="width: 100%;"></span> </div> </div> <div class="k-card-body"> <span class="k-skeleton k-skeleton-rect k-skeleton-pulse" style="height: 80px;"></span> </div> <div class="k-card-actions"> <span class="k-skeleton k-skeleton-text k-skeleton-pulse" style="width: 100%;"></span> </div> </div> </ng-template> <ng-template *ngIf="!(streaming && aiPrompt.streaming)" kendoAIPromptOutputBodyTemplate let-output> <p>{{output.output}}</p> </ng-template> <kendo-aiprompt-messages [generateOutput]="message('aiAssistantApplyButtonText')" ></kendo-aiprompt-messages> </kendo-aiprompt> `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: AIPromptComponent, selector: "kendo-aiprompt", inputs: ["activeView", "promptCommands", "promptSuggestions", "promptOutputs", "showOutputRating", "streaming", "speechToTextButton", "textAreaSettings", "generateButtonSVGIcon", "generateButtonIcon", "disabledGenerateButton"], outputs: ["activeViewChange", "promptRequest", "commandExecute", "outputCopy", "outputRatingChange", "promptRequestCancel"], exportAs: ["kendoAIPrompt"] }, { kind: "component", type: AIPromptCustomMessagesComponent, selector: "kendo-aiprompt-messages" }, { kind: "component", type: PromptViewComponent, selector: "kendo-aiprompt-prompt-view" }, { kind: "component", type: OutputViewComponent, selector: "kendo-aiprompt-output-view" }, { kind: "directive", type: AIPromptOutputTemplateDirective, selector: "[kendoAIPromptOutputTemplate]" }, { kind: "directive", type: AIPromptOutputBodyTemplateDirective, selector: "[kendoAIPromptOutputBodyTemplate]" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AiAssistantComponent, decorators: [{ type: Component, args: [{ standalone: true, imports: [NgIf, AIPromptComponent, AIPromptCustomMessagesComponent, PromptViewComponent, OutputViewComponent, AIPromptOutputTemplateDirective, AIPromptOutputBodyTemplateDirective], template: ` <kendo-aiprompt #aiPrompt [promptSuggestions]="aiPromptSettings?.promptSuggestions" [showOutputRating]="aiPromptSettings?.showOutputRating" [streaming]="streaming" [speechToTextButton]="aiPromptSettings?.speechToTextButton" [(activeView)]="activeView" [generateButtonSVGIcon]="aiPromptSettings?.generateButtonSVGIcon" [generateButtonIcon]="aiPromptSettings?.generateButtonIcon" [disabledGenerateButton]="disabledGenerateButton || promptView.textAreaValue?.length === 0" [promptOutputs]="aiPromptSettings?.promptOutputs" [textAreaSettings]="aiPromptSettings?.textAreaSettings" (promptRequest)="onPromptRequest($event)" (promptRequestCancel)="cancelRequest()" > <kendo-aiprompt-prompt-view #promptView></kendo-aiprompt-prompt-view> <kendo-aiprompt-output-view></kendo-aiprompt-output-view> <ng-template *ngIf="streaming && aiPrompt.streaming" kendoAIPromptOutputTemplate let-output> <div class="k-card"> <div class="k-card-header"> <div class="k-card-title"> <span class="k-skeleton k-skeleton-text k-skeleton-pulse" [style.width.px]="200"></span> </div> <div class="k-card-subtitle"> <span class="k-skeleton k-skeleton-text k-skeleton-pulse" style="width: 100%;"></span> </div> </div> <div class="k-card-body"> <span class="k-skeleton k-skeleton-rect k-skeleton-pulse" style="height: 80px;"></span> </div> <div class="k-card-actions"> <span class="k-skeleton k-skeleton-text k-skeleton-pulse" style="width: 100%;"></span> </div> </div> </ng-template> <ng-template *ngIf="!(streaming && aiPrompt.streaming)" kendoAIPromptOutputBodyTemplate let-output> <p>{{output.output}}</p> </ng-template> <kendo-aiprompt-messages [generateOutput]="message('aiAssistantApplyButtonText')" ></kendo-aiprompt-messages> </kendo-aiprompt> ` }] }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i2.ContextService }, { type: i3.ColumnInfoService }]; }, propDecorators: { aiPrompt: [{ type: ViewChild, args: [AIPromptComponent] }] } });