UNPKG

@progress/kendo-angular-grid

Version:

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

274 lines (273 loc) 12.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 { Directive, NgZone, ChangeDetectorRef, Input, Output, EventEmitter } from '@angular/core'; import { RefreshService, ToolBarButtonComponent } from '@progress/kendo-angular-toolbar'; import { isPresent } from '@progress/kendo-angular-common'; import { Subscription } from 'rxjs'; import { sparklesIcon, tableWizardIcon } from '@progress/kendo-svg-icons'; import { ContextService } from '../../../../common/provider.service'; import { filter, take } from 'rxjs/operators'; import { ToolbarToolBase } from '../../../../common/toolbar-tool-base.directive'; import { ToolbarToolName } from '../../../../navigation/toolbar-tool-name'; import { WindowService } from '@progress/kendo-angular-dialog'; import { AiAssistantComponent } from './ai-assistant.component'; import { DEFAULT_AI_REQUEST_OPTIONS } from './utils'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-dialog"; import * as i2 from "@progress/kendo-angular-toolbar"; import * as i3 from "../../../../common/provider.service"; /** * Represents an AI Assistant tool of the Grid. * Use this directive on any `kendo-toolbar-button` inside a ToolbarComponent in the Grid. * * @example * ```html-no-run * <kendo-grid> * <kendo-toolbar> * <kendo-toolbar-button kendoGridAIAssistantTool></kendo-toolbar-button> * </kendo-toolbar> * </kendo-grid> * ``` * @remarks * Applied to: {@link ToolBarButtonComponent}. */ export class AIAssistantToolbarDirective extends ToolbarToolBase { windowService; host; ctx; zone; refresh; /** * The URL to which the AI Assistant tool sends the AI request. * - When you set this property, the AI Assistant tool sends and handles an HTTP request to the provided `requestUrl`. You can handle the `promptRequest` event to modify the request options before the tool sends it. * - When you do not set this property, the AI Assistant tool does not send an HTTP request. You should handle the `promptRequest` event to send and handle a custom HTTP request. */ requestUrl; /** * Configures the request options that the AI Assistant tool sends with the AI request. * * @default { headers: new HttpHeaders({ 'Content-Type': 'application/json' }), role: 'user', method: 'POST', responseType: 'json', withCredentials: false } */ requestOptions; /** * Configures the initial settings for the AI Assistant Window when opened. */ aiWindowSettings; /** * Configures the initial settings for the AI Prompt component that the AI Assistant Window component uses when opened. */ aiPromptSettings; /** * Determines whether to close the AI Assistant Window automatically after a successful request. * @default true */ autoClose = true; /** * Determines whether to keep the AI Prompt's outputs after closing the AI Assistant Window. * @default false */ keepOutputHistory = false; /** * Emits an event before the AI Assistant tool sends the AI request. * - When you provide a `requestUrl`, you can handle the event to modify the request options. * - When you do not provide a `requestUrl`, you can handle the event to perform an entirely custom request. */ promptRequest = new EventEmitter(); /** * Emits an event when the user clicks the cancel button. */ cancelRequest = new EventEmitter(); /** * Emits an event when the AI Assistant tool completes the AI request successfully. * The event contains the response from the AI service and is preventable to allow stopping the default response handling. */ responseSuccess = new EventEmitter(); /** * Emits an event when the AI Assistant tool completes the AI request with an error. * The event contains the error response from the AI service and is preventable to allow stopping the default error handling. */ responseError = new EventEmitter(); /** * Emits an event when the AI Assistant tool closes. */ close = new EventEmitter(); /** * Emits an event when the AI Assistant tool opens. */ open = new EventEmitter(); tableWizardIcon = tableWizardIcon; emitOpenClose = false; promptOutputs = []; windowRef; subs = new Subscription(); defaultAiPromptSettings = { speechToTextButton: true, generateButtonSVGIcon: this.tableWizardIcon, generateButtonIcon: 'table-wizard' }; constructor(windowService, host, ctx, zone, refresh, cdr) { super(host, ToolbarToolName.aiAssistant, ctx, zone, cdr); this.windowService = windowService; this.host = host; this.ctx = ctx; this.zone = zone; this.refresh = refresh; this.host.rounded = 'full'; this.host.themeColor = 'primary'; this.host.showText = 'never'; } ngOnInit() { this.subs.add(this.host.click.subscribe(() => this.onClick())); const hasToolbarIcon = isPresent(this.host.toolbarOptions.icon) && this.host.toolbarOptions.icon !== ''; const hasOverflowIcon = isPresent(this.host.overflowOptions.icon) && this.host.overflowOptions.icon !== ''; const hasIcon = hasToolbarIcon && hasOverflowIcon; const hasSvgIcon = isPresent(this.host.toolbarOptions.svgIcon) && isPresent(this.host.overflowOptions.svgIcon); if (!hasIcon) { this.host.icon = 'sparkles'; } if (!hasSvgIcon) { this.host.svgIcon = sparklesIcon; } this.requestOptions = { ...DEFAULT_AI_REQUEST_OPTIONS, ...this.requestOptions }; } ngAfterViewInit() { super.ngAfterViewInit(); this.zone.onStable.pipe(take(1)).subscribe(() => { this.buttonElement?.setAttribute('aria-haspopup', 'dialog'); this.buttonElement?.setAttribute('aria-expanded', 'false'); const needsTitle = this.host.showText !== 'always' && this.host.showText !== 'toolbar'; if (needsTitle && !this.host.title) { this.buttonElement?.setAttribute('title', this.ctx.localization.get('aiAssistantToolbarToolText')); } }); this.subs.add(this.refresh.onRefresh.pipe(filter((tool) => tool === this.host)).subscribe((tool) => { if (tool.overflows && this.windowRef) { this.windowRef.close(); } })); } ngOnDestroy() { super.ngOnDestroy(); this.subs.unsubscribe(); this.promptOutputs = []; } /** * @hidden */ onClick() { this.emitOpenClose = true; this.toggleWindow(); } /** * Toggles the AI Assistant window. */ toggleWindow() { if (!this.windowRef) { this.openWindow(); } else { this.closeWindow(); } } openWindow() { if (!this.keepOutputHistory) { this.promptOutputs = []; } const defaultWindowWidth = 437; const rtl = this.ctx.localization.rtl; const defaultWindowSettings = { left: rtl ? this.buttonElement.offsetLeft - (this.aiWindowSettings.width || defaultWindowWidth) : this.buttonElement.offsetLeft + this.buttonElement.offsetWidth, top: this.buttonElement.offsetTop + this.buttonElement.offsetHeight, width: defaultWindowWidth, title: this.ctx.localization.get('aiAssistantWindowTitle'), cssClass: 'k-grid-assistant-window', content: AiAssistantComponent, autoFocusedElement: '.k-input-inner', appendTo: this.ctx.grid.windowContainer }; this.aiWindowSettings = { ...defaultWindowSettings, ...this.aiWindowSettings }; this.windowRef = this.windowService.open(this.aiWindowSettings); this.windowRef.window.instance.messages = { closeTitle: this.ctx.localization.get('aiAssistantWindowCloseTitle'), maximizeTitle: this.ctx.localization.get('aiAssistantWindowMaximizeTitle'), minimizeTitle: this.ctx.localization.get('aiAssistantWindowMinimizeTitle'), restoreTitle: this.ctx.localization.get('aiAssistantWindowRestoreTitle') }; const aiPrompt = this.windowRef.content.instance; aiPrompt.requestUrl = this.requestUrl; aiPrompt.requestOptions = this.requestOptions; aiPrompt.aiToolDirective = this; aiPrompt.disabledGenerateButton = this.aiPromptSettings?.disabledGenerateButton; aiPrompt.streaming = this.aiPromptSettings?.streaming || false; aiPrompt.activeView = this.aiPromptSettings?.activeView || 0; aiPrompt.aiPromptSettings = { ...this.defaultAiPromptSettings, ...this.aiPromptSettings }; if (!aiPrompt.aiPromptSettings.promptOutputs) { aiPrompt.aiPromptSettings.promptOutputs = this.promptOutputs; } if (this.emitOpenClose) { this.zone.onStable.pipe(take(1)).subscribe(() => { const event = { aiWindow: this.windowRef.window.instance, aiPrompt: this.windowRef.content.instance.aiPrompt }; this.open.emit(event); this.emitOpenClose = false; }); } this.subs.add(this.windowRef.window.instance.close.subscribe(() => { this.emitOpenClose = true; this.closeWindow(true); })); this.host.selected = true; } closeWindow(focusAnchor = false) { this.windowRef.close(); if (this.emitOpenClose) { this.close.emit(); this.emitOpenClose = false; } this.windowRef = null; this.buttonElement?.setAttribute('aria-expanded', 'false'); this.buttonElement?.removeAttribute('aria-controls'); this.host.selected = false; focusAnchor && this.buttonElement?.focus(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AIAssistantToolbarDirective, deps: [{ token: i1.WindowService }, { token: i2.ToolBarButtonComponent }, { token: i3.ContextService }, { token: i0.NgZone }, { token: i2.RefreshService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: AIAssistantToolbarDirective, isStandalone: true, selector: "[kendoGridAIAssistantTool]", inputs: { requestUrl: "requestUrl", requestOptions: "requestOptions", aiWindowSettings: "aiWindowSettings", aiPromptSettings: "aiPromptSettings", autoClose: "autoClose", keepOutputHistory: "keepOutputHistory" }, outputs: { promptRequest: "promptRequest", cancelRequest: "cancelRequest", responseSuccess: "responseSuccess", responseError: "responseError", close: "close", open: "open" }, usesInheritance: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AIAssistantToolbarDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoGridAIAssistantTool]', standalone: true }] }], ctorParameters: function () { return [{ type: i1.WindowService }, { type: i2.ToolBarButtonComponent }, { type: i3.ContextService }, { type: i0.NgZone }, { type: i2.RefreshService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { requestUrl: [{ type: Input }], requestOptions: [{ type: Input }], aiWindowSettings: [{ type: Input }], aiPromptSettings: [{ type: Input }], autoClose: [{ type: Input }], keepOutputHistory: [{ type: Input }], promptRequest: [{ type: Output }], cancelRequest: [{ type: Output }], responseSuccess: [{ type: Output }], responseError: [{ type: Output }], close: [{ type: Output }], open: [{ type: Output }] } });