[Query Copilot v2] Implementing output bubble (#1587)

* Implementing output bubble

* Fix lint

* Run prettier
This commit is contained in:
v-darkora 2023-08-29 08:56:53 +02:00 committed by GitHub
parent f7370fd341
commit 6a8e87f45f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1798 additions and 123 deletions

3
images/CopilotCopy.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="19" height="17" viewBox="0 0 19 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 0C5.89543 0 5 0.895431 5 2V12C5 13.1046 5.89543 14 7 14H13C14.1046 14 15 13.1046 15 12V2C15 0.89543 14.1046 0 13 0H7ZM6 2C6 1.44772 6.44772 1 7 1H13C13.5523 1 14 1.44772 14 2V12C14 12.5523 13.5523 13 13 13H7C6.44772 13 6 12.5523 6 12V2ZM3 4.00001C3 3.25973 3.4022 2.61339 4 2.26758V12.5C4 13.8807 5.11929 15 6.5 15H12.7324C12.3866 15.5978 11.7403 16 11 16H6.5C4.567 16 3 14.433 3 12.5V4.00001Z" fill="#242424"/>
</svg>

After

Width:  |  Height:  |  Size: 527 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.25028 7.30723C9.08872 7.49072 9.00001 7.74463 9.00001 8C9.00001 8.27614 8.77615 8.5 8.50001 8.5C8.22387 8.5 8.00001 8.27614 8.00001 8C8.00001 7.52689 8.1613 7.0308 8.49974 6.64641C8.84684 6.25219 9.3597 6 10 6C10.6403 6 11.1532 6.25219 11.5003 6.64641C11.8387 7.0308 12 7.52689 12 8C12 8.48947 11.8839 8.86964 11.6976 9.18921C11.5347 9.46855 11.3225 9.68963 11.1528 9.86652L11.1115 9.90956C10.9247 10.1051 10.7821 10.2639 10.6773 10.4641C10.5773 10.6551 10.5 10.9085 10.5 11.2929C10.5 11.5691 10.2762 11.7929 10 11.7929C9.72387 11.7929 9.50001 11.5691 9.50001 11.2929C9.50001 10.7611 9.61018 10.3464 9.79143 10.0002C9.96788 9.66319 10.2003 9.41576 10.3885 9.21878L10.4106 9.19559C10.5985 8.99908 10.7328 8.85858 10.8337 8.68547C10.9286 8.52273 11 8.31707 11 8C11 7.74463 10.9113 7.49072 10.7497 7.30723C10.5968 7.13358 10.3597 7 10 7C9.64033 7 9.40318 7.13358 9.25028 7.30723ZM9.99991 14.2122C10.3863 14.2122 10.6995 13.899 10.6995 13.5126C10.6995 13.1262 10.3863 12.813 9.99991 12.813C9.61353 12.813 9.3003 13.1262 9.3003 13.5126C9.3003 13.899 9.61353 14.2122 9.99991 14.2122ZM2.00001 10C2.00001 5.58172 5.58173 2 10 2C14.4183 2 18 5.58172 18 10C18 14.4183 14.4183 18 10 18C8.65078 18 7.37829 17.6656 6.26225 17.0748L2.62128 17.9851C2.45089 18.0277 2.27065 17.9777 2.14646 17.8536C2.02227 17.7294 1.97234 17.5491 2.01494 17.3787L2.92518 13.7378C2.33442 12.6217 2.00001 11.3492 2.00001 10ZM10 3C6.13402 3 3.00001 6.13401 3.00001 10C3.00001 11.245 3.32462 12.4128 3.89345 13.4247C3.95602 13.536 3.97363 13.6671 3.94266 13.791L3.18719 16.8128L6.20904 16.0574C6.33294 16.0264 6.46399 16.044 6.57531 16.1066C7.58726 16.6754 8.75497 17 10 17C13.866 17 17 13.866 17 10C17 6.13401 13.866 3 10 3Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

3
images/CopilotInsert.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 4C4.89543 4 4 4.89543 4 6V7C4 8.10457 4.89543 9 6 9H14C15.1046 9 16 8.10457 16 7V6C16 4.89543 15.1046 4 14 4H6ZM5 6C5 5.44772 5.44772 5 6 5H14C14.5523 5 15 5.44772 15 6V7C15 7.55228 14.5523 8 14 8H6C5.44772 8 5 7.55228 5 7V6ZM6 11C4.89543 11 4 11.8954 4 13V14C4 15.1046 4.89543 16 6 16H14C15.1046 16 16 15.1046 16 14V13C16 11.8954 15.1046 11 14 11H6ZM5 13C5 12.4477 5.44772 12 6 12H14C14.5523 12 15 12.4477 15 13V14C15 14.5523 14.5523 15 14 15H6C5.44772 15 5 14.5523 5 14V13Z" fill="#242424"/>
</svg>

After

Width:  |  Height:  |  Size: 609 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.4829 0.703737C9.68406 -0.133389 8.39129 0.316883 8.05198 1.29418C7.77205 2.10043 7.4084 3.06594 7.05406 3.77684C5.99442 5.90276 5.37583 7.11234 3.66974 8.62586C3.44337 8.82668 3.15163 8.9885 2.82905 9.11601C1.69991 9.56233 0.638089 10.7321 0.915812 12.1207L1.26885 13.8859C1.45455 14.8144 2.14894 15.5583 3.06251 15.8075L8.66224 17.3347C11.2078 18.0289 13.8017 16.3942 14.2737 13.7983L14.9576 10.0365C15.2924 8.19503 13.8777 6.49989 12.006 6.49989H11.1225L11.1328 6.44766C11.2129 6.03948 11.3093 5.47735 11.3738 4.86473C11.438 4.25446 11.4721 3.58034 11.4218 2.9522C11.3725 2.33584 11.2379 1.70305 10.9176 1.22254C10.8081 1.05832 10.6455 0.874161 10.4829 0.703737Z" fill="#605E5C"/>
</svg>

After

Width:  |  Height:  |  Size: 799 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.4829 0.703737C9.68406 -0.133389 8.39129 0.316883 8.05198 1.29418C7.77205 2.10043 7.4084 3.06594 7.05406 3.77684C5.99442 5.90276 5.37583 7.11234 3.66974 8.62586C3.44337 8.82668 3.15163 8.9885 2.82905 9.11601C1.69991 9.56233 0.638089 10.7321 0.915812 12.1207L1.26885 13.8859C1.45455 14.8144 2.14894 15.5583 3.06251 15.8075L8.66224 17.3347C11.2078 18.0289 13.8017 16.3942 14.2737 13.7983L14.9576 10.0365C15.2924 8.19503 13.8777 6.49989 12.006 6.49989H11.1225L11.1328 6.44766C11.2129 6.03948 11.3093 5.47735 11.3738 4.86473C11.438 4.25446 11.4721 3.58034 11.4218 2.9522C11.3725 2.33584 11.2379 1.70305 10.9176 1.22254C10.8081 1.05832 10.6455 0.874161 10.4829 0.703737Z" fill="#0078D4"/>
</svg>

After

Width:  |  Height:  |  Size: 799 B

View File

@ -0,0 +1,3 @@
<svg width="15" height="18" viewBox="0 0 15 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.55198 1.29418C7.89129 0.316883 9.18406 -0.133389 9.98289 0.703737C10.1455 0.874162 10.3081 1.05832 10.4176 1.22254C10.7379 1.70305 10.8725 2.33584 10.9218 2.9522C10.9721 3.58034 10.938 4.25446 10.8738 4.86473C10.8093 5.47735 10.7129 6.03948 10.6328 6.44766C10.6294 6.46535 10.6259 6.48277 10.6225 6.49989H11.506C13.3777 6.49989 14.7924 8.19503 14.4576 10.0365L13.7737 13.7983C13.3017 16.3942 10.7078 18.0289 8.16224 17.3347L2.56251 15.8075C1.64894 15.5583 0.954555 14.8144 0.768846 13.8859L0.415812 12.1207C0.138089 10.7321 1.19991 9.56233 2.32905 9.11601C2.65163 8.9885 2.94337 8.82668 3.16974 8.62586C4.87583 7.11234 5.49442 5.90276 6.55406 3.77684C6.9084 3.06594 7.27205 2.10043 7.55198 1.29418ZM9.51651 6.87851L9.51689 6.87696L9.51869 6.86962L9.5262 6.83852C9.53284 6.81068 9.54264 6.76892 9.55487 6.71482C9.57935 6.60658 9.61349 6.44919 9.65152 6.25525C9.72773 5.86655 9.81878 5.33493 9.8793 4.76005C9.94006 4.18282 9.96852 3.57569 9.92502 3.03195C9.88058 2.47644 9.76518 2.04673 9.58552 1.77724C9.52643 1.68859 9.41385 1.55593 9.25942 1.3941C9.06051 1.18565 8.63137 1.23417 8.49666 1.62217C8.21411 2.43598 7.83339 3.45183 7.44904 4.22294C6.38216 6.36338 5.69326 7.72396 3.83336 9.37392C3.49304 9.67583 3.08878 9.89099 2.69665 10.046C1.81631 10.394 1.25035 11.1944 1.39639 11.9246L1.74943 13.6898C1.86085 14.2469 2.27748 14.6932 2.82562 14.8427L8.42536 16.3699C10.4052 16.9099 12.4227 15.6384 12.7898 13.6194L13.4738 9.85766C13.697 8.62998 12.7538 7.49989 11.506 7.49989H10.0015C9.84758 7.49989 9.7022 7.42895 9.60745 7.3076C9.51272 7.18627 9.47921 7.02785 9.51651 6.87851C9.51651 6.87847 9.5165 6.87855 9.51651 6.87851Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 2.5C5 2.22386 4.77614 2 4.5 2C4.22386 2 4 2.22386 4 2.5V4H2.5C2.22386 4 2 4.22386 2 4.5C2 4.77614 2.22386 5 2.5 5H4.5C4.77614 5 5 4.77614 5 4.5V2.5ZM16 2.5C16 2.22386 15.7761 2 15.5 2C15.2239 2 15 2.22386 15 2.5V4.5C15 4.77614 15.2239 5 15.5 5H17.5C17.7761 5 18 4.77614 18 4.5C18 4.22386 17.7761 4 17.5 4H16V2.5ZM7 5C6.44771 5 6 5.44772 6 6V14C6 14.5523 6.44772 15 7 15H13C13.5523 15 14 14.5523 14 14V6C14 5.44772 13.5523 5 13 5H7ZM7 6H13V14H7V6ZM4.5 18C4.77614 18 5 17.7761 5 17.5V15.5C5 15.2239 4.77614 15 4.5 15H2.5C2.22386 15 2 15.2239 2 15.5C2 15.7761 2.22386 16 2.5 16H4V17.5C4 17.7761 4.22386 18 4.5 18ZM15.5 18C15.7761 18 16 17.7761 16 17.5V16H17.5C17.7761 16 18 15.7761 18 15.5C18 15.2239 17.7761 15 17.5 15H15.5C15.2239 15 15 15.2239 15 15.5V17.5C15 17.7761 15.2239 18 15.5 18ZM8.5 8C8.22386 8 8 8.22386 8 8.5C8 8.77614 8.22386 9 8.5 9H11.5C11.7761 9 12 8.77614 12 8.5C12 8.22386 11.7761 8 11.5 8H8.5ZM8.5 10C8.22386 10 8 10.2239 8 10.5C8 10.7761 8.22386 11 8.5 11H10.5C10.7761 11 11 10.7761 11 10.5C11 10.2239 10.7761 10 10.5 10H8.5Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.14645 2.64645C9.34171 2.45118 9.65829 2.45118 9.85355 2.64645L11.3536 4.14645C11.5488 4.34171 11.5488 4.65829 11.3536 4.85355L9.85355 6.35355C9.65829 6.54882 9.34171 6.54882 9.14645 6.35355C8.95118 6.15829 8.95118 5.84171 9.14645 5.64645L9.7885 5.00439C7.12517 5.11522 5 7.30943 5 10C5 11.568 5.72118 12.9672 6.85185 13.8847C7.06627 14.0587 7.09904 14.3736 6.92503 14.588C6.75103 14.8024 6.43615 14.8352 6.22172 14.6612C4.86712 13.5619 4 11.882 4 10C4 6.75447 6.57689 4.1108 9.79629 4.00339L9.14645 3.35355C8.95118 3.15829 8.95118 2.84171 9.14645 2.64645ZM13.075 5.41199C13.249 5.19756 13.5639 5.1648 13.7783 5.3388C15.1329 6.43806 16 8.11795 16 10C16 13.2455 13.4231 15.8892 10.2037 15.9966L10.8536 16.6464C11.0488 16.8417 11.0488 17.1583 10.8536 17.3536C10.6583 17.5488 10.3417 17.5488 10.1464 17.3536L8.64645 15.8536C8.55268 15.7598 8.5 15.6326 8.5 15.5C8.5 15.3674 8.55268 15.2402 8.64645 15.1464L10.1464 13.6464C10.3417 13.4512 10.6583 13.4512 10.8536 13.6464C11.0488 13.8417 11.0488 14.1583 10.8536 14.3536L10.2115 14.9956C12.8748 14.8848 15 12.6906 15 10C15 8.43201 14.2788 7.03283 13.1482 6.1153C12.9337 5.94129 12.901 5.62641 13.075 5.41199Z" fill="#242424"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.5 4C4.67157 4 4 4.67157 4 5.5V6.5C4 6.77614 3.77614 7 3.5 7C3.22386 7 3 6.77614 3 6.5V5.5C3 4.11929 4.11929 3 5.5 3H6.5C6.77614 3 7 3.22386 7 3.5C7 3.77614 6.77614 4 6.5 4H5.5ZM16 5.5C16 4.67157 15.3284 4 14.5 4H13.5C13.2239 4 13 3.77614 13 3.5C13 3.22386 13.2239 3 13.5 3H14.5C15.8807 3 17 4.11929 17 5.5V6.5C17 6.77614 16.7761 7 16.5 7C16.2239 7 16 6.77614 16 6.5V5.5ZM16 14.5C16 15.3284 15.3284 16 14.5 16H13.5C13.2239 16 13 16.2239 13 16.5C13 16.7761 13.2239 17 13.5 17H14.5C15.8807 17 17 15.8807 17 14.5V13.5C17 13.2239 16.7761 13 16.5 13C16.2239 13 16 13.2239 16 13.5V14.5ZM4 14.5C4 15.3284 4.67157 16 5.5 16H6.75C7.02614 16 7.25 16.2239 7.25 16.5C7.25 16.7761 7.02614 17 6.75 17H5.5C4.11929 17 3 15.8807 3 14.5V13.25C3 12.9739 3.22386 12.75 3.5 12.75C3.77614 12.75 4 12.9739 4 13.25V14.5ZM8.5 7C7.67157 7 7 7.67157 7 8.5V11.5C7 12.3284 7.67157 13 8.5 13H11.5C12.3284 13 13 12.3284 13 11.5V8.5C13 7.67157 12.3284 7 11.5 7H8.5ZM8 8.5C8 8.22386 8.22386 8 8.5 8H11.5C11.7761 8 12 8.22386 12 8.5V11.5C12 11.7761 11.7761 12 11.5 12H8.5C8.22386 12 8 11.7761 8 11.5V8.5Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -68,7 +68,8 @@ module.exports = {
// A map from regular expressions to module names that allow to stub out resources with a single module // A map from regular expressions to module names that allow to stub out resources with a single module
moduleNameMapper: { moduleNameMapper: {
"^.*[.](svg|png|gif|less|css)$": "<rootDir>/mockModule", "^.*[.](png|gif|less|css)$": "<rootDir>/mockModule",
"(.*)$[.](svg)": "<rootDir>/mockModule/$1",
"@nteract/stateful-components/(.*)$": "<rootDir>/mockModule", "@nteract/stateful-components/(.*)$": "<rootDir>/mockModule",
"@fluentui/react/lib/(.*)$": "@fluentui/react/lib-commonjs/$1", // https://github.com/microsoft/fluentui/wiki/Version-8-release-notes "@fluentui/react/lib/(.*)$": "@fluentui/react/lib-commonjs/$1", // https://github.com/microsoft/fluentui/wiki/Version-8-release-notes
"monaco-editor/(.*)$": "<rootDir>/__mocks__/monaco-editor", "monaco-editor/(.*)$": "<rootDir>/__mocks__/monaco-editor",
@ -165,6 +166,7 @@ module.exports = {
transform: { transform: {
"^.+\\.html?$": "html-loader-jest", "^.+\\.html?$": "html-loader-jest",
"^.+\\.[t|j]sx?$": "babel-jest", "^.+\\.[t|j]sx?$": "babel-jest",
"^.+\\.svg$": "<rootDir>/svgTransform.js",
}, },
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation

View File

@ -13,8 +13,14 @@ export interface EditorReactProps {
ariaLabel: string; // Sets what will be read to the user to define the control ariaLabel: string; // Sets what will be read to the user to define the control
onContentSelected?: (selectedContent: string) => void; // Called when text is selected onContentSelected?: (selectedContent: string) => void; // Called when text is selected
onContentChanged?: (newContent: string) => void; // Called when text is changed onContentChanged?: (newContent: string) => void; // Called when text is changed
lineNumbers?: monaco.editor.IEditorOptions["lineNumbers"];
theme?: string; // Monaco editor theme 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> { export class EditorReact extends React.Component<EditorReactProps, EditorReactStates> {
@ -54,7 +60,11 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
return ( return (
<React.Fragment> <React.Fragment>
{!this.state.showEditor && <Spinner size={SpinnerSize.large} className="spinner" />} {!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> </React.Fragment>
); );
} }
@ -84,14 +94,19 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
*/ */
private async createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) { private async createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
const options: monaco.editor.IEditorConstructionOptions = { const options: monaco.editor.IEditorConstructionOptions = {
value: this.props.content,
language: this.props.language, language: this.props.language,
value: this.props.content,
readOnly: this.props.isReadOnly, readOnly: this.props.isReadOnly,
lineNumbers: this.props.lineNumbers || "off",
fontSize: 12,
ariaLabel: this.props.ariaLabel, ariaLabel: this.props.ariaLabel,
theme: this.props.theme, fontSize: 12,
automaticLayout: true, 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 = ""; this.rootNode.innerHTML = "";

View File

@ -55,7 +55,7 @@ exports[`TreeNodeComponent does not render children by default 1`] = `
className="expandCollapseIcon" className="expandCollapseIcon"
onKeyPress={[Function]} onKeyPress={[Function]}
role="button" role="button"
src="" src={Object {}}
tabIndex={0} tabIndex={0}
/> />
<span <span
@ -158,7 +158,7 @@ exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`]
className="expandCollapseIcon" className="expandCollapseIcon"
onKeyPress={[Function]} onKeyPress={[Function]}
role="button" role="button"
src="" src={Object {}}
tabIndex={0} tabIndex={0}
/> />
<span <span
@ -309,7 +309,7 @@ exports[`TreeNodeComponent renders loading icon 1`] = `
className="expandCollapseIcon" className="expandCollapseIcon"
onKeyPress={[Function]} onKeyPress={[Function]}
role="button" role="button"
src="" src={Object {}}
tabIndex={0} tabIndex={0}
/> />
<span <span
@ -383,7 +383,7 @@ exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents
className="expandCollapseIcon" className="expandCollapseIcon"
onKeyPress={[Function]} onKeyPress={[Function]}
role="button" role="button"
src="" src={Object {}}
tabIndex={0} tabIndex={0}
/> />
<span <span
@ -553,7 +553,7 @@ exports[`TreeNodeComponent renders unsorted children by default 1`] = `
className="expandCollapseIcon" className="expandCollapseIcon"
onKeyPress={[Function]} onKeyPress={[Function]}
role="button" role="button"
src="" src={Object {}}
tabIndex={0} tabIndex={0}
/> />
<span <span

View File

@ -128,7 +128,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
> >
<img <img
alt="Delete" alt="Delete"
src="" src={Object {}}
/> />
</AccessibleElement> </AccessibleElement>
</td> </td>
@ -185,7 +185,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
> >
<img <img
alt="Delete" alt="Delete"
src="" src={Object {}}
/> />
</AccessibleElement> </AccessibleElement>
</td> </td>
@ -203,7 +203,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
> >
<img <img
alt="Add" alt="Add"
src="" src={Object {}}
/> />
Add Property Add Property
</AccessibleElement> </AccessibleElement>
@ -317,7 +317,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
> >
<img <img
alt="Delete" alt="Delete"
src="" src={Object {}}
/> />
</AccessibleElement> </AccessibleElement>
</td> </td>
@ -379,7 +379,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
> >
<img <img
alt="Delete" alt="Delete"
src="" src={Object {}}
/> />
</AccessibleElement> </AccessibleElement>
</td> </td>
@ -397,7 +397,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
> >
<img <img
alt="Add" alt="Add"
src="" src={Object {}}
/> />
Add Property Add Property
</AccessibleElement> </AccessibleElement>

View File

@ -22,7 +22,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
> >
<img <img
alt="in progress items" alt="in progress items"
src="" src={Object {}}
/> />
<span <span
className="numInProgress" className="numInProgress"
@ -35,7 +35,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
> >
<img <img
alt="error items" alt="error items"
src="" src={Object {}}
/> />
<span <span
className="numErroredItems" className="numErroredItems"
@ -48,7 +48,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
> >
<img <img
alt="info items" alt="info items"
src="" src={Object {}}
/> />
<span <span
className="numInfoItems" className="numInfoItems"
@ -150,7 +150,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
> >
<img <img
alt="clear notifications image" alt="clear notifications image"
src="" src={Object {}}
/> />
Clear Notifications Clear Notifications
</span> </span>
@ -185,7 +185,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
> >
<img <img
alt="in progress items" alt="in progress items"
src="" src={Object {}}
/> />
<span <span
className="numInProgress" className="numInProgress"
@ -198,7 +198,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
> >
<img <img
alt="error items" alt="error items"
src="" src={Object {}}
/> />
<span <span
className="numErroredItems" className="numErroredItems"
@ -211,7 +211,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
> >
<img <img
alt="info items" alt="info items"
src="" src={Object {}}
/> />
<span <span
className="numInfoItems" className="numInfoItems"
@ -315,7 +315,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
> >
<img <img
alt="clear notifications image" alt="clear notifications image"
src="" src={Object {}}
/> />
Clear Notifications Clear Notifications
</span> </span>
@ -330,7 +330,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
<img <img
alt="info" alt="info"
className="infoIcon" className="infoIcon"
src="" src={Object {}}
/> />
<span <span
className="date" className="date"

View File

@ -4340,7 +4340,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
id="deleteparam" id="deleteparam"
onClick={[Function]} onClick={[Function]}
role="button" role="button"
src="" src={Object {}}
width={20} width={20}
> >
<ImageBase <ImageBase
@ -4350,7 +4350,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
id="deleteparam" id="deleteparam"
onClick={[Function]} onClick={[Function]}
role="button" role="button"
src="" src={Object {}}
styles={[Function]} styles={[Function]}
theme={ theme={
Object { Object {
@ -4640,12 +4640,12 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
alt="Delete param" alt="Delete param"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87" className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
id="deleteparam" id="deleteparam"
key="fabricImage" key="fabricImage[object Object]"
onClick={[Function]} onClick={[Function]}
onError={[Function]} onError={[Function]}
onLoad={[Function]} onLoad={[Function]}
role="button" role="button"
src="" src={Object {}}
/> />
</div> </div>
</ImageBase> </ImageBase>
@ -4661,7 +4661,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
id="addparam" id="addparam"
onClick={[Function]} onClick={[Function]}
role="button" role="button"
src="" src={Object {}}
width={20} width={20}
> >
<ImageBase <ImageBase
@ -4671,7 +4671,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
id="addparam" id="addparam"
onClick={[Function]} onClick={[Function]}
role="button" role="button"
src="" src={Object {}}
styles={[Function]} styles={[Function]}
theme={ theme={
Object { Object {
@ -4961,12 +4961,12 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
alt="Add param" alt="Add param"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87" className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
id="addparam" id="addparam"
key="fabricImage" key="fabricImage[object Object]"
onClick={[Function]} onClick={[Function]}
onError={[Function]} onError={[Function]}
onLoad={[Function]} onLoad={[Function]}
role="button" role="button"
src="" src={Object {}}
/> />
</div> </div>
</ImageBase> </ImageBase>
@ -4989,13 +4989,13 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
alt="Add param" alt="Add param"
height={30} height={30}
key=".0:$.0" key=".0:$.0"
src="" src={Object {}}
width={20} width={20}
> >
<ImageBase <ImageBase
alt="Add param" alt="Add param"
height={30} height={30}
src="" src={Object {}}
styles={[Function]} styles={[Function]}
theme={ theme={
Object { Object {
@ -5284,10 +5284,10 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
<img <img
alt="Add param" alt="Add param"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87" className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
key="fabricImage" key="fabricImage[object Object]"
onError={[Function]} onError={[Function]}
onLoad={[Function]} onLoad={[Function]}
src="" src={Object {}}
/> />
</div> </div>
</ImageBase> </ImageBase>

View File

@ -39,7 +39,7 @@ exports[`Load Query Pane should render Default properly 1`] = `
className="fileIcon" className="fileIcon"
height={20} height={20}
imageFit={4} imageFit={4}
src="" src={Object {}}
width={20} width={20}
/> />
<input <input

View File

@ -44,13 +44,13 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
alt="Add Property" alt="Add Property"
height={30} height={30}
key=".0:$.0" key=".0:$.0"
src="" src={Object {}}
width={16} width={16}
> >
<ImageBase <ImageBase
alt="Add Property" alt="Add Property"
height={30} height={30}
src="" src={Object {}}
styles={[Function]} styles={[Function]}
theme={ theme={
Object { Object {
@ -339,10 +339,10 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
<img <img
alt="Add Property" alt="Add Property"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-55" className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-55"
key="fabricImage" key="fabricImage[object Object]"
onError={[Function]} onError={[Function]}
onLoad={[Function]} onLoad={[Function]}
src="" src={Object {}}
/> />
</div> </div>
</ImageBase> </ImageBase>

View File

@ -39,13 +39,13 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
alt="Add Entity" alt="Add Entity"
height={30} height={30}
key=".0:$.0" key=".0:$.0"
src="" src={Object {}}
width={16} width={16}
> >
<ImageBase <ImageBase
alt="Add Entity" alt="Add Entity"
height={30} height={30}
src="" src={Object {}}
styles={[Function]} styles={[Function]}
theme={ theme={
Object { Object {
@ -334,10 +334,10 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
<img <img
alt="Add Entity" alt="Add Entity"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-55" className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-55"
key="fabricImage" key="fabricImage[object Object]"
onError={[Function]} onError={[Function]}
onLoad={[Function]} onLoad={[Function]}
src="" src={Object {}}
/> />
</div> </div>
</ImageBase> </ImageBase>

View File

@ -20,7 +20,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
> >
<StackItem> <StackItem>
<Image <Image
src="" src={Object {}}
/> />
</StackItem> </StackItem>
</Stack> </Stack>
@ -84,7 +84,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
className="imageTextPadding" className="imageTextPadding"
> >
<Image <Image
src="" src={Object {}}
/> />
</StackItem> </StackItem>
<StackItem <StackItem
@ -120,7 +120,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
className="imageTextPadding" className="imageTextPadding"
> >
<Image <Image
src="" src={Object {}}
/> />
</StackItem> </StackItem>
<StackItem <StackItem
@ -156,7 +156,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
className="imageTextPadding" className="imageTextPadding"
> >
<Image <Image
src="" src={Object {}}
/> />
</StackItem> </StackItem>
<StackItem <StackItem

View File

@ -40,7 +40,7 @@ exports[`Copy Popup snapshot test should render when showCopyPopup is true 1`] =
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
style={ style={
Object { Object {
"height": 15, "height": 15,

View File

@ -87,7 +87,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
style={ style={
Object { Object {
"height": 25, "height": 25,
@ -191,7 +191,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
style={ style={
Object { Object {
"height": 25, "height": 25,
@ -295,7 +295,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
style={ style={
Object { Object {
"height": 25, "height": 25,
@ -477,7 +477,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
style={ style={
Object { Object {
"height": 25, "height": 25,
@ -581,7 +581,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
style={ style={
Object { Object {
"height": 25, "height": 25,
@ -685,7 +685,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
style={ style={
Object { Object {
"height": 25, "height": 25,

View File

@ -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();
});
});

View File

@ -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>
);
};

View File

@ -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]}
/>
`;

View File

@ -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();
});
});

View File

@ -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>
);
};

View File

@ -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>
`;

View File

@ -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();
});
});

View File

@ -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>
);
};

View File

@ -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>
`;

View File

@ -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();
});
});

View File

@ -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>
);
};

View File

@ -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",
},
],
}
}
/>
`;

View File

@ -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();
});
});

View File

@ -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>
);
};

View File

@ -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>
`;

View File

@ -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();
});
});
});

