@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
JavaScript
/**-----------------------------------------------------------------------------------------
* 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
}] } });