/* eslint-disable no-console */ import { FeedOptions } from "@azure/cosmos"; import { Callout, CommandBarButton, DirectionalHint, IconButton, Image, Link, Separator, Spinner, Stack, Text, TextField, } from "@fluentui/react"; import { QueryCopilotSampleContainerId, QueryCopilotSampleContainerSchema, QueryCopilotSampleDatabaseId, } from "Common/Constants"; import { getErrorMessage, handleError } from "Common/ErrorHandlingUtils"; import { shouldEnableCrossPartitionKey } from "Common/HeadersUtility"; import { MinimalQueryIterator } from "Common/IteratorUtilities"; import { queryDocuments } from "Common/dataAccess/queryDocuments"; import { queryDocumentsPage } from "Common/dataAccess/queryDocumentsPage"; import { QueryResults } from "Contracts/ViewModels"; import { CommandButtonComponentProps } from "Explorer/Controls/CommandButton/CommandButtonComponent"; import { EditorReact } from "Explorer/Controls/Editor/EditorReact"; import Explorer from "Explorer/Explorer"; import { useCommandBar } from "Explorer/Menus/CommandBar/CommandBarComponentAdapter"; import { SaveQueryPane } from "Explorer/Panes/SaveQueryPane/SaveQueryPane"; import { submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities"; import { QueryResultSection } from "Explorer/Tabs/QueryTab/QueryResultSection"; import { queryPagesUntilContentPresent } from "Utils/QueryUtils"; import { useQueryCopilot } from "hooks/useQueryCopilot"; import { useSidePanel } from "hooks/useSidePanel"; import React, { useState } from "react"; import SplitterLayout from "react-splitter-layout"; import CopilotIcon from "../../../images/Copilot.svg"; import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg"; import SaveQueryIcon from "../../../images/save-cosmos.svg"; import { useTabs } from "../../hooks/useTabs"; interface QueryCopilotTabProps { initialInput: string; explorer: Explorer; } interface GenerateSQLQueryResponse { apiVersion: string; sql: string; explanation: string; generateStart: string; generateEnd: string; } export const QueryCopilotTab: React.FC = ({ initialInput, explorer, }: QueryCopilotTabProps): JSX.Element => { const hideFeedbackModalForLikedQueries = useQueryCopilot((state) => state.hideFeedbackModalForLikedQueries); const [userInput, setUserInput] = useState(initialInput || ""); const [generatedQuery, setGeneratedQuery] = useState(""); const [query, setQuery] = useState(""); const [selectedQuery, setSelectedQuery] = useState(""); const [isGeneratingQuery, setIsGeneratingQuery] = useState(false); const [isExecuting, setIsExecuting] = useState(false); const [likeQuery, setLikeQuery] = useState(); const [showCallout, setShowCallout] = useState(false); const [queryIterator, setQueryIterator] = useState(); const [queryResults, setQueryResults] = useState(); const [errorMessage, setErrorMessage] = useState(""); const generateSQLQuery = async (): Promise => { try { setIsGeneratingQuery(true); useTabs.getState().setIsTabExecuting(true); const payload = { containerSchema: QueryCopilotSampleContainerSchema, userPrompt: userInput, }; const response = await fetch("https://copilotorchestrater.azurewebsites.net/generateSQLQuery", { method: "POST", headers: { "content-type": "application/json", }, body: JSON.stringify(payload), }); const generateSQLQueryResponse: GenerateSQLQueryResponse = await response?.json(); if (generateSQLQueryResponse?.sql) { let query = `-- ${userInput}\r\n`; if (generateSQLQueryResponse.explanation) { query += "-- **Explanation of query**\r\n"; query += `-- ${generateSQLQueryResponse.explanation}\r\n`; } query += generateSQLQueryResponse.sql; setQuery(query); setGeneratedQuery(generateSQLQueryResponse.sql); } } catch (error) { handleError(error, "executeNaturalLanguageQuery"); throw error; } finally { setIsGeneratingQuery(false); useTabs.getState().setIsTabExecuting(false); } }; const onExecuteQueryClick = async (): Promise => { const queryToExecute = selectedQuery || query; const queryIterator = queryDocuments(QueryCopilotSampleDatabaseId, QueryCopilotSampleContainerId, queryToExecute, { enableCrossPartitionQuery: shouldEnableCrossPartitionKey(), } as FeedOptions); setQueryIterator(queryIterator); setTimeout(async () => { await queryDocumentsPerPage(0, queryIterator); }, 100); }; const queryDocumentsPerPage = async (firstItemIndex: number, queryIterator: MinimalQueryIterator): Promise => { try { setIsExecuting(true); useTabs.getState().setIsTabExecuting(true); const queryResults: QueryResults = await queryPagesUntilContentPresent( firstItemIndex, async (firstItemIndex: number) => queryDocumentsPage(QueryCopilotSampleContainerId, queryIterator, firstItemIndex) ); setQueryResults(queryResults); setErrorMessage(""); } catch (error) { const errorMessage = getErrorMessage(error); setErrorMessage(errorMessage); handleError(errorMessage, "executeQueryCopilotTab"); } finally { setIsExecuting(false); useTabs.getState().setIsTabExecuting(false); } }; const getCommandbarButtons = (): CommandButtonComponentProps[] => { const executeQueryBtnLabel = selectedQuery ? "Execute Selection" : "Execute Query"; const executeQueryBtn = { iconSrc: ExecuteQueryIcon, iconAlt: executeQueryBtnLabel, onCommandClick: () => onExecuteQueryClick(), commandButtonLabel: executeQueryBtnLabel, ariaLabel: executeQueryBtnLabel, hasPopup: false, }; const saveQueryBtn = { iconSrc: SaveQueryIcon, iconAlt: "Save Query", onCommandClick: () => useSidePanel.getState().openSidePanel("Save Query", ), commandButtonLabel: "Save Query", ariaLabel: "Save Query", hasPopup: false, }; return [executeQueryBtn, saveQueryBtn]; }; React.useEffect(() => { useCommandBar.getState().setContextButtons(getCommandbarButtons()); }, [query, selectedQuery]); React.useEffect(() => { if (initialInput) { generateSQLQuery(); } }, []); return ( Copilot setUserInput(newValue)} style={{ lineHeight: 30 }} styles={{ root: { width: "90%" } }} disabled={isGeneratingQuery} /> generateSQLQuery()} /> {isGeneratingQuery && } AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.{" "} Read preview terms Provide feedback on the query generated {showCallout && !hideFeedbackModalForLikedQueries && ( { setShowCallout(false); submitFeedback({ generatedQuery, likeQuery, description: "", userPrompt: userInput }); }} directionalHint={DirectionalHint.topCenter} > Thank you. Need to give{" "} { setShowCallout(false); useQueryCopilot.getState().openFeedbackModal(generatedQuery, true, userInput); }} > more feedback? )} { setLikeQuery(true); setShowCallout(true); }} /> { setLikeQuery(false); setShowCallout(false); useQueryCopilot.getState().openFeedbackModal(generatedQuery, false, userInput); }} /> Copy code Delete code setQuery(newQuery)} onContentSelected={(selectedQuery: string) => setSelectedQuery(selectedQuery)} /> queryDocumentsPerPage(firstItemIndex, queryIterator)} /> ); };