View 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>
);
};

View File

@ -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>
`;

View File

@ -19,7 +19,7 @@ exports[`Footer snapshot test should not pass if no text 1`] = `
<Stack> <Stack>
<Image <Image
onClick={[Function]} onClick={[Function]}
src="" src={Object {}}
styles={ styles={
Object { Object {
"label": Object { "label": Object {
@ -104,7 +104,7 @@ exports[`Footer snapshot test should not pass text with non enter key 1`] = `
<Stack> <Stack>
<Image <Image
onClick={[Function]} onClick={[Function]}
src="" src={Object {}}
styles={ styles={
Object { Object {
"label": Object { "label": Object {
@ -189,7 +189,7 @@ exports[`Footer snapshot test should open sample prompts on button click 1`] = `
<Stack> <Stack>
<Image <Image
onClick={[Function]} onClick={[Function]}
src="" src={Object {}}
styles={ styles={
Object { Object {
"label": Object { "label": Object {
@ -274,7 +274,7 @@ exports[`Footer snapshot test should pass text with enter key 1`] = `
<Stack> <Stack>
<Image <Image
onClick={[Function]} onClick={[Function]}
src="" src={Object {}}
styles={ styles={
Object { Object {
"label": Object { "label": Object {
@ -359,7 +359,7 @@ exports[`Footer snapshot test should pass text with icon button 1`] = `
<Stack> <Stack>
<Image <Image
onClick={[Function]} onClick={[Function]}
src="" src={Object {}}
styles={ styles={
Object { Object {
"label": Object { "label": Object {
@ -444,7 +444,7 @@ exports[`Footer snapshot test should update user input 1`] = `
<Stack> <Stack>
<Image <Image
onClick={[Function]} onClick={[Function]}
src="" src={Object {}}
styles={ styles={
Object { Object {
"label": Object { "label": Object {

View File

@ -18,7 +18,7 @@ exports[`Header snapshot test should close on button click 1`] = `
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
/> />
<Text <Text
style={ style={

View File

@ -1,5 +1,6 @@
import { Stack } from "@fluentui/react"; import { Stack } from "@fluentui/react";
import { QueryCopilotProps } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces"; 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 { RetrievingBubble } from "Explorer/QueryCopilot/V2/Bubbles/Retriveing/RetrievingBubble";
import { SampleBubble } from "Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble"; import { SampleBubble } from "Explorer/QueryCopilot/V2/Bubbles/Sample/SampleBubble";
import { WelcomeBubble } from "Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble"; import { WelcomeBubble } from "Explorer/QueryCopilot/V2/Bubbles/Welcome/WelcomeBubble";
@ -10,13 +11,7 @@ import React from "react";
import { WelcomeSidebarModal } from "../Modal/WelcomeSidebarModal"; import { WelcomeSidebarModal } from "../Modal/WelcomeSidebarModal";
export const QueryCopilotSidebar: React.FC<QueryCopilotProps> = ({ explorer }: QueryCopilotProps): JSX.Element => { export const QueryCopilotSidebar: React.FC<QueryCopilotProps> = ({ explorer }: QueryCopilotProps): JSX.Element => {
const { const { setWasCopilotUsed, showCopilotSidebar, chatMessages, isGeneratingQuery } = useQueryCopilot();
setWasCopilotUsed,
showCopilotSidebar,
chatMessages,
showWelcomeSidebar,
isGeneratingQuery,
} = useQueryCopilot();
React.useEffect(() => { React.useEffect(() => {
if (showCopilotSidebar) { if (showCopilotSidebar) {
@ -27,10 +22,7 @@ export const QueryCopilotSidebar: React.FC<QueryCopilotProps> = ({ explorer }: Q
return ( return (
<Stack style={{ width: "100%", height: "100%", backgroundColor: "#FAFAFA" }}> <Stack style={{ width: "100%", height: "100%", backgroundColor: "#FAFAFA" }}>
<Header /> <Header />
{showWelcomeSidebar ? (
<WelcomeSidebarModal /> <WelcomeSidebarModal />
) : (
<>
<Stack <Stack
style={{ style={{
flexGrow: 1, flexGrow: 1,
@ -40,8 +32,7 @@ export const QueryCopilotSidebar: React.FC<QueryCopilotProps> = ({ explorer }: Q
}} }}
> >
<WelcomeBubble /> <WelcomeBubble />
{chatMessages.map((message, index) => {chatMessages.map((message, index) => (
message.source === 0 ? (
<Stack <Stack
key={index} key={index}
horizontalAlign="center" horizontalAlign="center"
@ -53,32 +44,14 @@ export const QueryCopilotSidebar: React.FC<QueryCopilotProps> = ({ explorer }: Q
textAlign: "start", textAlign: "start",
}} }}
> >
{message.message} {message}
</Stack> </Stack>
) : ( ))}
<Stack <OutputBubble />
key={index}
horizontalAlign="center"
tokens={{ padding: 8, childrenGap: 8 }}
style={{
backgroundColor: "white",
borderRadius: "8px",
margin: "5px 10px",
textAlign: "start",
}}
>
{message.message}
</Stack>
)
)}
<RetrievingBubble /> <RetrievingBubble />
{chatMessages.length === 0 && !isGeneratingQuery && <SampleBubble />} {chatMessages.length === 0 && !isGeneratingQuery && <SampleBubble />}
</Stack> </Stack>
<Footer explorer={explorer} /> <Footer explorer={explorer} />
</>
)}
</Stack> </Stack>
); );
}; };

View File

@ -12,6 +12,51 @@ exports[`Query Copilot Sidebar snapshot test should render and not set copilot u
> >
<Header /> <Header />
<WelcomeSidebarModal /> <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> </Stack>
`; `;
@ -27,6 +72,51 @@ exports[`Query Copilot Sidebar snapshot test should render and set copilot used
> >
<Header /> <Header />
<WelcomeSidebarModal /> <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> </Stack>
`; `;
@ -42,6 +132,51 @@ exports[`Query Copilot Sidebar snapshot test should render samples without messa
> >
<Header /> <Header />
<WelcomeSidebarModal /> <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> </Stack>
`; `;
@ -57,5 +192,69 @@ exports[`Query Copilot Sidebar snapshot test should render with chat messages 1`
> >
<Header /> <Header />
<WelcomeSidebarModal /> <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> </Stack>
`; `;

View File

@ -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. 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> </Text>
<Image <Image
src="" src={Object {}}
style={ style={
Object { Object {
"margin": "16px auto", "margin": "16px auto",

View File

@ -23,7 +23,7 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
verticalAlign="center" verticalAlign="center"
> >
<Image <Image
src="" src={Object {}}
/> />
<Text <Text
style={ style={

View File

@ -76,6 +76,7 @@ interface IQueryTabStates {
isExecutionError: boolean; isExecutionError: boolean;
isExecuting: boolean; isExecuting: boolean;
showCopilotSidebar: boolean; showCopilotSidebar: boolean;
queryCopilotGeneratedQuery: string;
} }
export default class QueryTabComponent extends React.Component<IQueryTabComponentProps, IQueryTabStates> { 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, isExecutionError: this.props.isExecutionError,
isExecuting: false, isExecuting: false,
showCopilotSidebar: useQueryCopilot.getState().showCopilotSidebar, showCopilotSidebar: useQueryCopilot.getState().showCopilotSidebar,
queryCopilotGeneratedQuery: useQueryCopilot.getState().query,
}; };
this.isCloseClicked = false; this.isCloseClicked = false;
this.splitterId = this.props.tabId + "_splitter"; this.splitterId = this.props.tabId + "_splitter";
@ -334,6 +336,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
public onChangeContent(newContent: string): void { public onChangeContent(newContent: string): void {
this.setState({ this.setState({
sqlQueryEditorContent: newContent, sqlQueryEditorContent: newContent,
queryCopilotGeneratedQuery: "",
}); });
if (this.isPreferredApiMongoDB) { if (this.isPreferredApiMongoDB) {
if (newContent.length > 0) { if (newContent.length > 0) {
@ -365,6 +368,14 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
useCommandBar.getState().setContextButtons(this.getTabsButtons()); useCommandBar.getState().setContextButtons(this.getTabsButtons());
} }
public setEditorContent(): string {
if (this.state.queryCopilotGeneratedQuery) {
return this.state.queryCopilotGeneratedQuery;
}
return this.state.sqlQueryEditorContent;
}
private unsubscribeCopilotSidebar: () => void; private unsubscribeCopilotSidebar: () => void;
componentDidMount(): void { componentDidMount(): void {
@ -372,6 +383,9 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
if (this.state.showCopilotSidebar !== state.showCopilotSidebar) { if (this.state.showCopilotSidebar !== state.showCopilotSidebar) {
this.setState({ showCopilotSidebar: state.showCopilotSidebar }); this.setState({ showCopilotSidebar: state.showCopilotSidebar });
} }
if (this.state.queryCopilotGeneratedQuery !== state.query) {
this.setState({ queryCopilotGeneratedQuery: state.query });
}
}); });
useCommandBar.getState().setContextButtons(this.getTabsButtons()); useCommandBar.getState().setContextButtons(this.getTabsButtons());
@ -393,7 +407,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
<div className="queryEditor" style={{ height: "100%" }}> <div className="queryEditor" style={{ height: "100%" }}>
<EditorReact <EditorReact
language={"sql"} language={"sql"}
content={this.state.sqlQueryEditorContent} content={this.setEditorContent()}
isReadOnly={false} isReadOnly={false}
ariaLabel={"Editing Query"} ariaLabel={"Editing Query"}
lineNumbers={"on"} lineNumbers={"on"}

11
svgTransform.js Normal file
View File

@ -0,0 +1,11 @@
module.exports = {
process() {
return {
code: `module.exports = {};`,
};
},
getCacheKey() {
// The output is always the same.
return "svgTransform";
},
};