diff --git a/src/Explorer/QueryCopilot/QueryCopilotTab.test.tsx b/src/Explorer/QueryCopilot/QueryCopilotTab.test.tsx index b3939f8b4..eb62cc22c 100644 --- a/src/Explorer/QueryCopilot/QueryCopilotTab.test.tsx +++ b/src/Explorer/QueryCopilot/QueryCopilotTab.test.tsx @@ -5,9 +5,7 @@ import { QueryCopilotTab } from "./QueryCopilotTab"; describe("Query copilot tab snapshot test", () => { it("should render with initial input", () => { - const wrapper = shallow( - - ); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); }); diff --git a/src/Explorer/QueryCopilot/QueryCopilotTab.tsx b/src/Explorer/QueryCopilot/QueryCopilotTab.tsx index 2a449e29d..e94b3a979 100644 --- a/src/Explorer/QueryCopilot/QueryCopilotTab.tsx +++ b/src/Explorer/QueryCopilot/QueryCopilotTab.tsx @@ -56,7 +56,6 @@ interface SuggestedPrompt { } interface QueryCopilotTabProps { - initialInput: string; explorer: Explorer; } @@ -73,32 +72,50 @@ const promptStyles: IButtonStyles = { label: { fontWeight: 400, textAlign: "left", paddingLeft: 8 }, }; -export const QueryCopilotTab: React.FC = ({ - initialInput, - explorer, -}: QueryCopilotTabProps): JSX.Element => { - const hideFeedbackModalForLikedQueries = useQueryCopilot((state) => state.hideFeedbackModalForLikedQueries); - const [userPrompt, setUserPrompt] = useState(initialInput || ""); - const [generatedQuery, setGeneratedQuery] = useState(""); - const [generatedQueryComments, setGeneratedQueryComments] = useState(""); - const [query, setQuery] = useState(""); - const [selectedQuery, setSelectedQuery] = useState(""); - const [isGeneratingQuery, setIsGeneratingQuery] = useState(false); - const [isExecuting, setIsExecuting] = useState(false); - const [likeQuery, setLikeQuery] = useState(); - const [dislikeQuery, setDislikeQuery] = useState(); - const [showCallout, setShowCallout] = useState(false); - const [showSamplePrompts, setShowSamplePrompts] = useState(false); - const [queryIterator, setQueryIterator] = useState(); - const [queryResults, setQueryResults] = useState(); - const [errorMessage, setErrorMessage] = useState(""); +export const QueryCopilotTab: React.FC = ({ explorer }: QueryCopilotTabProps): JSX.Element => { const [copilotTeachingBubbleVisible, { toggle: toggleCopilotTeachingBubbleVisible }] = useBoolean(false); const inputEdited = useRef(false); - const [isSamplePromptsOpen, setIsSamplePromptsOpen] = useState(false); - const [showDeletePopup, setShowDeletePopup] = useState(false); - const [showFeedbackBar, setShowFeedbackBar] = useState(false); - const [showCopyPopup, setshowCopyPopup] = useState(false); - const [showErrorMessageBar, setShowErrorMessageBar] = useState(false); + const { + hideFeedbackModalForLikedQueries, + userPrompt, + setUserPrompt, + generatedQuery, + setGeneratedQuery, + query, + setQuery, + selectedQuery, + setSelectedQuery, + isGeneratingQuery, + setIsGeneratingQuery, + isExecuting, + setIsExecuting, + likeQuery, + setLikeQuery, + dislikeQuery, + setDislikeQuery, + showCallout, + setShowCallout, + showSamplePrompts, + setShowSamplePrompts, + queryIterator, + setQueryIterator, + queryResults, + setQueryResults, + errorMessage, + setErrorMessage, + isSamplePromptsOpen, + setIsSamplePromptsOpen, + showDeletePopup, + setShowDeletePopup, + showFeedbackBar, + setShowFeedbackBar, + showCopyPopup, + setshowCopyPopup, + showErrorMessageBar, + setShowErrorMessageBar, + generatedQueryComments, + setGeneratedQueryComments, + } = useQueryCopilot(); const sampleProps: SamplePromptsProps = { isSamplePromptsOpen: isSamplePromptsOpen, @@ -301,9 +318,10 @@ export const QueryCopilotTab: React.FC = ({ return [executeQueryBtn, saveQueryBtn]; }; const showTeachingBubble = (): void => { - if (!inputEdited.current) { + const shouldShowTeachingBubble = !inputEdited.current && userPrompt.trim() === ""; + if (shouldShowTeachingBubble) { setTimeout(() => { - if (!inputEdited.current) { + if (shouldShowTeachingBubble) { toggleCopilotTeachingBubbleVisible(); inputEdited.current = true; } @@ -328,9 +346,6 @@ export const QueryCopilotTab: React.FC = ({ }, [query, selectedQuery]); React.useEffect(() => { - if (initialInput) { - generateSQLQuery(); - } showTeachingBubble(); useTabs.getState().setIsQueryErrorThrown(false); }, []); @@ -517,7 +532,12 @@ export const QueryCopilotTab: React.FC = ({ target="#likeBtn" onDismiss={() => { setShowCallout(false); - submitFeedback({ generatedQuery, likeQuery, description: "", userPrompt: userPrompt }); + submitFeedback({ + generatedQuery: generatedQuery, + likeQuery: likeQuery, + description: "", + userPrompt: userPrompt, + }); }} directionalHint={DirectionalHint.topCenter} > diff --git a/src/Explorer/QueryCopilot/__snapshots__/QueryCopilotTab.test.tsx.snap b/src/Explorer/QueryCopilot/__snapshots__/QueryCopilotTab.test.tsx.snap index 63f70e7ae..f945713cc 100644 --- a/src/Explorer/QueryCopilot/__snapshots__/QueryCopilotTab.test.tsx.snap +++ b/src/Explorer/QueryCopilot/__snapshots__/QueryCopilotTab.test.tsx.snap @@ -67,10 +67,10 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] = }, } } - value="Write a query to return all records in this table" + value="" /> ) => { event.stopPropagation(); tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind); + tabKind === ReactTabKind.QueryCopilot && useQueryCopilot.getState().resetQueryCopilotStates(); }} tabIndex={active ? 0 : undefined} onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)} @@ -251,7 +253,7 @@ const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): J case ReactTabKind.Quickstart: return ; case ReactTabKind.QueryCopilot: - return ; + return ; default: throw Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`); } diff --git a/src/hooks/useQueryCopilot.ts b/src/hooks/useQueryCopilot.ts index 7fab2dca6..a707ea56f 100644 --- a/src/hooks/useQueryCopilot.ts +++ b/src/hooks/useQueryCopilot.ts @@ -1,3 +1,5 @@ +import { MinimalQueryIterator } from "Common/IteratorUtilities"; +import { QueryResults } from "Contracts/ViewModels"; import { guid } from "Explorer/Tables/Utilities"; import create, { UseStore } from "zustand"; @@ -8,23 +10,126 @@ interface QueryCopilotState { showFeedbackModal: boolean; hideFeedbackModalForLikedQueries: boolean; correlationId: string; + query: string; + selectedQuery: string; + isGeneratingQuery: boolean; + isExecuting: boolean; + dislikeQuery: boolean | undefined; + showCallout: boolean; + showSamplePrompts: boolean; + queryIterator: MinimalQueryIterator | undefined; + queryResults: QueryResults | undefined; + errorMessage: string; + isSamplePromptsOpen: boolean; + showDeletePopup: boolean; + showFeedbackBar: boolean; + showCopyPopup: boolean; + showErrorMessageBar: boolean; + generatedQueryComments: string; + openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) => void; closeFeedbackModal: () => void; setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) => void; refreshCorrelationId: () => void; + setUserPrompt: (userPrompt: string) => void; + setQuery: (query: string) => void; + setGeneratedQuery: (generatedQuery: string) => void; + setSelectedQuery: (selectedQuery: string) => void; + setIsGeneratingQuery: (isGeneratingQuery: boolean) => void; + setIsExecuting: (isExecuting: boolean) => void; + setLikeQuery: (likeQuery: boolean) => void; + setDislikeQuery: (dislikeQuery: boolean | undefined) => void; + setShowCallout: (showCallout: boolean) => void; + setShowSamplePrompts: (showSamplePrompts: boolean) => void; + setQueryIterator: (queryIterator: MinimalQueryIterator | undefined) => void; + setQueryResults: (queryResults: QueryResults | undefined) => void; + setErrorMessage: (errorMessage: string) => void; + setIsSamplePromptsOpen: (isSamplePromptsOpen: boolean) => void; + setShowDeletePopup: (showDeletePopup: boolean) => void; + setShowFeedbackBar: (showFeedbackBar: boolean) => void; + setshowCopyPopup: (showCopyPopup: boolean) => void; + setShowErrorMessageBar: (showErrorMessageBar: boolean) => void; + setGeneratedQueryComments: (generatedQueryComments: string) => void; + resetQueryCopilotStates: () => void; } -export const useQueryCopilot: UseStore = create((set) => ({ +type QueryCopilotStore = UseStore; + +export const useQueryCopilot: QueryCopilotStore = create((set) => ({ generatedQuery: "", likeQuery: false, userPrompt: "", showFeedbackModal: false, hideFeedbackModalForLikedQueries: false, correlationId: "", + query: "", + selectedQuery: "", + isGeneratingQuery: false, + isExecuting: false, + dislikeQuery: undefined, + showCallout: false, + showSamplePrompts: false, + queryIterator: undefined, + queryResults: undefined, + errorMessage: "", + isSamplePromptsOpen: false, + showDeletePopup: false, + showFeedbackBar: false, + showCopyPopup: false, + showErrorMessageBar: false, + generatedQueryComments: "", + openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) => set({ generatedQuery, likeQuery, userPrompt, showFeedbackModal: true }), closeFeedbackModal: () => set({ generatedQuery: "", likeQuery: false, userPrompt: "", showFeedbackModal: false }), setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) => set({ hideFeedbackModalForLikedQueries }), refreshCorrelationId: () => set({ correlationId: guid() }), + setUserPrompt: (userPrompt: string) => set({ userPrompt }), + setQuery: (query: string) => set({ query }), + setGeneratedQuery: (generatedQuery: string) => set({ generatedQuery }), + setSelectedQuery: (selectedQuery: string) => set({ selectedQuery }), + setIsGeneratingQuery: (isGeneratingQuery: boolean) => set({ isGeneratingQuery }), + setIsExecuting: (isExecuting: boolean) => set({ isExecuting }), + setLikeQuery: (likeQuery: boolean) => set({ likeQuery }), + setDislikeQuery: (dislikeQuery: boolean | undefined) => set({ dislikeQuery }), + setShowCallout: (showCallout: boolean) => set({ showCallout }), + setShowSamplePrompts: (showSamplePrompts: boolean) => set({ showSamplePrompts }), + setQueryIterator: (queryIterator: MinimalQueryIterator | undefined) => set({ queryIterator }), + setQueryResults: (queryResults: QueryResults | undefined) => set({ queryResults }), + setErrorMessage: (errorMessage: string) => set({ errorMessage }), + setIsSamplePromptsOpen: (isSamplePromptsOpen: boolean) => set({ isSamplePromptsOpen }), + setShowDeletePopup: (showDeletePopup: boolean) => set({ showDeletePopup }), + setShowFeedbackBar: (showFeedbackBar: boolean) => set({ showFeedbackBar }), + setshowCopyPopup: (showCopyPopup: boolean) => set({ showCopyPopup }), + setShowErrorMessageBar: (showErrorMessageBar: boolean) => set({ showErrorMessageBar }), + setGeneratedQueryComments: (generatedQueryComments: string) => set({ generatedQueryComments }), + + resetQueryCopilotStates: () => { + set((state) => ({ + ...state, + generatedQuery: "", + likeQuery: false, + userPrompt: "", + showFeedbackModal: false, + hideFeedbackModalForLikedQueries: false, + correlationId: "", + query: "", + selectedQuery: "", + isGeneratingQuery: false, + isExecuting: false, + dislikeQuery: undefined, + showCallout: false, + showSamplePrompts: false, + queryIterator: undefined, + queryResults: undefined, + errorMessage: "", + isSamplePromptsOpen: false, + showDeletePopup: false, + showFeedbackBar: false, + showCopyPopup: false, + showErrorMessageBar: false, + generatedQueryComments: "", + })); + }, }));