UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

609 lines (504 loc) 23.2 kB
import './kendo.core.js'; import './kendo.icons.js'; import './kendo.textarea.js'; import './kendo.button.js'; import './kendo.panelbar.js'; import './kendo.licensing.js'; import '@progress/kendo-licensing'; import './kendo.html.icon.js'; import './kendo.html.base.js'; import '@progress/kendo-svg-icons'; import './kendo.floatinglabel.js'; import './prefix-suffix-containers-B9VRe3lS.js'; import './kendo.badge.js'; import './kendo.html.button.js'; import './kendo.data.js'; import './kendo.data.odata.js'; import './kendo.data.xml.js'; (function($) { let Widget = kendo.ui.Widget; const messageTypes = { "ai": "assistant", "user": "user"}; const KDISABLED = "k-disabled"; const isFunction = kendo.isFunction; let AIPromptBaseView = kendo.ui.AIPromptBaseView = Widget.extend({ init: function(element, options) { let that = this; Widget.fn.init.call(that, element, options); that.aiprompt = element.getKendoAIPrompt(); that.contentElement = that.options.contentElement; that.footerElement = that.options.footerElement; that.buttonText = that.options.buttonText; that.buttonIcon = that.options.buttonIcon; that.service = that.options.service; }, options: { name: "AIPromptBaseView", buttonText: "", buttonIcon: "", }, render: function() { let that = this; that._renderContent(); that._renderFooter(); }, _renderContentElement: function() { let that = this; let content = $("<div></div>").addClass("k-prompt-content"); that.contentElement = content; that.element.append(content); return that.contentElement; }, _renderFooterElement: function() { let that = this; let footer = $("<div></div>").addClass("k-prompt-footer"); that.footerElement = footer; that.element.append(footer); return that.footerElement; }, _ajaxRequest: function(prompt, isRetry, history) { let that = this; let service = that.service; let data = that._getAjaxData(prompt, isRetry, history); const url = typeof service === "string" ? service : service.url; const requestOptions = { url: url, type: "POST", contentType: "application/json", data: JSON.stringify(data), success: (response) => that._ajaxSuccessHandler(response, isRetry, prompt), }; if (service?.headers) { requestOptions.headers = service.headers; } kendo.ui.progress(that.contentElement, true); return $.ajax(requestOptions); }, _ajaxSuccessHandler: function(response, isRetry, prompt) { const that = this; const outputGetter = that.service?.outputGetter || that._getResponseMessageText; const output = { id: kendo.guid(), output: outputGetter(response), prompt: prompt, isRetry: isRetry, activeView: 1 }; that.aiprompt.trigger("promptResponse", { output }); that.aiprompt.addPromptOutput(output); that.aiprompt.activeView(output.activeView); if (!isRetry) { const generateButton = that.footerElement.find("button[ref-generate-output-button]"); generateButton.removeClass(KDISABLED); } kendo.ui.progress(that.contentElement, false); }, _getResponseMessageText: function(response) { return response?.Message?.Text || "An error occurred while processing the request."; }, _getAjaxData: function(prompt, isRetry, history) { const that = this; const service = that.service; let defaultData = [ { role: { value: messageTypes.user }, text: prompt } ]; if (history?.length) { defaultData = history.concat(defaultData); } if (typeof service === "string") { return defaultData; } if (kendo.isPresent(service.data) && Object.keys(service.data).length) { service.data.messages = defaultData; return service.data; } if (isFunction(service?.data)) { return service.data(prompt, isRetry, history); } if ($.isPlainObject(service) && kendo.isPresent(service.url)) { return defaultData; } throw new Error("Invalid AIPrompt service configuration."); }, destroy: function() { let that = this; Widget.fn.destroy.call(that); if (that.contentElement) { that.contentElement.off(); kendo.destroy(that.contentElement); that.contentElement.remove(); } if (that.footerElement) { that.footerElement.off(); kendo.destroy(that.footerElement); that.footerElement.remove(); } } }); let DEFAULT_PROMPT_VIEW_TEMPLATE = ({ suggestions, promptSuggestionItemTemplate, messages }) => `<div class="k-prompt-view"> <textarea ref-prompt-input></textarea> ${suggestions?.length ? `<div class="k-prompt-expander"> <button ref-prompt-suggestions-button aria-expanded="true">${messages.promptSuggestions}</button> <div class="k-prompt-expander-content" role="list"> ${suggestions.map(suggestion => promptSuggestionItemTemplate({ suggestion })).join("")} </div> </div>` : '' } </div>`; let DEFAULT_PROMPT_VIEW_FOOTER_TEMPLATE = ({ messages }) => `<div class="k-actions k-actions-start k-actions-horizontal k-prompt-actions"> <button ref-generate-output-button>${messages.generateOutput}</button> </div>`; let DEFAULT_PROMPT_VIEW_SUGGESTION_ITEM_TEMPLATE = ({ suggestion }) => `<div role="listitem" class="k-prompt-suggestion">${suggestion}</div>`; kendo.ui.AIPromptPromptView = AIPromptBaseView.extend({ init: function(element, options) { let that = this; AIPromptBaseView.fn.init.call(that, element, options); that.promptSuggestions = that.options.promptSuggestions; that.promptSuggestionItemTemplate = kendo.template(that.options.promptSuggestionItemTemplate || DEFAULT_PROMPT_VIEW_SUGGESTION_ITEM_TEMPLATE); }, options: { name: "AIPromptPromptView", buttonIcon: "sparkles", }, _renderContent: function() { let that = this; let suggestions = that.promptSuggestions; let promptSuggestionItemTemplate = that.promptSuggestionItemTemplate; let content = kendo.template(that.options.viewTemplate || DEFAULT_PROMPT_VIEW_TEMPLATE)({ suggestions, promptSuggestionItemTemplate, messages: that.options.messages }); that._renderContentElement(); that.contentElement.append(content); }, _renderFooter: function() { let that = this; let footer = kendo.template(that.options.footerTemplate || DEFAULT_PROMPT_VIEW_FOOTER_TEMPLATE)({ messages: that.options.messages }); that._renderFooterElement(); that.footerElement.append(footer); }, setTextAreaValue: function(value) { let that = this; that.contentElement.find("textarea[ref-prompt-input]").getKendoTextArea().value(value); }, _focusSuggestion(element) { let that = this; if (!element || !element.length) { return; } that.contentElement.find(".k-prompt-suggestion[tabindex=0]").attr("tabindex", "-1"); element.attr("tabindex", "0").trigger("focus"); }, initializeComponents: function() { let that = this; let suggestions = that.promptSuggestions; const generateButton = that.footerElement.find("button[ref-generate-output-button]"); that.contentElement.find("textarea[ref-prompt-input]").kendoTextArea({ resize: "vertical", placeholder: that.options.messages.promptPlaceholder }); generateButton.kendoButton({ icon: "sparkles", themeColor: "primary", rounded: "full", click: function(e) { const prompt = that.contentElement.find("textarea[ref-prompt-input]").getKendoTextArea().value(); const eventArgs = { prompt, isRetry: false, history: [] }; that.aiprompt.trigger("promptRequest", eventArgs); generateButton.addClass(KDISABLED); if (that.service) { that._ajaxRequest(prompt, false, eventArgs.history); } } }); if (suggestions?.length) { that.contentElement.find(".k-prompt-suggestion").first().attr("tabindex", "0"); let nextExpanderContentId = kendo.guid(); let expanderButton = that.contentElement.find(".k-prompt-expander button[ref-prompt-suggestions-button]"); that.contentElement.find(".k-prompt-expander button[ref-prompt-suggestions-button]").attr("aria-controls", nextExpanderContentId); expanderButton.next(".k-prompt-expander-content").attr("id", nextExpanderContentId); that.contentElement.find(".k-prompt-expander button[ref-prompt-suggestions-button]").kendoButton({ icon: "chevron-up", fillMode: "flat", click: function(e) { let expander = $(e.target).closest(".k-prompt-expander"); let content = expander.find(".k-prompt-expander-content"); let iconEl = e.sender.element.find(".k-icon"); kendo.ui.icon(iconEl, content.is(":visible") ? "chevron-down" : "chevron-up"); content.toggle(); e.sender.element.attr("aria-expanded", content.is(":visible")); } }); that.contentElement.on("click", ".k-prompt-suggestion", function(e) { that.setTextAreaValue($(e.target).text()); }); that.contentElement.on("keydown", ".k-prompt-suggestion", function(e) { if (e.keyCode === 40 || e.keyCode === 38 || e.keyCode === 36 || e.keyCode === 35 || e.keyCode === 13 || e.keyCode === 32) { e.preventDefault(); let target = $(e.target); let siblings = target.siblings(); let next, prev; // down arrow if (e.keyCode === 40) { next = target.next(); that._focusSuggestion(next); } // up arrow if (e.keyCode === 38) { prev = target.prev(); that._focusSuggestion(prev); } // home if (e.keyCode === 36) { prev = siblings.first(); that._focusSuggestion(prev); } // end if (e.keyCode === 35) { next = siblings.last(); that._focusSuggestion(next); } // enter or space if (e.keyCode === 13 || e.keyCode === 32) { that.setTextAreaValue($(e.target).text()); } } }); } }, render: function() { let that = this; that._renderContent(); that._renderFooter(); that.initializeComponents(); }, }); let DEFAULT_OUTPUT_CARD_TEMPLATE_FUNC = ({ output, showOutputRating, messages }) => ` <div role="listitem" tabindex="0" class="k-card" data-id="${output.id}" > <div class="k-card-header"> <div class="k-card-title">${messages.outputTitle}</div> <div class="k-card-subtitle">${output.prompt}</div> </div> <div class="k-card-body"> <p class="k-white-space-pre-line">${output.output}</p> </div> <div class="k-actions k-actions-start k-actions-horizontal k-card-actions"> <button ref-copy-button>${messages.copyOutput}</button> <button ref-retry-button>${messages.retryGeneration}</button> <span class="k-spacer"></span> ${showOutputRating ? ` <button ref-rate-positive title=${messages.ratePositive ? messages.ratePositive : 'Helpful'}>${messages.ratePositive}</button> <button ref-rate-negative title=${messages.rateNegative ? messages.rateNegative : 'Unhelpful'}>${messages.rateNegative}</button> ` : ""} </div> </div>`; let DEFAULT_OUTPUT_VIEW_TEMPLATE = ({ promptOutputs, showOutputRating, messages }) => `<div class="k-prompt-view"><div role="list" class="k-card-list"> ${promptOutputs ? promptOutputs.map(output => DEFAULT_OUTPUT_CARD_TEMPLATE_FUNC({ output, showOutputRating, messages })).join("") : ''} </div></div>`; kendo.ui.AIPromptOutputView = AIPromptBaseView.extend({ init: function(element, options) { let that = this; AIPromptBaseView.fn.init.call(that, element, options); that.promptOutputs = (that.options.promptOutputs || []).map(output => { output.id = output.id || kendo.guid(); return output; }); that.showOutputRating = that.options.showOutputRating; }, options: { name: "AIPromptOutputView", buttonIcon: "comment", promptOutputs: [] }, addPromptOutput: function(output) { let that = this; output.id = output.id || kendo.guid(); that.promptOutputs.unshift(output); that.renderPromptOutput(output); }, renderPromptOutput: function(output) { let that = this; let showOutputRating = that.options.showOutputRating; let messages = that.options.messages; let card = $(kendo.template(DEFAULT_OUTPUT_CARD_TEMPLATE_FUNC)({ output, showOutputRating, messages })); that.outputsContainer.append(card); that.initializeComponents(card); }, _renderContent: function() { let that = this; let promptOutputs = that.promptOutputs; let showOutputRating = that.options.showOutputRating; let messages = that.options.messages; let outputsContainer = kendo.template(that.viewTemplate || DEFAULT_OUTPUT_VIEW_TEMPLATE)({ promptOutputs, showOutputRating, messages }); that.outputsContainer = $(outputsContainer); that._renderContentElement(); that.contentElement.append(that.outputsContainer); }, _getOutputFromElement: function(element) { let that = this; let card = $(element).closest(".k-card"); let id = card.data("id"); let promptOutput = that.promptOutputs.find(output => output.id === id); return promptOutput; }, initializeComponents: function(parentElement) { let that = this; parentElement = parentElement || that.contentElement; parentElement.find("[ref-copy-button]").kendoButton({ icon: "copy", fillMode: "flat", themeColor: "primary", click: function(e) { let promptOutput = that._getOutputFromElement(e.target); if (!that.aiprompt.trigger("outputCopy", { output: promptOutput, prompt: promptOutput.prompt })) { if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") { navigator.clipboard.writeText(promptOutput.output); } } } }); parentElement.find("[ref-retry-button]").kendoButton({ icon: "arrow-rotate-cw", fillMode: "flat", click: function(e) { let promptOutput = that._getOutputFromElement(e.target); const history = { role: { value: messageTypes.ai }, text: promptOutput.output }; const eventArgs = { prompt: promptOutput.prompt, output: promptOutput, isRetry: true, history: [history] }; that.aiprompt.trigger("promptRequest", eventArgs); if (that.service) { that._ajaxRequest(promptOutput.prompt, true, eventArgs.history); } } }); if (that.options.showOutputRating) { parentElement.find("[ref-rate-positive]").kendoButton({ icon: "thumb-up-outline", fillMode: "flat", click: function(e) { let promptOutput = that._getOutputFromElement(e.target); let rateType = "positive"; that.aiprompt.trigger("outputRatingChange", { rateType, output: promptOutput }); kendo.ui.icon(e.sender.element.find(".k-icon"), "thumb-up"); kendo.ui.icon(e.target.next("[ref-rate-negative]").find(".k-icon"), "thumb-down-outline"); } }); parentElement.find("[ref-rate-negative]").kendoButton({ icon: "thumb-down-outline", fillMode: "flat", click: function(e) { let promptOutput = that._getOutputFromElement(e.target); let rateType = "negative"; that.aiprompt.trigger("outputRatingChange", { rateType, output: promptOutput }); kendo.ui.icon(e.sender.element.find(".k-icon"), "thumb-down"); kendo.ui.icon(e.target.prev("[ref-rate-positive]").find(".k-icon"), "thumb-up-outline"); } }); } }, render: function() { let that = this; that._renderContent(); that.initializeComponents(); that.contentElement.on("keydown", ".k-card", function(e) { let target = $(e.target); // if up or down arrow, focus next or previous card // if home or end, focus first or last card if (e.keyCode === 40 || e.keyCode === 38 || e.keyCode === 36 || e.keyCode === 35) { e.preventDefault(); // down arrow if (e.keyCode === 40) { target.next(".k-card").trigger("focus"); } // up arrow if (e.keyCode === 38) { target.prev(".k-card").trigger("focus"); } // home if (e.keyCode === 36) { that.contentElement.find(".k-card").first().trigger("focus"); } // end if (e.keyCode === 35) { that.contentElement.find(".k-card").last().trigger("focus"); } } }); } }); kendo.ui.AIPromptCommandsView = AIPromptBaseView.extend({ options: { name: "AIPromptCommandsView", buttonText: "", buttonIcon: "more-horizontal", promptCommands: [] }, initializeComponents: function() { let that = this; let commandItems = that.options.promptCommands; let panelBarEl = $("<div></div>").kendoPanelBar({ animation: false, dataSource: commandItems, selectable: false, select: function(ev) { let item = $(ev.item); let dataItem = this.dataItem(item); if (dataItem.hasChildren) { return; } that.aiprompt.trigger("commandExecute", { sender: that.aiprompt, item: dataItem }); } }); const promptViewWrapper = $("<div class='k-prompt-view'>"); promptViewWrapper.append(panelBarEl); that.contentElement.append(promptViewWrapper); }, render: function() { let that = this; that._renderContentElement(); that.initializeComponents(); }, }); let EMPTY_TEMPLATE = () => ""; kendo.ui.AIPromptCustomView = AIPromptBaseView.extend({ options: { name: "AIPromptCustomView", buttonText: "", buttonIcon: "", viewTemplate: EMPTY_TEMPLATE, footerTemplate: EMPTY_TEMPLATE, }, initializeComponents: function() { let that = this; if (typeof that.options.initializeComponents === "function") { that.options.initializeComponents.call(that); } }, _renderContent: function() { let that = this; let content = kendo.template(that.options.viewTemplate)({ aiprompt: that }); that._renderContentElement(); that.contentElement.append(content); }, _renderFooter: function() { let that = this; if (that.options.footerTemplate === EMPTY_TEMPLATE) { return; } let footer = kendo.template(that.options.footerTemplate)({ messages: that.options.messages }); that._renderFooterElement(); that.footerElement.append(footer); }, render: function() { let that = this; that._renderContent(); that._renderFooter(); that.initializeComponents(); }, }); })(window.kendo.jQuery); var kendo$1 = kendo; export { kendo$1 as default };