diff --git a/src/Explorer/QueryCopilot/QueryCopilotTab.tsx b/src/Explorer/QueryCopilot/QueryCopilotTab.tsx index e94b3a979..0ae18f751 100644 --- a/src/Explorer/QueryCopilot/QueryCopilotTab.tsx +++ b/src/Explorer/QueryCopilot/QueryCopilotTab.tsx @@ -32,7 +32,7 @@ import { WelcomeModal } from "Explorer/QueryCopilot/Modal/WelcomeModal"; import { CopyPopup } from "Explorer/QueryCopilot/Popup/CopyPopup"; import { DeletePopup } from "Explorer/QueryCopilot/Popup/DeletePopup"; import { querySampleDocuments, submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities"; -import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/SamplePrompts/SamplePrompts"; +import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/Shared/SamplePrompts/SamplePrompts"; import { QueryResultSection } from "Explorer/Tabs/QueryTab/QueryResultSection"; import { Action } from "Shared/Telemetry/TelemetryConstants"; import { traceFailure, traceStart, traceSuccess } from "Shared/Telemetry/TelemetryProcessor"; diff --git a/src/Explorer/QueryCopilot/SamplePrompts/SamplePrompts.test.tsx b/src/Explorer/QueryCopilot/Shared/SamplePrompts/SamplePrompts.test.tsx similarity index 100% rename from src/Explorer/QueryCopilot/SamplePrompts/SamplePrompts.test.tsx rename to src/Explorer/QueryCopilot/Shared/SamplePrompts/SamplePrompts.test.tsx diff --git a/src/Explorer/QueryCopilot/SamplePrompts/SamplePrompts.tsx b/src/Explorer/QueryCopilot/Shared/SamplePrompts/SamplePrompts.tsx similarity index 96% rename from src/Explorer/QueryCopilot/SamplePrompts/SamplePrompts.tsx rename to src/Explorer/QueryCopilot/Shared/SamplePrompts/SamplePrompts.tsx index 070e66e84..4bb4a144d 100644 --- a/src/Explorer/QueryCopilot/SamplePrompts/SamplePrompts.tsx +++ b/src/Explorer/QueryCopilot/Shared/SamplePrompts/SamplePrompts.tsx @@ -1,8 +1,8 @@ import { DefaultButton, FontIcon, IconButton, Image, Modal, Stack, Text } from "@fluentui/react"; import React, { Dispatch, SetStateAction } from "react"; -import ComplexPrompts from "../../../../images/ComplexPrompts.svg"; -import IntermediatePrompts from "../../../../images/IntermediatePrompts.svg"; -import SimplePrompts from "../../../../images/SimplePrompts.svg"; +import ComplexPrompts from "../../../../../images/ComplexPrompts.svg"; +import IntermediatePrompts from "../../../../../images/IntermediatePrompts.svg"; +import SimplePrompts from "../../../../../images/SimplePrompts.svg"; export interface SamplePromptsProps { isSamplePromptsOpen: boolean; diff --git a/src/Explorer/QueryCopilot/SamplePrompts/__snapshots__/SamplePrompts.test.tsx.snap b/src/Explorer/QueryCopilot/Shared/SamplePrompts/__snapshots__/SamplePrompts.test.tsx.snap similarity index 100% rename from src/Explorer/QueryCopilot/SamplePrompts/__snapshots__/SamplePrompts.test.tsx.snap rename to src/Explorer/QueryCopilot/Shared/SamplePrompts/__snapshots__/SamplePrompts.test.tsx.snap diff --git a/src/Explorer/QueryCopilot/Sidebar/QueryCopilotSidebar.tsx b/src/Explorer/QueryCopilot/Sidebar/QueryCopilotSidebar.tsx deleted file mode 100644 index 84c1def96..000000000 --- a/src/Explorer/QueryCopilot/Sidebar/QueryCopilotSidebar.tsx +++ /dev/null @@ -1,243 +0,0 @@ -import { IButtonStyles, IconButton, Image, Stack, Text, TextField } from "@fluentui/react"; -import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/SamplePrompts/SamplePrompts"; -import { WelcomeSidebarPopup } from "Explorer/QueryCopilot/Sidebar/WelcomeSidebarPopup"; -import { useQueryCopilot } from "hooks/useQueryCopilot"; -import React from "react"; -import CopilotIcon from "../../../../images/CopilotSidebarLogo.svg"; -import HintIcon from "../../../../images/Hint.svg"; - -const sampleChatMessages: string[] = [ - "Write a query to return last 10 records in the database", - 'Write a query to return all records in this table created in the last thirty days which also have the record owner as "Contoso"', -]; - -const promptStyles: IButtonStyles = { - root: { border: "5px", selectors: { ":hover": { outline: "1px dashed #605e5c" } } }, - label: { fontWeight: 400, textAlign: "left", paddingLeft: 8 }, -}; - -export const QueryCopilotSidebar: React.FC = (): JSX.Element => { - const { - setWasCopilotUsed, - showCopilotSidebar, - setShowCopilotSidebar, - userPrompt, - setUserPrompt, - chatMessages, - setChatMessages, - showWelcomeSidebar, - isSamplePromptsOpen, - setIsSamplePromptsOpen, - } = useQueryCopilot(); - - const sampleProps: SamplePromptsProps = { - isSamplePromptsOpen: isSamplePromptsOpen, - setIsSamplePromptsOpen: setIsSamplePromptsOpen, - setTextBox: setUserPrompt, - }; - - const handleSendMessage = () => { - if (userPrompt.trim() !== "") { - setChatMessages([...chatMessages, userPrompt]); - setUserPrompt(""); - } - }; - - const handleInputChange = (value: string) => { - setUserPrompt(value); - }; - - const handleEnterKeyPress = (event: React.KeyboardEvent) => { - if (event.key === "Enter" && !event.shiftKey) { - event.preventDefault(); - handleSendMessage(); - } - }; - - React.useEffect(() => { - if (showCopilotSidebar) { - setWasCopilotUsed(true); - } - }, []); - - return ( - - - - - - Copilot - - Preview - - - setShowCopilotSidebar(false)} - iconProps={{ iconName: "Cancel" }} - title="Exit" - ariaLabel="Exit" - style={{ color: "#424242", verticalAlign: "middle" }} - /> - - - {showWelcomeSidebar ? ( - - - - ) : ( - <> - - {new Date().toLocaleDateString("en-US", { - month: "long", - day: "numeric", - })}{" "} - {new Date().toLocaleTimeString("en-US", { - hour: "numeric", - minute: "numeric", - hour12: true, - })} - - -
- - - Hello, I am Cosmos Db's copilot assistant. I can help you do the following things: - - - - - Generate queries based upon prompt you suggest - - - - - Explain and provide alternate queries for a query suggested by you - - - - - Help answer questions about Cosmos DB - - - - To get started, ask me a question or use one of the sample prompts to generate a query. AI-generated - content may be incorrect. - - - {chatMessages.map((message, index) => ( - - {message} - - ))} -
- - {chatMessages.length === 0 && ( - - handleInputChange(sampleChatMessages[0])} - style={{ - cursor: "pointer", - border: "1.5px solid #B0BEFF", - width: "100%", - padding: "2px", - borderRadius: "4px", - marginBottom: "5px", - }} - > - {sampleChatMessages[0]} - - handleInputChange(sampleChatMessages[1])} - style={{ - cursor: "pointer", - border: "1.5px solid #B0BEFF", - width: "100%", - padding: "2px", - borderRadius: "4px", - marginBottom: "5px", - }} - > - {sampleChatMessages[1]} - - - )} - - - - setIsSamplePromptsOpen(true)} /> - - - handleInputChange(newValue)} - onKeyDown={handleEnterKeyPress} - multiline - resizable={false} - styles={{ - root: { - width: "100%", - height: "80px", - borderRadius: "20px", - padding: "8px", - border: "none", - outline: "none", - marginLeft: "10px", - }, - fieldGroup: { border: "none" }, - }} - /> - - -
- - )} -
- ); -}; diff --git a/src/Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble.test.tsx b/src/Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble.test.tsx new file mode 100644 index 000000000..f32c152c2 --- /dev/null +++ b/src/Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble.test.tsx @@ -0,0 +1,10 @@ +import { shallow } from "enzyme"; +import React from "react"; +import { SampleBubble } from "./SampleBubble"; + +describe("Sample Bubble snapshot test", () => { + it("should render ", () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/src/Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble.tsx b/src/Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble.tsx new file mode 100644 index 000000000..001808fa8 --- /dev/null +++ b/src/Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble.tsx @@ -0,0 +1,42 @@ +import { Stack, Text } from "@fluentui/react"; +import { useQueryCopilot } from "hooks/useQueryCopilot"; +import React from "react"; + +export const SampleBubble: React.FC = (): JSX.Element => { + const { setUserPrompt } = useQueryCopilot(); + + const sampleChatMessages: string[] = [ + "Write a query to return last 10 records in the database", + 'Write a query to return all records in this table created in the last thirty days which also have the record owner as "Contoso"', + ]; + + return ( + + {sampleChatMessages.map((text, index) => ( + setUserPrompt(text)} + style={{ + cursor: "pointer", + border: "1.5px solid #B0BEFF", + width: "100%", + padding: "2px", + borderRadius: "4px", + marginBottom: "5px", + }} + > + {text} + + ))} + + ); +}; diff --git a/src/Explorer/QueryCopilot/V2/Bubbles/Sample/__snapshots__/SampleBubble.test.tsx.snap b/src/Explorer/QueryCopilot/V2/Bubbles/Sample/__snapshots__/SampleBubble.test.tsx.snap new file mode 100644 index 000000000..be3917fc4 --- /dev/null +++ b/src/Explorer/QueryCopilot/V2/Bubbles/Sample/__snapshots__/SampleBubble.test.tsx.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Sample Bubble snapshot test should render 1`] = ` + + + Write a query to return last 10 records in the database + + + Write a query to return all records in this table created in the last thirty days which also have the record owner as "Contoso" + + +`; diff --git a/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble.test.tsx b/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble.test.tsx new file mode 100644 index 000000000..54360f908 --- /dev/null +++ b/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble.test.tsx @@ -0,0 +1,13 @@ +import { shallow } from "enzyme"; +import React from "react"; +import { WelcomeBubble } from "./WelcomeBubble"; + +const mockedDate = new Date(2023, 7, 15); +jest.spyOn(global, "Date").mockImplementation(() => (mockedDate as unknown) as string); + +describe("Welcome Bubble snapshot test", () => { + it("should render ", () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble.tsx b/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble.tsx new file mode 100644 index 000000000..201c1b852 --- /dev/null +++ b/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble.tsx @@ -0,0 +1,52 @@ +import { Stack, Text } from "@fluentui/react"; +import React from "react"; + +export const WelcomeBubble: React.FC = (): JSX.Element => { + return ( + + + {new Date().toLocaleDateString("en-US", { + month: "long", + day: "numeric", + })}{" "} + {new Date().toLocaleTimeString("en-US", { + hour: "numeric", + minute: "numeric", + hour12: true, + })} + + + + Hello, I am Cosmos Db's copilot assistant. I can help you do the following things: + + + + + Generate queries based upon prompt you suggest + + + + + Explain and provide alternate queries for a query suggested by you + + + + + Help answer questions about Cosmos DB + + + + To get started, ask me a question or use one of the sample prompts to generate a query. AI-generated content + may be incorrect. + + + + ); +}; diff --git a/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/__snapshots__/WelcomeBubble.test.tsx.snap b/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/__snapshots__/WelcomeBubble.test.tsx.snap new file mode 100644 index 000000000..3f30e0b55 --- /dev/null +++ b/src/Explorer/QueryCopilot/V2/Bubbles/Welcome/__snapshots__/WelcomeBubble.test.tsx.snap @@ -0,0 +1,160 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Welcome Bubble snapshot test should render 1`] = ` + + + August 15 + + 12:00 AM + + + + Hello, I am Cosmos Db's copilot assistant. I can help you do the following things: + + + + + • + + + Generate queries based upon prompt you suggest + + + + + • + + + Explain and provide alternate queries for a query suggested by you + + + + + • + + + Help answer questions about Cosmos DB + + + + + To get started, ask me a question or use one of the sample prompts to generate a query. AI-generated content may be incorrect. + + + +`; diff --git a/src/Explorer/QueryCopilot/V2/Footer/Footer.test.tsx b/src/Explorer/QueryCopilot/V2/Footer/Footer.test.tsx new file mode 100644 index 000000000..cd302da12 --- /dev/null +++ b/src/Explorer/QueryCopilot/V2/Footer/Footer.test.tsx @@ -0,0 +1,10 @@ +import { shallow } from "enzyme"; +import React from "react"; +import { Footer } from "./Footer"; + +describe("Footer snapshot test", () => { + it("should render ", () => { + const wrapper = shallow(