mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-19 08:51:24 +00:00
[Query Copilot v2] Implementing output bubble (#1587)
* Implementing output bubble * Fix lint * Run prettier
This commit is contained in:
@@ -13,8 +13,14 @@ export interface EditorReactProps {
|
||||
ariaLabel: string; // Sets what will be read to the user to define the control
|
||||
onContentSelected?: (selectedContent: string) => void; // Called when text is selected
|
||||
onContentChanged?: (newContent: string) => void; // Called when text is changed
|
||||
lineNumbers?: monaco.editor.IEditorOptions["lineNumbers"];
|
||||
theme?: string; // Monaco editor theme
|
||||
wordWrap?: monaco.editor.IEditorOptions["wordWrap"];
|
||||
lineNumbers?: monaco.editor.IEditorOptions["lineNumbers"];
|
||||
lineNumbersMinChars?: monaco.editor.IEditorOptions["lineNumbersMinChars"];
|
||||
lineDecorationsWidth?: monaco.editor.IEditorOptions["lineDecorationsWidth"];
|
||||
minimap?: monaco.editor.IEditorOptions["minimap"];
|
||||
scrollBeyondLastLine?: monaco.editor.IEditorOptions["scrollBeyondLastLine"];
|
||||
monacoContainerStyles?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export class EditorReact extends React.Component<EditorReactProps, EditorReactStates> {
|
||||
@@ -54,7 +60,11 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
|
||||
return (
|
||||
<React.Fragment>
|
||||
{!this.state.showEditor && <Spinner size={SpinnerSize.large} className="spinner" />}
|
||||
<div className="jsonEditor" ref={(elt: HTMLElement) => this.setRef(elt)} />
|
||||
<div
|
||||
className="jsonEditor"
|
||||
style={this.props.monacoContainerStyles}
|
||||
ref={(elt: HTMLElement) => this.setRef(elt)}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -84,14 +94,19 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
|
||||
*/
|
||||
private async createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
|
||||
const options: monaco.editor.IEditorConstructionOptions = {
|
||||
value: this.props.content,
|
||||
language: this.props.language,
|
||||
value: this.props.content,
|
||||
readOnly: this.props.isReadOnly,
|
||||
lineNumbers: this.props.lineNumbers || "off",
|
||||
fontSize: 12,
|
||||
ariaLabel: this.props.ariaLabel,
|
||||
theme: this.props.theme,
|
||||
fontSize: 12,
|
||||
automaticLayout: true,
|
||||
theme: this.props.theme,
|
||||
wordWrap: this.props.wordWrap || "off",
|
||||
lineNumbers: this.props.lineNumbers || "off",
|
||||
lineNumbersMinChars: this.props.lineNumbersMinChars,
|
||||
lineDecorationsWidth: this.props.lineDecorationsWidth,
|
||||
minimap: this.props.minimap,
|
||||
scrollBeyondLastLine: this.props.scrollBeyondLastLine,
|
||||
};
|
||||
|
||||
this.rootNode.innerHTML = "";
|
||||
|
||||
@@ -55,7 +55,7 @@ exports[`TreeNodeComponent does not render children by default 1`] = `
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<span
|
||||
@@ -158,7 +158,7 @@ exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`]
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<span
|
||||
@@ -309,7 +309,7 @@ exports[`TreeNodeComponent renders loading icon 1`] = `
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<span
|
||||
@@ -383,7 +383,7 @@ exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<span
|
||||
@@ -553,7 +553,7 @@ exports[`TreeNodeComponent renders unsorted children by default 1`] = `
|
||||
className="expandCollapseIcon"
|
||||
onKeyPress={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<span
|
||||
|
||||
@@ -128,7 +128,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="Delete"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</AccessibleElement>
|
||||
</td>
|
||||
@@ -185,7 +185,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="Delete"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</AccessibleElement>
|
||||
</td>
|
||||
@@ -203,7 +203,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="Add"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
Add Property
|
||||
</AccessibleElement>
|
||||
@@ -317,7 +317,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="Delete"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</AccessibleElement>
|
||||
</td>
|
||||
@@ -379,7 +379,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="Delete"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</AccessibleElement>
|
||||
</td>
|
||||
@@ -397,7 +397,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="Add"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
Add Property
|
||||
</AccessibleElement>
|
||||
|
||||
@@ -22,7 +22,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="in progress items"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<span
|
||||
className="numInProgress"
|
||||
@@ -35,7 +35,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="error items"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<span
|
||||
className="numErroredItems"
|
||||
@@ -48,7 +48,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="info items"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<span
|
||||
className="numInfoItems"
|
||||
@@ -150,7 +150,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
|
||||
>
|
||||
<img
|
||||
alt="clear notifications image"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
Clear Notifications
|
||||
</span>
|
||||
@@ -185,7 +185,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
|
||||
>
|
||||
<img
|
||||
alt="in progress items"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<span
|
||||
className="numInProgress"
|
||||
@@ -198,7 +198,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
|
||||
>
|
||||
<img
|
||||
alt="error items"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<span
|
||||
className="numErroredItems"
|
||||
@@ -211,7 +211,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
|
||||
>
|
||||
<img
|
||||
alt="info items"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<span
|
||||
className="numInfoItems"
|
||||
@@ -315,7 +315,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
|
||||
>
|
||||
<img
|
||||
alt="clear notifications image"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
Clear Notifications
|
||||
</span>
|
||||
@@ -330,7 +330,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
|
||||
<img
|
||||
alt="info"
|
||||
className="infoIcon"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<span
|
||||
className="date"
|
||||
|
||||
@@ -4340,7 +4340,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||
id="deleteparam"
|
||||
onClick={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
width={20}
|
||||
>
|
||||
<ImageBase
|
||||
@@ -4350,7 +4350,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||
id="deleteparam"
|
||||
onClick={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
@@ -4640,12 +4640,12 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||
alt="Delete param"
|
||||
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
|
||||
id="deleteparam"
|
||||
key="fabricImage"
|
||||
key="fabricImage[object Object]"
|
||||
onClick={[Function]}
|
||||
onError={[Function]}
|
||||
onLoad={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</div>
|
||||
</ImageBase>
|
||||
@@ -4661,7 +4661,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||
id="addparam"
|
||||
onClick={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
width={20}
|
||||
>
|
||||
<ImageBase
|
||||
@@ -4671,7 +4671,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||
id="addparam"
|
||||
onClick={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
@@ -4961,12 +4961,12 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||
alt="Add param"
|
||||
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
|
||||
id="addparam"
|
||||
key="fabricImage"
|
||||
key="fabricImage[object Object]"
|
||||
onClick={[Function]}
|
||||
onError={[Function]}
|
||||
onLoad={[Function]}
|
||||
role="button"
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</div>
|
||||
</ImageBase>
|
||||
@@ -4989,13 +4989,13 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||
alt="Add param"
|
||||
height={30}
|
||||
key=".0:$.0"
|
||||
src=""
|
||||
src={Object {}}
|
||||
width={20}
|
||||
>
|
||||
<ImageBase
|
||||
alt="Add param"
|
||||
height={30}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
@@ -5284,10 +5284,10 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
||||
<img
|
||||
alt="Add param"
|
||||
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
|
||||
key="fabricImage"
|
||||
key="fabricImage[object Object]"
|
||||
onError={[Function]}
|
||||
onLoad={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</div>
|
||||
</ImageBase>
|
||||
|
||||
@@ -39,7 +39,7 @@ exports[`Load Query Pane should render Default properly 1`] = `
|
||||
className="fileIcon"
|
||||
height={20}
|
||||
imageFit={4}
|
||||
src=""
|
||||
src={Object {}}
|
||||
width={20}
|
||||
/>
|
||||
<input
|
||||
|
||||
@@ -44,13 +44,13 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
|
||||
alt="Add Property"
|
||||
height={30}
|
||||
key=".0:$.0"
|
||||
src=""
|
||||
src={Object {}}
|
||||
width={16}
|
||||
>
|
||||
<ImageBase
|
||||
alt="Add Property"
|
||||
height={30}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
@@ -339,10 +339,10 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
|
||||
<img
|
||||
alt="Add Property"
|
||||
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-55"
|
||||
key="fabricImage"
|
||||
key="fabricImage[object Object]"
|
||||
onError={[Function]}
|
||||
onLoad={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</div>
|
||||
</ImageBase>
|
||||
|
||||
@@ -39,13 +39,13 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
|
||||
alt="Add Entity"
|
||||
height={30}
|
||||
key=".0:$.0"
|
||||
src=""
|
||||
src={Object {}}
|
||||
width={16}
|
||||
>
|
||||
<ImageBase
|
||||
alt="Add Entity"
|
||||
height={30}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
@@ -334,10 +334,10 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
|
||||
<img
|
||||
alt="Add Entity"
|
||||
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-55"
|
||||
key="fabricImage"
|
||||
key="fabricImage[object Object]"
|
||||
onError={[Function]}
|
||||
onLoad={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</div>
|
||||
</ImageBase>
|
||||
|
||||
@@ -20,7 +20,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
||||
>
|
||||
<StackItem>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
@@ -84,7 +84,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
||||
className="imageTextPadding"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</StackItem>
|
||||
<StackItem
|
||||
@@ -120,7 +120,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
||||
className="imageTextPadding"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</StackItem>
|
||||
<StackItem
|
||||
@@ -156,7 +156,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
||||
className="imageTextPadding"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
</StackItem>
|
||||
<StackItem
|
||||
|
||||
@@ -40,7 +40,7 @@ exports[`Copy Popup snapshot test should render when showCopyPopup is true 1`] =
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
style={
|
||||
Object {
|
||||
"height": 15,
|
||||
|
||||
@@ -87,7 +87,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
style={
|
||||
Object {
|
||||
"height": 25,
|
||||
@@ -191,7 +191,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
style={
|
||||
Object {
|
||||
"height": 25,
|
||||
@@ -295,7 +295,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
style={
|
||||
Object {
|
||||
"height": 25,
|
||||
@@ -477,7 +477,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
style={
|
||||
Object {
|
||||
"height": 25,
|
||||
@@ -581,7 +581,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
style={
|
||||
Object {
|
||||
"height": 25,
|
||||
@@ -685,7 +685,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
style={
|
||||
Object {
|
||||
"height": 25,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { IconButton } from "@fluentui/react";
|
||||
import { CopyButton } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/Copy/CopyButton";
|
||||
import { shallow } from "enzyme";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
|
||||
document.execCommand = jest.fn();
|
||||
|
||||
describe("Copy button snapshot tests", () => {
|
||||
it("should render and click copy", async () => {
|
||||
const testInput = "test input query";
|
||||
useQueryCopilot.getState().setGeneratedQuery(testInput);
|
||||
const wrapper = shallow(<CopyButton />);
|
||||
|
||||
const button = wrapper.find(IconButton).first();
|
||||
button.simulate("click", {});
|
||||
|
||||
expect(document.execCommand).toHaveBeenCalledWith("copy");
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { IconButton } from "@fluentui/react";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
import CopilotCopy from "../../../../../../../../images/CopilotCopy.svg";
|
||||
|
||||
export const CopyButton: React.FC = (): JSX.Element => {
|
||||
const copyGeneratedCode = (): void => {
|
||||
const queryElement = document.createElement("textarea");
|
||||
queryElement.value = useQueryCopilot.getState().generatedQuery;
|
||||
document.body.appendChild(queryElement);
|
||||
queryElement.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(queryElement);
|
||||
};
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
iconProps={{ imageProps: { src: CopilotCopy } }}
|
||||
ariaLabel="Copy"
|
||||
onClick={copyGeneratedCode}
|
||||
></IconButton>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Copy button snapshot tests should render and click copy 1`] = `
|
||||
<CustomizedIconButton
|
||||
ariaLabel="Copy"
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": Object {},
|
||||
},
|
||||
}
|
||||
}
|
||||
onClick={[Function]}
|
||||
/>
|
||||
`;
|
||||
@@ -0,0 +1,205 @@
|
||||
import { Callout, IconButton, Link } from "@fluentui/react";
|
||||
import { useId } from "@fluentui/react-hooks";
|
||||
import { FeedbackButtons } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/Feedback/FeedbackButtons";
|
||||
import { shallow } from "enzyme";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
import LikeHover from "../../../../../../../../images/CopilotLikeHover.svg";
|
||||
import LikePressed from "../../../../../../../../images/CopilotLikePressed.svg";
|
||||
import LikeRest from "../../../../../../../../images/CopilotLikeRest.svg";
|
||||
|
||||
useId as jest.Mock;
|
||||
|
||||
jest.mock("../../../../../../../../images/CopilotLikeHover.svg", () => "LikeHover");
|
||||
jest.mock("../../../../../../../../images/CopilotLikePressed.svg", () => "LikePressed");
|
||||
jest.mock("../../../../../../../../images/CopilotLikeRest.svg", () => "LikeRest");
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe("Feedback buttons snapshot tests", () => {
|
||||
it("should click like and show callout", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let likeButton = wrapper.find(IconButton).first();
|
||||
const dislikeButton = wrapper.find(IconButton).last();
|
||||
likeButton.simulate("click");
|
||||
likeButton = wrapper.find(IconButton).first();
|
||||
const callout = wrapper.find(Callout).first();
|
||||
|
||||
expect(likeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikeRest);
|
||||
expect(callout.exists()).toBeTruthy();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should click like and dismiss callout", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
const likeButton = wrapper.find(IconButton).first();
|
||||
likeButton.simulate("click");
|
||||
let callout = wrapper.find(Callout).first();
|
||||
callout.simulate("dismiss");
|
||||
callout = wrapper.find(Callout).first();
|
||||
|
||||
expect(callout.exists()).toBeFalsy();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should click like and submit feedback", () => {
|
||||
const spy = jest.spyOn(useQueryCopilot.getState(), "openFeedbackModal");
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
const likeButton = wrapper.find(IconButton).first();
|
||||
likeButton.simulate("click");
|
||||
const link = wrapper.find(Link).first();
|
||||
link.simulate("click");
|
||||
|
||||
expect(spy).toHaveBeenNthCalledWith(1, "", true, "");
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hover over like", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let likeButton = wrapper.find(IconButton).first();
|
||||
likeButton.simulate("mouseover");
|
||||
likeButton = wrapper.find(IconButton).first();
|
||||
|
||||
expect(likeButton.props().iconProps.imageProps.src).toEqual(LikeHover);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hover over rest like and leave", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let likeButton = wrapper.find(IconButton).first();
|
||||
likeButton.simulate("mouseover");
|
||||
likeButton.simulate("mouseleave");
|
||||
likeButton = wrapper.find(IconButton).first();
|
||||
|
||||
expect(likeButton.props().iconProps.imageProps.src).toEqual(LikeRest);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hover over pressed like and leave", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let likeButton = wrapper.find(IconButton).first();
|
||||
likeButton.simulate("click");
|
||||
likeButton = wrapper.find(IconButton).first();
|
||||
likeButton.simulate("mouseover");
|
||||
likeButton.simulate("mouseleave");
|
||||
|
||||
expect(likeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hover over like and click", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let likeButton = wrapper.find(IconButton).first();
|
||||
likeButton.simulate("mouseover");
|
||||
likeButton.simulate("click");
|
||||
likeButton = wrapper.find(IconButton).first();
|
||||
|
||||
expect(likeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should dobule click on like", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let likeButton = wrapper.find(IconButton).first();
|
||||
likeButton.simulate("click");
|
||||
likeButton = wrapper.find(IconButton).first();
|
||||
expect(likeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
|
||||
likeButton.simulate("click");
|
||||
likeButton = wrapper.find(IconButton).first();
|
||||
expect(likeButton.props().iconProps.imageProps.src).toEqual(LikeRest);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should click dislike and show popup", () => {
|
||||
const spy = jest.spyOn(useQueryCopilot.getState(), "openFeedbackModal");
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
const likeButton = wrapper.find(IconButton).first();
|
||||
let dislikeButton = wrapper.find(IconButton).last();
|
||||
dislikeButton.simulate("click");
|
||||
const callout = wrapper.find(Callout).first();
|
||||
dislikeButton = wrapper.find(IconButton).last();
|
||||
|
||||
expect(likeButton.props().iconProps.imageProps.src).toEqual(LikeRest);
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
expect(spy).toHaveBeenNthCalledWith(1, "", false, "");
|
||||
expect(callout.exists()).toBeFalsy();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hover over dislike", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let dislikeButton = wrapper.find(IconButton).last();
|
||||
dislikeButton.simulate("mouseover");
|
||||
dislikeButton = wrapper.find(IconButton).last();
|
||||
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikeHover);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hover over rest dislike and leave", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let dislikeButton = wrapper.find(IconButton).last();
|
||||
dislikeButton.simulate("mouseover");
|
||||
dislikeButton.simulate("mouseleave");
|
||||
dislikeButton = wrapper.find(IconButton).last();
|
||||
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikeRest);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hover over pressed dislike and leave", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let dislikeButton = wrapper.find(IconButton).last();
|
||||
dislikeButton.simulate("click");
|
||||
dislikeButton = wrapper.find(IconButton).last();
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
dislikeButton.simulate("mouseover");
|
||||
dislikeButton.simulate("mouseleave");
|
||||
dislikeButton = wrapper.find(IconButton).last();
|
||||
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should hover over dislike and click", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let dislikeButton = wrapper.find(IconButton).last();
|
||||
dislikeButton.simulate("mouseover");
|
||||
dislikeButton.simulate("click");
|
||||
dislikeButton = wrapper.find(IconButton).last();
|
||||
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should dobule click on dislike", () => {
|
||||
const wrapper = shallow(<FeedbackButtons />);
|
||||
|
||||
let dislikeButton = wrapper.find(IconButton).last();
|
||||
dislikeButton.simulate("click");
|
||||
dislikeButton = wrapper.find(IconButton).last();
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikePressed);
|
||||
|
||||
dislikeButton.simulate("click");
|
||||
dislikeButton = wrapper.find(IconButton).last();
|
||||
expect(dislikeButton.props().iconProps.imageProps.src).toEqual(LikeRest);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
import { Callout, DirectionalHint, IconButton, Link, Stack, Text } from "@fluentui/react";
|
||||
import { useId } from "@fluentui/react-hooks";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React, { useState } from "react";
|
||||
import LikeHover from "../../../../../../../../images/CopilotLikeHover.svg";
|
||||
import LikePressed from "../../../../../../../../images/CopilotLikePressed.svg";
|
||||
import LikeRest from "../../../../../../../../images/CopilotLikeRest.svg";
|
||||
|
||||
export const FeedbackButtons: React.FC = (): JSX.Element => {
|
||||
const { generatedQuery, userPrompt } = useQueryCopilot();
|
||||
|
||||
const [likeQuery, setLikeQuery] = useState<boolean>(false);
|
||||
const [dislikeQuery, setDislikeQuery] = useState<boolean>(false);
|
||||
const [likeImageLink, setLikeImageLink] = useState<string>(LikeRest);
|
||||
const [dislikeImageLink, setDislikeImageLink] = useState<string>(LikeRest);
|
||||
const [calloutVisible, setCalloutVisible] = useState<boolean>(false);
|
||||
const likeBtnId = useId("likeBtn");
|
||||
const dislikeBtnId = useId("dislikeBtn");
|
||||
|
||||
return (
|
||||
<Stack horizontal>
|
||||
{calloutVisible && (
|
||||
<Callout
|
||||
target={`#${likeBtnId}`}
|
||||
onDismiss={() => setCalloutVisible(false)}
|
||||
directionalHint={DirectionalHint.topCenter}
|
||||
role="dialog"
|
||||
style={{ padding: "5px 12px 5px 12px", borderRadius: "4px" }}
|
||||
styles={{ beakCurtain: { borderRadius: "4px" }, root: { borderRadius: "4px" } }}
|
||||
>
|
||||
<Text>
|
||||
{" "}
|
||||
<Text>
|
||||
Thank you. Need to give{" "}
|
||||
<Link
|
||||
onClick={() => {
|
||||
setCalloutVisible(false);
|
||||
useQueryCopilot.getState().openFeedbackModal(generatedQuery, true, userPrompt);
|
||||
}}
|
||||
>
|
||||
more feedback?
|
||||
</Link>
|
||||
</Text>
|
||||
</Text>
|
||||
</Callout>
|
||||
)}
|
||||
|
||||
<IconButton
|
||||
id={likeBtnId}
|
||||
iconProps={{
|
||||
imageProps: { src: likeImageLink },
|
||||
style: { minHeight: "18px" },
|
||||
}}
|
||||
onClick={() => {
|
||||
if (likeQuery) {
|
||||
setLikeQuery(false);
|
||||
setLikeImageLink(LikeRest);
|
||||
setCalloutVisible(false);
|
||||
} else {
|
||||
setLikeQuery(true);
|
||||
setDislikeQuery(false);
|
||||
setLikeImageLink(LikePressed);
|
||||
setDislikeImageLink(LikeRest);
|
||||
setCalloutVisible(true);
|
||||
}
|
||||
}}
|
||||
onMouseOver={() => setLikeImageLink(LikeHover)}
|
||||
onMouseLeave={() => setLikeImageLink(likeQuery ? LikePressed : LikeRest)}
|
||||
/>
|
||||
<IconButton
|
||||
id={dislikeBtnId}
|
||||
iconProps={{
|
||||
imageProps: { src: dislikeImageLink },
|
||||
style: { minHeight: "18px", transform: "rotate(180deg)" },
|
||||
}}
|
||||
onClick={() => {
|
||||
if (dislikeQuery) {
|
||||
setDislikeQuery(false);
|
||||
setDislikeImageLink(LikeRest);
|
||||
} else {
|
||||
setDislikeQuery(true);
|
||||
setLikeQuery(false);
|
||||
setDislikeImageLink(LikePressed);
|
||||
setLikeImageLink(LikeRest);
|
||||
useQueryCopilot.getState().openFeedbackModal(generatedQuery, false, userPrompt);
|
||||
}
|
||||
}}
|
||||
onMouseOver={() => setDislikeImageLink(LikeHover)}
|
||||
onMouseLeave={() => setDislikeImageLink(dislikeQuery ? LikePressed : LikeRest)}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,666 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Feedback buttons snapshot tests should click dislike and show popup 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn16"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikePressed",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn17"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should click like and dismiss callout 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikePressed",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn2"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn3"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should click like and show callout 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<Callout
|
||||
directionalHint={1}
|
||||
onDismiss={[Function]}
|
||||
role="dialog"
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "4px",
|
||||
"padding": "5px 12px 5px 12px",
|
||||
}
|
||||
}
|
||||
styles={
|
||||
Object {
|
||||
"beakCurtain": Object {
|
||||
"borderRadius": "4px",
|
||||
},
|
||||
"root": Object {
|
||||
"borderRadius": "4px",
|
||||
},
|
||||
}
|
||||
}
|
||||
target="#likeBtn0"
|
||||
>
|
||||
<Text>
|
||||
|
||||
<Text>
|
||||
Thank you. Need to give
|
||||
|
||||
<StyledLinkBase
|
||||
onClick={[Function]}
|
||||
>
|
||||
more feedback?
|
||||
</StyledLinkBase>
|
||||
</Text>
|
||||
</Text>
|
||||
</Callout>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikePressed",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn0"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn1"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should click like and submit feedback 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikePressed",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn4"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn5"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should dobule click on dislike 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn26"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn27"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should dobule click on like 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn14"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn15"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should hover over dislike 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn18"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeHover",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn19"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should hover over dislike and click 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn24"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikePressed",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn25"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should hover over like 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeHover",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn6"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn7"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should hover over like and click 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<Callout
|
||||
directionalHint={1}
|
||||
onDismiss={[Function]}
|
||||
role="dialog"
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "4px",
|
||||
"padding": "5px 12px 5px 12px",
|
||||
}
|
||||
}
|
||||
styles={
|
||||
Object {
|
||||
"beakCurtain": Object {
|
||||
"borderRadius": "4px",
|
||||
},
|
||||
"root": Object {
|
||||
"borderRadius": "4px",
|
||||
},
|
||||
}
|
||||
}
|
||||
target="#likeBtn12"
|
||||
>
|
||||
<Text>
|
||||
|
||||
<Text>
|
||||
Thank you. Need to give
|
||||
|
||||
<StyledLinkBase
|
||||
onClick={[Function]}
|
||||
>
|
||||
more feedback?
|
||||
</StyledLinkBase>
|
||||
</Text>
|
||||
</Text>
|
||||
</Callout>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikePressed",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn12"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn13"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should hover over pressed dislike and leave 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn22"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikePressed",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn23"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should hover over pressed like and leave 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<Callout
|
||||
directionalHint={1}
|
||||
onDismiss={[Function]}
|
||||
role="dialog"
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "4px",
|
||||
"padding": "5px 12px 5px 12px",
|
||||
}
|
||||
}
|
||||
styles={
|
||||
Object {
|
||||
"beakCurtain": Object {
|
||||
"borderRadius": "4px",
|
||||
},
|
||||
"root": Object {
|
||||
"borderRadius": "4px",
|
||||
},
|
||||
}
|
||||
}
|
||||
target="#likeBtn10"
|
||||
>
|
||||
<Text>
|
||||
|
||||
<Text>
|
||||
Thank you. Need to give
|
||||
|
||||
<StyledLinkBase
|
||||
onClick={[Function]}
|
||||
>
|
||||
more feedback?
|
||||
</StyledLinkBase>
|
||||
</Text>
|
||||
</Text>
|
||||
</Callout>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikePressed",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn10"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn11"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should hover over rest dislike and leave 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn20"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn21"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`Feedback buttons snapshot tests should hover over rest like and leave 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="likeBtn8"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": "LikeRest",
|
||||
},
|
||||
"style": Object {
|
||||
"minHeight": "18px",
|
||||
"transform": "rotate(180deg)",
|
||||
},
|
||||
}
|
||||
}
|
||||
id="dislikeBtn9"
|
||||
onClick={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { ActionButton } from "@fluentui/react";
|
||||
import { InsertButton } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/Insert/InsertButton";
|
||||
import { shallow } from "enzyme";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
|
||||
describe("Insert button snapshot tests", () => {
|
||||
it("should click and update state", () => {
|
||||
const testQuery = "test query";
|
||||
useQueryCopilot.getState().setGeneratedQuery(testQuery);
|
||||
const wrapper = shallow(<InsertButton />);
|
||||
|
||||
const button = wrapper.find(ActionButton).first();
|
||||
button.simulate("click");
|
||||
|
||||
expect(useQueryCopilot.getState().query).toEqual(testQuery);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import { ActionButton } from "@fluentui/react";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
import CopilotInsert from "../../../../../../../../images/CopilotInsert.svg";
|
||||
|
||||
export const InsertButton: React.FC = (): JSX.Element => {
|
||||
return (
|
||||
<ActionButton
|
||||
iconProps={{ imageProps: { src: CopilotInsert } }}
|
||||
style={{ borderRadius: "4px", borderWidth: "1px", borderColor: "#D1D1D1", height: "24px", paddingBottom: "2px" }}
|
||||
onClick={() => useQueryCopilot.getState().setQuery(useQueryCopilot.getState().generatedQuery)}
|
||||
>
|
||||
Insert
|
||||
</ActionButton>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Insert button snapshot tests should click and update state 1`] = `
|
||||
<CustomizedActionButton
|
||||
iconProps={
|
||||
Object {
|
||||
"imageProps": Object {
|
||||
"src": Object {},
|
||||
},
|
||||
}
|
||||
}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderColor": "#D1D1D1",
|
||||
"borderRadius": "4px",
|
||||
"borderWidth": "1px",
|
||||
"height": "24px",
|
||||
"paddingBottom": "2px",
|
||||
}
|
||||
}
|
||||
>
|
||||
Insert
|
||||
</CustomizedActionButton>
|
||||
`;
|
||||
@@ -0,0 +1,11 @@
|
||||
import { MoreButton } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/More/MoreButton";
|
||||
import { shallow } from "enzyme";
|
||||
import React from "react";
|
||||
|
||||
describe("More button snapshot tests", () => {
|
||||
it("should render", () => {
|
||||
const wrapper = shallow(<MoreButton />);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
import { DirectionalHint, IContextualMenuProps, IconButton } from "@fluentui/react";
|
||||
import React from "react";
|
||||
import ExplainIcon from "../../../../../../../../images/CopilotExplain.svg";
|
||||
import OptimizeIcon from "../../../../../../../../images/CopilotOptimize.svg";
|
||||
import RegenerateIcon from "../../../../../../../../images/CopilotRegenerate.svg";
|
||||
import SimplifyIcon from "../../../../../../../../images/CopilotSimplify.svg";
|
||||
|
||||
export const MoreButton: React.FC = (): JSX.Element => {
|
||||
const menuProps: IContextualMenuProps = {
|
||||
items: [
|
||||
{
|
||||
key: "regenerate",
|
||||
text: "Regenerate code",
|
||||
iconProps: { imageProps: { src: RegenerateIcon } },
|
||||
},
|
||||
{
|
||||
key: "explain",
|
||||
text: "Explain code",
|
||||
iconProps: { imageProps: { src: ExplainIcon } },
|
||||
},
|
||||
{
|
||||
key: "optimize",
|
||||
text: "Optimize",
|
||||
iconProps: { imageProps: { src: OptimizeIcon } },
|
||||
},
|
||||
{
|
||||
key: "simplify",
|
||||
text: "Simplify",
|
||||
iconProps: { imageProps: { src: SimplifyIcon } },
|
||||
},
|
||||
],
|
||||
directionalHint: DirectionalHint.topRightEdge,
|
||||
calloutProps: {
|
||||
styles: { calloutMain: { borderRadius: "4px" }, root: { borderRadius: "4px" } },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<IconButton iconProps={{ iconName: "More" }} menuProps={menuProps} menuIconProps={{ hidden: true }}></IconButton>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`More button snapshot tests should render 1`] = `
|
||||
<CustomizedIconButton
|
||||
iconProps={
|
||||
Object {
|
||||
"iconName": "More",
|
||||
}
|
||||
}
|
||||
menuIconProps={
|
||||
Object {
|
||||
"hidden": true,
|
||||
}
|
||||
}
|
||||
menuProps={
|
||||
Object {
|
||||
"calloutProps": Object {
|
||||
"styles": Object {
|
||||
"calloutMain": Object {
|
||||
"borderRadius": "4px",
|
||||
},
|
||||
"root": Object {
|
||||
"borderRadius": "4px",
|
||||
},
|
||||
},
|
||||
},
|
||||
"directionalHint": 2,
|
||||
"items": Array [
|
||||
Object {
|
||||
"iconProps": Object {
|
||||
"imageProps": Object {
|
||||
"src": Object {},
|
||||
},
|
||||
},
|
||||
"key": "regenerate",
|
||||
"text": "Regenerate code",
|
||||
},
|
||||
Object {
|
||||
"iconProps": Object {
|
||||
"imageProps": Object {
|
||||
"src": Object {},
|
||||
},
|
||||
},
|
||||
"key": "explain",
|
||||
"text": "Explain code",
|
||||
},
|
||||
Object {
|
||||
"iconProps": Object {
|
||||
"imageProps": Object {
|
||||
"src": Object {},
|
||||
},
|
||||
},
|
||||
"key": "optimize",
|
||||
"text": "Optimize",
|
||||
},
|
||||
Object {
|
||||
"iconProps": Object {
|
||||
"imageProps": Object {
|
||||
"src": Object {},
|
||||
},
|
||||
},
|
||||
"key": "simplify",
|
||||
"text": "Simplify",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
@@ -0,0 +1,11 @@
|
||||
import { OutputBubbleButtons } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/OutputBubbleButtons";
|
||||
import { shallow } from "enzyme";
|
||||
import React from "react";
|
||||
|
||||
describe("Output Bubble Buttons snapshot tests", () => {
|
||||
it("should render", () => {
|
||||
const wrapper = shallow(<OutputBubbleButtons />);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Stack } from "@fluentui/react";
|
||||
import { CopyButton } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/Copy/CopyButton";
|
||||
import { FeedbackButtons } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/Feedback/FeedbackButtons";
|
||||
import { InsertButton } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/Insert/InsertButton";
|
||||
import { MoreButton } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/More/MoreButton";
|
||||
import React from "react";
|
||||
|
||||
export const OutputBubbleButtons: React.FC = (): JSX.Element => {
|
||||
return (
|
||||
<Stack horizontal>
|
||||
<Stack.Item style={{ paddingTop: "5px" }}>
|
||||
<InsertButton />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<CopyButton />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<FeedbackButtons />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<MoreButton />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Output Bubble Buttons snapshot tests should render 1`] = `
|
||||
<Stack
|
||||
horizontal={true}
|
||||
>
|
||||
<StackItem
|
||||
style={
|
||||
Object {
|
||||
"paddingTop": "5px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<InsertButton />
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<CopyButton />
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<FeedbackButtons />
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<MoreButton />
|
||||
</StackItem>
|
||||
</Stack>
|
||||
`;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
|
||||
import { OutputBubble } from "Explorer/QueryCopilot/V2/Bubbles/Output/OutputBubble";
|
||||
import { shallow } from "enzyme";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import { withHooks } from "jest-react-hooks-shallow";
|
||||
import React from "react";
|
||||
|
||||
describe("Output Bubble snapshot tests", () => {
|
||||
it("should render and update height", () => {
|
||||
withHooks(() => {
|
||||
useQueryCopilot.getState().setGeneratedQuery("test query");
|
||||
useQueryCopilot.getState().setGeneratedQueryComments("test comments");
|
||||
const wrapper = shallow(<OutputBubble />);
|
||||
|
||||
const editor = wrapper.find(EditorReact).first();
|
||||
|
||||
expect(editor.props().monacoContainerStyles).not.toHaveProperty("height", undefined);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
60
src/Explorer/QueryCopilot/V2/Bubbles/Output/OutputBubble.tsx
Normal file
60
src/Explorer/QueryCopilot/V2/Bubbles/Output/OutputBubble.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Stack, Text } from "@fluentui/react";
|
||||
import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
|
||||
import { OutputBubbleButtons } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/OutputBubbleButtons";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React, { useState } from "react";
|
||||
|
||||
export const OutputBubble: React.FC = (): JSX.Element => {
|
||||
const [windowHeight, setWindowHeight] = useState<string>();
|
||||
|
||||
const calculateQueryWindowHeight = (): string => {
|
||||
const calculatedHeight = document.getElementById("outputBubble")?.clientHeight * (3 / 5);
|
||||
return `${calculatedHeight}px`;
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
setWindowHeight(calculateQueryWindowHeight());
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
id="outputBubble"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
padding: "10px",
|
||||
margin: "10px",
|
||||
backgroundColor: "white",
|
||||
borderRadius: "8px",
|
||||
}}
|
||||
tokens={{ padding: 8, childrenGap: 8 }}
|
||||
>
|
||||
<Stack.Item style={{ alignSelf: "flex-start", paddingLeft: "2px" }}>
|
||||
{useQueryCopilot.getState()?.generatedQueryComments}
|
||||
</Stack.Item>
|
||||
<Stack.Item style={{ alignSelf: "stretch", flexGrow: 4 }}>
|
||||
<EditorReact
|
||||
language={"sql"}
|
||||
content={useQueryCopilot.getState()?.generatedQuery}
|
||||
isReadOnly={true}
|
||||
ariaLabel={"AI Response"}
|
||||
wordWrap="on"
|
||||
lineNumbers="on"
|
||||
lineNumbersMinChars={2}
|
||||
lineDecorationsWidth={0}
|
||||
minimap={{ enabled: false }}
|
||||
scrollBeyondLastLine={false}
|
||||
monacoContainerStyles={{ height: windowHeight, borderRadius: "4px" }}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item style={{ alignSelf: "flex-start" }}>
|
||||
<OutputBubbleButtons />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Text style={{ fontWeight: 400, fontSize: "10px", lineHeight: "14px" }}>
|
||||
AI-generated content may be incorrect
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Output Bubble snapshot tests should render and update height 1`] = `
|
||||
<Stack
|
||||
id="outputBubble"
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "white",
|
||||
"borderRadius": "8px",
|
||||
"display": "flex",
|
||||
"margin": "10px",
|
||||
"padding": "10px",
|
||||
}
|
||||
}
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 8,
|
||||
"padding": 8,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem
|
||||
style={
|
||||
Object {
|
||||
"alignSelf": "flex-start",
|
||||
"paddingLeft": "2px",
|
||||
}
|
||||
}
|
||||
>
|
||||
test comments
|
||||
</StackItem>
|
||||
<StackItem
|
||||
style={
|
||||
Object {
|
||||
"alignSelf": "stretch",
|
||||
"flexGrow": 4,
|
||||
}
|
||||
}
|
||||
>
|
||||
<EditorReact
|
||||
ariaLabel="AI Response"
|
||||
content="test query"
|
||||
isReadOnly={true}
|
||||
language="sql"
|
||||
lineDecorationsWidth={0}
|
||||
lineNumbers="on"
|
||||
lineNumbersMinChars={2}
|
||||
minimap={
|
||||
Object {
|
||||
"enabled": false,
|
||||
}
|
||||
}
|
||||
monacoContainerStyles={
|
||||
Object {
|
||||
"borderRadius": "4px",
|
||||
"height": "NaNpx",
|
||||
}
|
||||
}
|
||||
scrollBeyondLastLine={false}
|
||||
wordWrap="on"
|
||||
/>
|
||||
</StackItem>
|
||||
<StackItem
|
||||
style={
|
||||
Object {
|
||||
"alignSelf": "flex-start",
|
||||
}
|
||||
}
|
||||
>
|
||||
<OutputBubbleButtons />
|
||||
</StackItem>
|
||||
<StackItem>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"fontSize": "10px",
|
||||
"fontWeight": 400,
|
||||
"lineHeight": "14px",
|
||||
}
|
||||
}
|
||||
>
|
||||
AI-generated content may be incorrect
|
||||
</Text>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
`;
|
||||
@@ -19,7 +19,7 @@ exports[`Footer snapshot test should not pass if no text 1`] = `
|
||||
<Stack>
|
||||
<Image
|
||||
onClick={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={
|
||||
Object {
|
||||
"label": Object {
|
||||
@@ -104,7 +104,7 @@ exports[`Footer snapshot test should not pass text with non enter key 1`] = `
|
||||
<Stack>
|
||||
<Image
|
||||
onClick={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={
|
||||
Object {
|
||||
"label": Object {
|
||||
@@ -189,7 +189,7 @@ exports[`Footer snapshot test should open sample prompts on button click 1`] = `
|
||||
<Stack>
|
||||
<Image
|
||||
onClick={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={
|
||||
Object {
|
||||
"label": Object {
|
||||
@@ -274,7 +274,7 @@ exports[`Footer snapshot test should pass text with enter key 1`] = `
|
||||
<Stack>
|
||||
<Image
|
||||
onClick={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={
|
||||
Object {
|
||||
"label": Object {
|
||||
@@ -359,7 +359,7 @@ exports[`Footer snapshot test should pass text with icon button 1`] = `
|
||||
<Stack>
|
||||
<Image
|
||||
onClick={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={
|
||||
Object {
|
||||
"label": Object {
|
||||
@@ -444,7 +444,7 @@ exports[`Footer snapshot test should update user input 1`] = `
|
||||
<Stack>
|
||||
<Image
|
||||
onClick={[Function]}
|
||||
src=""
|
||||
src={Object {}}
|
||||
styles={
|
||||
Object {
|
||||
"label": Object {
|
||||
|
||||
@@ -18,7 +18,7 @@ exports[`Header snapshot test should close on button click 1`] = `
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<Text
|
||||
style={
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Stack } from "@fluentui/react";
|
||||
import { QueryCopilotProps } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
|
||||
import { OutputBubble } from "Explorer/QueryCopilot/V2/Bubbles/Output/OutputBubble";
|
||||
import { RetrievingBubble } from "Explorer/QueryCopilot/V2/Bubbles/Retriveing/RetrievingBubble";
|
||||
import { SampleBubble } from "Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble";
|
||||
import { WelcomeBubble } from "Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble";
|
||||
@@ -10,13 +11,7 @@ import React from "react";
|
||||
import { WelcomeSidebarModal } from "../Modal/WelcomeSidebarModal";
|
||||
|
||||
export const QueryCopilotSidebar: React.FC<QueryCopilotProps> = ({ explorer }: QueryCopilotProps): JSX.Element => {
|
||||
const {
|
||||
setWasCopilotUsed,
|
||||
showCopilotSidebar,
|
||||
chatMessages,
|
||||
showWelcomeSidebar,
|
||||
isGeneratingQuery,
|
||||
} = useQueryCopilot();
|
||||
const { setWasCopilotUsed, showCopilotSidebar, chatMessages, isGeneratingQuery } = useQueryCopilot();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (showCopilotSidebar) {
|
||||
@@ -27,58 +22,36 @@ export const QueryCopilotSidebar: React.FC<QueryCopilotProps> = ({ explorer }: Q
|
||||
return (
|
||||
<Stack style={{ width: "100%", height: "100%", backgroundColor: "#FAFAFA" }}>
|
||||
<Header />
|
||||
{showWelcomeSidebar ? (
|
||||
<WelcomeSidebarModal />
|
||||
) : (
|
||||
<>
|
||||
<WelcomeSidebarModal />
|
||||
<Stack
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
<WelcomeBubble />
|
||||
{chatMessages.map((message, index) => (
|
||||
<Stack
|
||||
key={index}
|
||||
horizontalAlign="center"
|
||||
tokens={{ padding: 8, childrenGap: 8 }}
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflowY: "auto",
|
||||
backgroundColor: "#E0E7FF",
|
||||
borderRadius: "8px",
|
||||
margin: "5px 10px",
|
||||
textAlign: "start",
|
||||
}}
|
||||
>
|
||||
<WelcomeBubble />
|
||||
{chatMessages.map((message, index) =>
|
||||
message.source === 0 ? (
|
||||
<Stack
|
||||
key={index}
|
||||
horizontalAlign="center"
|
||||
tokens={{ padding: 8, childrenGap: 8 }}
|
||||
style={{
|
||||
backgroundColor: "#E0E7FF",
|
||||
borderRadius: "8px",
|
||||
margin: "5px 10px",
|
||||
textAlign: "start",
|
||||
}}
|
||||
>
|
||||
{message.message}
|
||||
</Stack>
|
||||
) : (
|
||||
<Stack
|
||||
key={index}
|
||||
horizontalAlign="center"
|
||||
tokens={{ padding: 8, childrenGap: 8 }}
|
||||
style={{
|
||||
backgroundColor: "white",
|
||||
borderRadius: "8px",
|
||||
margin: "5px 10px",
|
||||
textAlign: "start",
|
||||
}}
|
||||
>
|
||||
{message.message}
|
||||
</Stack>
|
||||
)
|
||||
)}
|
||||
|
||||
<RetrievingBubble />
|
||||
|
||||
{chatMessages.length === 0 && !isGeneratingQuery && <SampleBubble />}
|
||||
{message}
|
||||
</Stack>
|
||||
<Footer explorer={explorer} />
|
||||
</>
|
||||
)}
|
||||
))}
|
||||
<OutputBubble />
|
||||
<RetrievingBubble />
|
||||
{chatMessages.length === 0 && !isGeneratingQuery && <SampleBubble />}
|
||||
</Stack>
|
||||
<Footer explorer={explorer} />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,6 +12,51 @@ exports[`Query Copilot Sidebar snapshot test should render and not set copilot u
|
||||
>
|
||||
<Header />
|
||||
<WelcomeSidebarModal />
|
||||
<Stack
|
||||
style={
|
||||
Object {
|
||||
"display": "flex",
|
||||
"flexDirection": "column",
|
||||
"flexGrow": 1,
|
||||
"overflowY": "auto",
|
||||
}
|
||||
}
|
||||
>
|
||||
<WelcomeBubble />
|
||||
<OutputBubble />
|
||||
<RetrievingBubble />
|
||||
<SampleBubble />
|
||||
</Stack>
|
||||
<Footer
|
||||
explorer={
|
||||
Explorer {
|
||||
"_isInitializingNotebooks": false,
|
||||
"_resetNotebookWorkspace": [Function],
|
||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||
"isTabsContentExpanded": [Function],
|
||||
"onRefreshDatabasesKeyPress": [Function],
|
||||
"onRefreshResourcesClick": [Function],
|
||||
"phoenixClient": PhoenixClient {
|
||||
"armResourceId": undefined,
|
||||
"retryOptions": Object {
|
||||
"maxTimeout": 5000,
|
||||
"minTimeout": 5000,
|
||||
"retries": 3,
|
||||
},
|
||||
},
|
||||
"provideFeedbackEmail": [Function],
|
||||
"queriesClient": QueriesClient {
|
||||
"container": [Circular],
|
||||
},
|
||||
"refreshNotebookList": [Function],
|
||||
"resourceTree": ResourceTreeAdapter {
|
||||
"container": [Circular],
|
||||
"copyNotebook": [Function],
|
||||
"parameters": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
@@ -27,6 +72,51 @@ exports[`Query Copilot Sidebar snapshot test should render and set copilot used
|
||||
>
|
||||
<Header />
|
||||
<WelcomeSidebarModal />
|
||||
<Stack
|
||||
style={
|
||||
Object {
|
||||
"display": "flex",
|
||||
"flexDirection": "column",
|
||||
"flexGrow": 1,
|
||||
"overflowY": "auto",
|
||||
}
|
||||
}
|
||||
>
|
||||
<WelcomeBubble />
|
||||
<OutputBubble />
|
||||
<RetrievingBubble />
|
||||
<SampleBubble />
|
||||
</Stack>
|
||||
<Footer
|
||||
explorer={
|
||||
Explorer {
|
||||
"_isInitializingNotebooks": false,
|
||||
"_resetNotebookWorkspace": [Function],
|
||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||
"isTabsContentExpanded": [Function],
|
||||
"onRefreshDatabasesKeyPress": [Function],
|
||||
"onRefreshResourcesClick": [Function],
|
||||
"phoenixClient": PhoenixClient {
|
||||
"armResourceId": undefined,
|
||||
"retryOptions": Object {
|
||||
"maxTimeout": 5000,
|
||||
"minTimeout": 5000,
|
||||
"retries": 3,
|
||||
},
|
||||
},
|
||||
"provideFeedbackEmail": [Function],
|
||||
"queriesClient": QueriesClient {
|
||||
"container": [Circular],
|
||||
},
|
||||
"refreshNotebookList": [Function],
|
||||
"resourceTree": ResourceTreeAdapter {
|
||||
"container": [Circular],
|
||||
"copyNotebook": [Function],
|
||||
"parameters": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
@@ -42,6 +132,51 @@ exports[`Query Copilot Sidebar snapshot test should render samples without messa
|
||||
>
|
||||
<Header />
|
||||
<WelcomeSidebarModal />
|
||||
<Stack
|
||||
style={
|
||||
Object {
|
||||
"display": "flex",
|
||||
"flexDirection": "column",
|
||||
"flexGrow": 1,
|
||||
"overflowY": "auto",
|
||||
}
|
||||
}
|
||||
>
|
||||
<WelcomeBubble />
|
||||
<OutputBubble />
|
||||
<RetrievingBubble />
|
||||
<SampleBubble />
|
||||
</Stack>
|
||||
<Footer
|
||||
explorer={
|
||||
Explorer {
|
||||
"_isInitializingNotebooks": false,
|
||||
"_resetNotebookWorkspace": [Function],
|
||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||
"isTabsContentExpanded": [Function],
|
||||
"onRefreshDatabasesKeyPress": [Function],
|
||||
"onRefreshResourcesClick": [Function],
|
||||
"phoenixClient": PhoenixClient {
|
||||
"armResourceId": undefined,
|
||||
"retryOptions": Object {
|
||||
"maxTimeout": 5000,
|
||||
"minTimeout": 5000,
|
||||
"retries": 3,
|
||||
},
|
||||
},
|
||||
"provideFeedbackEmail": [Function],
|
||||
"queriesClient": QueriesClient {
|
||||
"container": [Circular],
|
||||
},
|
||||
"refreshNotebookList": [Function],
|
||||
"resourceTree": ResourceTreeAdapter {
|
||||
"container": [Circular],
|
||||
"copyNotebook": [Function],
|
||||
"parameters": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
@@ -57,5 +192,69 @@ exports[`Query Copilot Sidebar snapshot test should render with chat messages 1`
|
||||
>
|
||||
<Header />
|
||||
<WelcomeSidebarModal />
|
||||
<Stack
|
||||
style={
|
||||
Object {
|
||||
"display": "flex",
|
||||
"flexDirection": "column",
|
||||
"flexGrow": 1,
|
||||
"overflowY": "auto",
|
||||
}
|
||||
}
|
||||
>
|
||||
<WelcomeBubble />
|
||||
<Stack
|
||||
horizontalAlign="center"
|
||||
key="0"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#E0E7FF",
|
||||
"borderRadius": "8px",
|
||||
"margin": "5px 10px",
|
||||
"textAlign": "start",
|
||||
}
|
||||
}
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 8,
|
||||
"padding": 8,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Component />
|
||||
</Stack>
|
||||
<OutputBubble />
|
||||
<RetrievingBubble />
|
||||
</Stack>
|
||||
<Footer
|
||||
explorer={
|
||||
Explorer {
|
||||
"_isInitializingNotebooks": false,
|
||||
"_resetNotebookWorkspace": [Function],
|
||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||
"isTabsContentExpanded": [Function],
|
||||
"onRefreshDatabasesKeyPress": [Function],
|
||||
"onRefreshResourcesClick": [Function],
|
||||
"phoenixClient": PhoenixClient {
|
||||
"armResourceId": undefined,
|
||||
"retryOptions": Object {
|
||||
"maxTimeout": 5000,
|
||||
"minTimeout": 5000,
|
||||
"retries": 3,
|
||||
},
|
||||
},
|
||||
"provideFeedbackEmail": [Function],
|
||||
"queriesClient": QueriesClient {
|
||||
"container": [Circular],
|
||||
},
|
||||
"refreshNotebookList": [Function],
|
||||
"resourceTree": ResourceTreeAdapter {
|
||||
"container": [Circular],
|
||||
"copyNotebook": [Function],
|
||||
"parameters": [Function],
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
@@ -74,7 +74,7 @@ exports[`Query Copilot Carousel snapshot test should render when isOpen is true
|
||||
To generate queries , just describe the query you want and copilot will generate the query for you.Watch this video to learn more about how to use copilot.
|
||||
</Text>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
style={
|
||||
Object {
|
||||
"margin": "16px auto",
|
||||
|
||||
@@ -23,7 +23,7 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
|
||||
verticalAlign="center"
|
||||
>
|
||||
<Image
|
||||
src=""
|
||||
src={Object {}}
|
||||
/>
|
||||
<Text
|
||||
style={
|
||||
|
||||
@@ -76,6 +76,7 @@ interface IQueryTabStates {
|
||||
isExecutionError: boolean;
|
||||
isExecuting: boolean;
|
||||
showCopilotSidebar: boolean;
|
||||
queryCopilotGeneratedQuery: string;
|
||||
}
|
||||
|
||||
export default class QueryTabComponent extends React.Component<IQueryTabComponentProps, IQueryTabStates> {
|
||||
@@ -101,6 +102,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
isExecutionError: this.props.isExecutionError,
|
||||
isExecuting: false,
|
||||
showCopilotSidebar: useQueryCopilot.getState().showCopilotSidebar,
|
||||
queryCopilotGeneratedQuery: useQueryCopilot.getState().query,
|
||||
};
|
||||
this.isCloseClicked = false;
|
||||
this.splitterId = this.props.tabId + "_splitter";
|
||||
@@ -334,6 +336,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
public onChangeContent(newContent: string): void {
|
||||
this.setState({
|
||||
sqlQueryEditorContent: newContent,
|
||||
queryCopilotGeneratedQuery: "",
|
||||
});
|
||||
if (this.isPreferredApiMongoDB) {
|
||||
if (newContent.length > 0) {
|
||||
@@ -365,6 +368,14 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
useCommandBar.getState().setContextButtons(this.getTabsButtons());
|
||||
}
|
||||
|
||||
public setEditorContent(): string {
|
||||
if (this.state.queryCopilotGeneratedQuery) {
|
||||
return this.state.queryCopilotGeneratedQuery;
|
||||
}
|
||||
|
||||
return this.state.sqlQueryEditorContent;
|
||||
}
|
||||
|
||||
private unsubscribeCopilotSidebar: () => void;
|
||||
|
||||
componentDidMount(): void {
|
||||
@@ -372,6 +383,9 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
if (this.state.showCopilotSidebar !== state.showCopilotSidebar) {
|
||||
this.setState({ showCopilotSidebar: state.showCopilotSidebar });
|
||||
}
|
||||
if (this.state.queryCopilotGeneratedQuery !== state.query) {
|
||||
this.setState({ queryCopilotGeneratedQuery: state.query });
|
||||
}
|
||||
});
|
||||
|
||||
useCommandBar.getState().setContextButtons(this.getTabsButtons());
|
||||
@@ -393,7 +407,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
<div className="queryEditor" style={{ height: "100%" }}>
|
||||
<EditorReact
|
||||
language={"sql"}
|
||||
content={this.state.sqlQueryEditorContent}
|
||||
content={this.setEditorContent()}
|
||||
isReadOnly={false}
|
||||
ariaLabel={"Editing Query"}
|
||||
lineNumbers={"on"}
|
||||
|
||||
Reference in New Issue
Block a user