mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-23 19:01:28 +00:00
Compare commits
1 Commits
upload_doc
...
users/v-da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deb33daae3 |
@@ -1,3 +0,0 @@
|
||||
<svg width="10" height="14" viewBox="0 0 10 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 2.5C10 3.88071 7.76142 5 5 5C2.23858 5 0 3.88071 0 2.5C0 1.11929 2.23858 0 5 0C7.76142 0 10 1.11929 10 2.5ZM0 11.5V4.487C1.057 5.413 2.864 6 5 6C7.136 6 8.943 5.413 10 4.487V11.5C10 12.925 7.851 14 5 14C2.149 14 0 12.925 0 11.5Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 363 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="13" height="17" viewBox="0 0 13 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.21207 0C3.73772 0 3.32085 0.314446 3.19054 0.770537L0.940937 8.64415C0.747029 9.32283 1.25663 9.99841 1.96246 9.99841H3.22974L2.06002 14.6773C1.79611 15.7329 3.10089 16.4551 3.85526 15.6726L12.5318 6.81506L12.5354 6.81137C13.1762 6.1436 12.7152 5 11.7688 5H9.20509L10.4665 1.40582L10.469 1.39836C10.6983 0.710426 10.1863 0 9.46114 0H4.21207Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 475 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.5806 0.051598C6.83006 -0.157 6.24411 0.402481 6.03494 0.923322C5.79411 1.52303 5.58243 1.94395 5.32941 2.44707C5.17287 2.75833 5.00052 3.10106 4.79565 3.53704C4.32141 4.54625 3.84755 5.19347 3.5035 5.58154C3.33128 5.77579 3.19093 5.90585 3.09835 5.98435C3.05204 6.02362 3.01761 6.05005 2.99704 6.0652L2.9809 6.07684L1.109 7.18119C0.272443 7.67473 -0.0885815 8.69797 0.253045 9.6072L0.773038 10.9912C0.989444 11.5671 1.45891 12.0114 2.04591 12.1958L7.40179 13.8781C8.73654 14.2974 10.1555 13.5397 10.5497 12.1973L11.9139 7.55127C12.29 6.2705 11.3298 4.9878 9.99492 4.9878H8.60995C8.67586 4.76117 8.74339 4.50906 8.80466 4.24751C8.93612 3.68641 9.04781 3.04484 9.03753 2.51008C9.02797 2.01293 8.97781 1.49126 8.77353 1.04807C8.55437 0.572583 8.1709 0.21566 7.5806 0.051598ZM2.9768 6.07969L2.97492 6.08097L2.9768 6.07969Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 952 B |
@@ -1,29 +0,0 @@
|
||||
<svg width="287" height="225" viewBox="0 0 287 225" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.3" d="M7.75456 192.647H231.829C233.524 192.647 235.156 191.988 236.381 190.764C237.605 189.539 238.265 187.907 238.265 186.211V33.061C238.265 29.5132 234.56 26.248 229.568 26.248L10.8314 29.576C9.98368 29.576 9.16738 29.733 8.38248 30.047C7.59758 30.3923 6.90687 30.8319 6.31034 31.4598C5.71381 32.0563 5.24287 32.747 4.89751 33.5319C4.55216 34.3168 4.42658 35.1645 4.42658 35.9808L1.31836 186.274C1.31836 187.969 1.97767 189.602 3.20212 190.795C4.42657 191.988 6.05917 192.647 7.75456 192.647Z" fill="#1F1D20"/>
|
||||
<path d="M231.264 23.3906H6.37342C2.85705 23.3906 0 26.2477 0 29.764V183.228C0 186.745 2.85705 189.602 6.37342 189.602H231.295C234.811 189.602 237.669 186.745 237.669 183.228V29.764C237.637 26.2477 234.78 23.3906 231.264 23.3906Z" fill="url(#paint0_linear_1151_179507)"/>
|
||||
<path d="M228.313 32.7148H119.62V178.707H228.313V32.7148Z" fill="white"/>
|
||||
<path d="M121.158 32.7148H12.4648V178.707H121.158V32.7148Z" fill="#CDCDD0"/>
|
||||
<path d="M34.1909 0V144.799C34.1909 144.799 63.2009 141.91 86.7166 153.715C110.264 165.52 121.158 178.581 121.158 178.581V33.7508C121.158 33.7508 107.595 16.483 86.7166 10.1095C69.7313 4.8978 34.1909 0 34.1909 0Z" fill="#EAEAEA"/>
|
||||
<path d="M141.094 102.383L134.249 99.4006L127.374 102.383V23.3906H141.094V102.383Z" fill="url(#paint1_linear_1151_179507)"/>
|
||||
<path opacity="0.15" d="M206.9 61.2871H159.304C157.231 61.2871 155.567 62.9825 155.567 65.0233C155.567 67.0954 157.263 68.7594 159.304 68.7594H206.9C208.972 68.7594 210.636 67.064 210.636 65.0233C210.668 62.9511 208.972 61.2871 206.9 61.2871Z" fill="#1F1D20"/>
|
||||
<path opacity="0.15" d="M206.9 77.5498H159.304C157.231 77.5498 155.567 79.2452 155.567 81.2859C155.567 83.3581 157.263 85.0221 159.304 85.0221H206.9C208.972 85.0221 210.636 83.3267 210.636 81.2859C210.668 79.2138 208.972 77.5498 206.9 77.5498Z" fill="#1F1D20"/>
|
||||
<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M159.304 93.8428H206.838C208.91 93.8428 210.574 95.5381 210.574 97.5789C210.574 99.651 208.878 101.315 206.838 101.315H159.304C157.232 101.315 155.568 99.6196 155.568 97.5789C155.536 95.5381 157.2 93.8428 159.304 93.8428Z" fill="#1F1D20"/>
|
||||
<path d="M206.9 60.0303H159.304C157.231 60.0303 155.567 61.7257 155.567 63.7664C155.567 65.8385 157.263 67.5025 159.304 67.5025H206.9C208.972 67.5025 210.636 65.8072 210.636 63.7664C210.668 61.6943 208.972 60.0303 206.9 60.0303Z" fill="#50E6FF"/>
|
||||
<path d="M206.9 76.3262H159.304C157.231 76.3262 155.567 78.0216 155.567 80.0623C155.567 82.1345 157.263 83.7984 159.304 83.7984H206.9C208.972 83.7984 210.636 82.1031 210.636 80.0623C210.668 77.9902 208.972 76.3262 206.9 76.3262Z" fill="#32B0E7"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M159.304 92.5889H206.838C208.91 92.5889 210.574 94.2843 210.574 96.325C210.574 98.3972 208.878 100.061 206.838 100.061H159.304C157.232 100.093 155.568 98.3658 155.568 96.325C155.536 94.2843 157.2 92.5889 159.304 92.5889Z" fill="#185A97"/>
|
||||
<path opacity="0.2" d="M287 143.834H192V205.096C192 207.687 194.089 209.776 196.68 209.776H206.648V224.265L221.243 209.776H282.32C284.911 209.776 287 207.687 287 205.096V143.834Z" fill="#1F1D21"/>
|
||||
<path d="M283.827 140H195.173C193.428 140 192 141.428 192 143.173V202.769C192 204.514 193.428 205.942 195.173 205.942H206.648V220.431L221.243 205.942H283.827C285.572 205.942 287 204.514 287 202.769V143.173C287 141.428 285.572 140 283.827 140Z" fill="#49C8EF"/>
|
||||
<path d="M254.24 161.762H224.706C223.543 161.762 222.591 162.714 222.591 163.877C222.591 165.04 223.543 165.992 224.706 165.992H254.24C255.403 165.992 256.355 165.04 256.355 163.877C256.355 162.714 255.403 161.762 254.24 161.762Z" fill="#C3F1FF"/>
|
||||
<path d="M254.24 171.042H224.706C223.543 171.042 222.591 171.994 222.591 173.157C222.591 174.321 223.543 175.272 224.706 175.272H254.24C255.403 175.272 256.355 174.321 256.355 173.157C256.355 172.02 255.403 171.042 254.24 171.042Z" fill="#C3F1FF"/>
|
||||
<path d="M254.24 180.373H224.706C223.543 180.373 222.591 181.325 222.591 182.488C222.591 183.652 223.543 184.604 224.706 184.604H254.24C255.403 184.604 256.355 183.652 256.355 182.488C256.355 181.298 255.403 180.373 254.24 180.373Z" fill="#C3F1FF"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1151_179507" x1="118.845" y1="34.0854" x2="118.845" y2="202.888" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#007ED8"/>
|
||||
<stop offset="0.7065" stop-color="#002D4C"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_1151_179507" x1="87.2694" y1="-23.1274" x2="250.063" y2="275.059" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#007ED8"/>
|
||||
<stop offset="0.7065" stop-color="#002D4C"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.6 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 0C8.73438 0 9.44271 0.0963542 10.125 0.289062C10.8073 0.476562 11.4427 0.744792 12.0312 1.09375C12.625 1.44271 13.1641 1.86198 13.6484 2.35156C14.138 2.83594 14.5573 3.375 14.9062 3.96875C15.2552 4.55729 15.5234 5.19271 15.7109 5.875C15.9036 6.55729 16 7.26562 16 8C16 8.73438 15.9036 9.44271 15.7109 10.125C15.5234 10.8073 15.2552 11.4453 14.9062 12.0391C14.5573 12.6276 14.138 13.1667 13.6484 13.6562C13.1641 14.1406 12.625 14.5573 12.0312 14.9062C11.4427 15.2552 10.8073 15.526 10.125 15.7188C9.44271 15.9062 8.73438 16 8 16C7.26562 16 6.55729 15.9062 5.875 15.7188C5.19271 15.526 4.55469 15.2552 3.96094 14.9062C3.3724 14.5573 2.83333 14.1406 2.34375 13.6562C1.85938 13.1667 1.44271 12.6276 1.09375 12.0391C0.744792 11.4453 0.473958 10.8073 0.28125 10.125C0.09375 9.44271 0 8.73438 0 8C0 7.26562 0.09375 6.55729 0.28125 5.875C0.473958 5.19271 0.744792 4.55729 1.09375 3.96875C1.44271 3.375 1.85938 2.83594 2.34375 2.35156C2.83333 1.86198 3.3724 1.44271 3.96094 1.09375C4.55469 0.744792 5.19271 0.476562 5.875 0.289062C6.55729 0.0963542 7.26562 0 8 0ZM8 15C8.64583 15 9.26562 14.9167 9.85938 14.75C10.4583 14.5833 11.0156 14.349 11.5312 14.0469C12.0521 13.7396 12.5234 13.375 12.9453 12.9531C13.3724 12.526 13.737 12.0547 14.0391 11.5391C14.3464 11.0182 14.5833 10.4609 14.75 9.86719C14.9167 9.26823 15 8.64583 15 8C15 7.35417 14.9167 6.73438 14.75 6.14062C14.5833 5.54167 14.3464 4.98438 14.0391 4.46875C13.737 3.94792 13.3724 3.47656 12.9453 3.05469C12.5234 2.6276 12.0521 2.26302 11.5312 1.96094C11.0156 1.65365 10.4583 1.41667 9.85938 1.25C9.26562 1.08333 8.64583 1 8 1C7.35417 1 6.73177 1.08333 6.13281 1.25C5.53906 1.41667 4.98177 1.65365 4.46094 1.96094C3.94531 2.26302 3.47396 2.6276 3.04688 3.05469C2.625 3.47656 2.26042 3.94792 1.95312 4.46875C1.65104 4.98438 1.41667 5.54167 1.25 6.14062C1.08333 6.73438 1 7.35417 1 8C1 8.64583 1.08333 9.26823 1.25 9.86719C1.41667 10.4609 1.65104 11.0182 1.95312 11.5391C2.26042 12.0547 2.625 12.526 3.04688 12.9531C3.47396 13.375 3.94531 13.7396 4.46094 14.0469C4.98177 14.349 5.53906 14.5833 6.13281 14.75C6.73177 14.9167 7.35417 15 8 15ZM11.4609 5.24219L8.71094 8L11.4609 10.7578L10.7578 11.4609L8 8.71094L5.24219 11.4609L4.53906 10.7578L7.28906 8L4.53906 5.24219L5.24219 4.53906L8 7.28906L10.7578 4.53906L11.4609 5.24219Z" fill="#E00B1C"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
@@ -38,7 +38,6 @@ export enum MessageTypes {
|
||||
OpenPostgreSQLPasswordReset,
|
||||
OpenPostgresNetworkingBlade,
|
||||
OpenCosmosDBNetworkingBlade,
|
||||
DisplayNPSSurvey,
|
||||
}
|
||||
|
||||
export { Versions, ActionContracts, Diagnostics };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||
import { QueryCopilotSampleContainerId, QueryCopilotSampleDatabaseId } from "Common/Constants";
|
||||
import React from "react";
|
||||
import AddCollectionIcon from "../../images/AddCollection.svg";
|
||||
import AddSqlQueryIcon from "../../images/AddSqlQuery_16x16.svg";
|
||||
@@ -62,6 +62,13 @@ export const createDatabaseContextMenu = (container: Explorer, databaseId: strin
|
||||
return items;
|
||||
};
|
||||
|
||||
const isQueryCopilotMoreMenu = (selectedCollection: ViewModels.Collection): boolean => {
|
||||
return (
|
||||
selectedCollection.databaseId === QueryCopilotSampleDatabaseId &&
|
||||
selectedCollection.id() === QueryCopilotSampleContainerId
|
||||
);
|
||||
};
|
||||
|
||||
export const createCollectionContextMenuButton = (
|
||||
container: Explorer,
|
||||
selectedCollection: ViewModels.Collection
|
||||
@@ -96,61 +103,49 @@ export const createCollectionContextMenuButton = (
|
||||
});
|
||||
}
|
||||
|
||||
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
||||
items.push({
|
||||
iconSrc: AddStoredProcedureIcon,
|
||||
onClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, undefined);
|
||||
},
|
||||
label: "New Stored Procedure",
|
||||
});
|
||||
if (!isQueryCopilotMoreMenu(selectedCollection)) {
|
||||
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
||||
items.push({
|
||||
iconSrc: AddStoredProcedureIcon,
|
||||
onClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, undefined);
|
||||
},
|
||||
label: "New Stored Procedure",
|
||||
});
|
||||
|
||||
items.push({
|
||||
iconSrc: AddUdfIcon,
|
||||
onClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection);
|
||||
},
|
||||
label: "New UDF",
|
||||
});
|
||||
|
||||
items.push({
|
||||
iconSrc: AddTriggerIcon,
|
||||
onClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection, undefined);
|
||||
},
|
||||
label: "New Trigger",
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
iconSrc: AddUdfIcon,
|
||||
onClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection);
|
||||
},
|
||||
label: "New UDF",
|
||||
});
|
||||
|
||||
items.push({
|
||||
iconSrc: AddTriggerIcon,
|
||||
onClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection, undefined);
|
||||
},
|
||||
label: "New Trigger",
|
||||
iconSrc: DeleteCollectionIcon,
|
||||
onClick: () =>
|
||||
useSidePanel
|
||||
.getState()
|
||||
.openSidePanel(
|
||||
"Delete " + getCollectionName(),
|
||||
<DeleteCollectionConfirmationPane refreshDatabases={() => container.refreshAllDatabases()} />
|
||||
),
|
||||
label: `Delete ${getCollectionName()}`,
|
||||
styleClass: "deleteCollectionMenuItem",
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
iconSrc: DeleteCollectionIcon,
|
||||
onClick: () =>
|
||||
useSidePanel
|
||||
.getState()
|
||||
.openSidePanel(
|
||||
"Delete " + getCollectionName(),
|
||||
<DeleteCollectionConfirmationPane refreshDatabases={() => container.refreshAllDatabases()} />
|
||||
),
|
||||
label: `Delete ${getCollectionName()}`,
|
||||
styleClass: "deleteCollectionMenuItem",
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
export const createSampleCollectionContextMenuButton = (): TreeNodeMenuItem[] => {
|
||||
const items: TreeNodeMenuItem[] = [];
|
||||
if (userContext.apiType === "SQL") {
|
||||
items.push({
|
||||
iconSrc: AddSqlQueryIcon,
|
||||
onClick: () => useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot),
|
||||
label: "New SQL Query",
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ export class AccordionComponent extends React.Component<AccordionComponentProps>
|
||||
export interface AccordionItemComponentProps {
|
||||
title: string;
|
||||
isExpanded?: boolean;
|
||||
styles?: React.CSSProperties;
|
||||
}
|
||||
|
||||
interface AccordionItemComponentState {
|
||||
@@ -54,7 +53,6 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const { styles } = this.props;
|
||||
return (
|
||||
<div className="accordionItemContainer">
|
||||
<div className="accordionItemHeader" onClick={this.onHeaderClick} onKeyPress={this.onHeaderKeyPress}>
|
||||
@@ -62,11 +60,7 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
|
||||
{this.props.title}
|
||||
</div>
|
||||
<div className="accordionItemContent">
|
||||
<AnimateHeight
|
||||
style={{ ...styles }}
|
||||
duration={AccordionItemComponent.durationMS}
|
||||
height={this.state.isExpanded ? "auto" : 0}
|
||||
>
|
||||
<AnimateHeight duration={AccordionItemComponent.durationMS} height={this.state.isExpanded ? "auto" : 0}>
|
||||
{this.props.children}
|
||||
</AnimateHeight>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||
import * as React from "react";
|
||||
import AddCollectionIcon from "../../../../images/AddCollection.svg";
|
||||
import AddDatabaseIcon from "../../../../images/AddDatabase.svg";
|
||||
@@ -9,23 +8,23 @@ import AddUdfIcon from "../../../../images/AddUdf.svg";
|
||||
import BrowseQueriesIcon from "../../../../images/BrowseQuery.svg";
|
||||
import CosmosTerminalIcon from "../../../../images/Cosmos-Terminal.svg";
|
||||
import FeedbackIcon from "../../../../images/Feedback-Command.svg";
|
||||
import HostedTerminalIcon from "../../../../images/Hosted-Terminal.svg";
|
||||
import OpenQueryFromDiskIcon from "../../../../images/OpenQueryFromDisk.svg";
|
||||
import GitHubIcon from "../../../../images/github.svg";
|
||||
import HostedTerminalIcon from "../../../../images/Hosted-Terminal.svg";
|
||||
import NewNotebookIcon from "../../../../images/notebook/Notebook-new.svg";
|
||||
import ResetWorkspaceIcon from "../../../../images/notebook/Notebook-reset-workspace.svg";
|
||||
import OpenInTabIcon from "../../../../images/open-in-tab.svg";
|
||||
import OpenQueryFromDiskIcon from "../../../../images/OpenQueryFromDisk.svg";
|
||||
import SettingsIcon from "../../../../images/settings_15x15.svg";
|
||||
import SynapseIcon from "../../../../images/synapse-link.svg";
|
||||
import { AuthType } from "../../../AuthType";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { Platform, configContext } from "../../../ConfigContext";
|
||||
import { configContext, Platform } from "../../../ConfigContext";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||
import { JunoClient } from "../../../Juno/JunoClient";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import { getCollectionName, getDatabaseName } from "../../../Utils/APITypeUtils";
|
||||
import { isRunningOnNationalCloud } from "../../../Utils/CloudUtils";
|
||||
import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import Explorer from "../../Explorer";
|
||||
import { useNotebook } from "../../Notebook/useNotebook";
|
||||
@@ -36,7 +35,7 @@ import { GitHubReposPanel } from "../../Panes/GitHubReposPanel/GitHubReposPanel"
|
||||
import { LoadQueryPane } from "../../Panes/LoadQueryPane/LoadQueryPane";
|
||||
import { SettingsPane } from "../../Panes/SettingsPane/SettingsPane";
|
||||
import { useDatabases } from "../../useDatabases";
|
||||
import { SelectedNodeState, useSelectedNode } from "../../useSelectedNode";
|
||||
import { SelectedNodeState } from "../../useSelectedNode";
|
||||
|
||||
let counter = 0;
|
||||
|
||||
@@ -145,9 +144,7 @@ export function createStaticCommandBarButtons(
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled:
|
||||
useSelectedNode.getState().isQueryCopilotCollectionSelected() ||
|
||||
selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||
};
|
||||
|
||||
newStoredProcedureBtn.children = createScriptCommandButtons(selectedNodeState);
|
||||
@@ -268,7 +265,6 @@ function createNewCollectionGroup(container: Explorer): CommandButtonComponentPr
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
id: "createNewContainerCommandButton",
|
||||
disabled: useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -293,8 +289,7 @@ function createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonCo
|
||||
onCommandClick: () => container.openEnableSynapseLinkDialog(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled:
|
||||
useSelectedNode.getState().isQueryCopilotCollectionSelected() || useNotebook.getState().isSynapseLinkUpdating,
|
||||
disabled: useNotebook.getState().isSynapseLinkUpdating,
|
||||
ariaLabel: label,
|
||||
};
|
||||
}
|
||||
@@ -314,7 +309,6 @@ function createNewDatabase(container: Explorer): CommandButtonComponentProps {
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -326,12 +320,8 @@ function createNewSQLQueryButton(selectedNodeState: SelectedNodeState): CommandB
|
||||
iconSrc: AddSqlQueryIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
if (useSelectedNode.getState().isQueryCopilotCollectionSelected()) {
|
||||
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
|
||||
} else {
|
||||
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection);
|
||||
}
|
||||
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection);
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
@@ -376,9 +366,7 @@ export function createScriptCommandButtons(selectedNodeState: SelectedNodeState)
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled:
|
||||
useSelectedNode.getState().isQueryCopilotCollectionSelected() ||
|
||||
selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||
};
|
||||
buttons.push(newStoredProcedureBtn);
|
||||
}
|
||||
@@ -395,9 +383,7 @@ export function createScriptCommandButtons(selectedNodeState: SelectedNodeState)
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled:
|
||||
useSelectedNode.getState().isQueryCopilotCollectionSelected() ||
|
||||
selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||
};
|
||||
buttons.push(newUserDefinedFunctionBtn);
|
||||
}
|
||||
@@ -414,9 +400,7 @@ export function createScriptCommandButtons(selectedNodeState: SelectedNodeState)
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled:
|
||||
useSelectedNode.getState().isQueryCopilotCollectionSelected() ||
|
||||
selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||
};
|
||||
buttons.push(newTriggerBtn);
|
||||
}
|
||||
@@ -440,7 +424,7 @@ function createNewNotebookButton(container: Explorer): CommandButtonComponentPro
|
||||
onCommandClick: () => container.onNewNotebookClicked(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
disabled: false,
|
||||
ariaLabel: label,
|
||||
};
|
||||
}
|
||||
@@ -453,7 +437,7 @@ function createuploadNotebookButton(container: Explorer): CommandButtonComponent
|
||||
onCommandClick: () => container.openUploadFilePanel(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
disabled: false,
|
||||
ariaLabel: label,
|
||||
};
|
||||
}
|
||||
@@ -468,7 +452,7 @@ function createOpenQueryButton(container: Explorer): CommandButtonComponentProps
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
disabled: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -481,7 +465,7 @@ function createOpenQueryFromDiskButton(): CommandButtonComponentProps {
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
disabled: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -545,8 +529,7 @@ function createOpenCassandraTerminalButton(container: Explorer): CommandButtonCo
|
||||
function createOpenPsqlTerminalButton(container: Explorer): CommandButtonComponentProps {
|
||||
const label = "Open PSQL Shell";
|
||||
const disableButton =
|
||||
(!useNotebook.getState().isNotebooksEnabledForAccount && !useNotebook.getState().isNotebookEnabled) ||
|
||||
useSelectedNode.getState().isQueryCopilotCollectionSelected();
|
||||
!useNotebook.getState().isNotebooksEnabledForAccount && !useNotebook.getState().isNotebookEnabled;
|
||||
return {
|
||||
iconSrc: HostedTerminalIcon,
|
||||
iconAlt: label,
|
||||
@@ -573,7 +556,7 @@ function createNotebookWorkspaceResetButton(container: Explorer): CommandButtonC
|
||||
onCommandClick: () => container.resetNotebookWorkspace(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
disabled: false,
|
||||
ariaLabel: label,
|
||||
};
|
||||
}
|
||||
@@ -599,7 +582,7 @@ function createManageGitHubAccountButton(container: Explorer): CommandButtonComp
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
disabled: false,
|
||||
ariaLabel: label,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
import { Dropdown, IDropdownOption } from "@fluentui/react";
|
||||
import * as React from "react";
|
||||
import AnimateHeight from "react-animate-height";
|
||||
import ClearIcon from "../../../../images/Clear-1.svg";
|
||||
import ChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
|
||||
import ChevronUpIcon from "../../../../images/QueryBuilder/CollapseChevronUp_16x.png";
|
||||
import LoaderIcon from "../../../../images/circular_loader_black_16x16.gif";
|
||||
import ClearIcon from "../../../../images/Clear-1.svg";
|
||||
import ErrorBlackIcon from "../../../../images/error_black.svg";
|
||||
import ErrorRedIcon from "../../../../images/error_red.svg";
|
||||
import infoBubbleIcon from "../../../../images/info-bubble-9x9.svg";
|
||||
import InfoIcon from "../../../../images/info_color.svg";
|
||||
import LoadingIcon from "../../../../images/loading.svg";
|
||||
import ChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
|
||||
import ChevronUpIcon from "../../../../images/QueryBuilder/CollapseChevronUp_16x.png";
|
||||
import { ClientDefaults, KeyCodes } from "../../../Common/Constants";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import { useNotificationConsole } from "../../../hooks/useNotificationConsole";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import { ConsoleData, ConsoleDataType } from "./ConsoleData";
|
||||
|
||||
export interface NotificationConsoleComponentProps {
|
||||
@@ -256,7 +256,6 @@ export class NotificationConsoleComponent extends React.Component<
|
||||
if (this.props.isConsoleExpanded && this.consoleHeaderElement) {
|
||||
this.consoleHeaderElement.focus();
|
||||
}
|
||||
useNotificationConsole.getState().setConsoleAnimationFinished(true);
|
||||
};
|
||||
|
||||
private updateConsoleData = (prevProps: NotificationConsoleComponentProps): void => {
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import {
|
||||
actions,
|
||||
AppState,
|
||||
castToSessionId,
|
||||
ContentRef,
|
||||
createKernelRef,
|
||||
JupyterHostRecordProps,
|
||||
ServerConfig as JupyterServerConfig,
|
||||
KernelInfo,
|
||||
KernelRef,
|
||||
RemoteKernelProps,
|
||||
actions,
|
||||
castToSessionId,
|
||||
createKernelRef,
|
||||
selectors,
|
||||
ServerConfig as JupyterServerConfig,
|
||||
} from "@nteract/core";
|
||||
import { Channels, childOf, createMessage, message, ofMessageType } from "@nteract/messaging";
|
||||
import { Channels, childOf, createMessage, JupyterMessage, message, ofMessageType } from "@nteract/messaging";
|
||||
import { defineConfigOption } from "@nteract/mythic-configuration";
|
||||
import { RecordOf } from "immutable";
|
||||
import { Action, AnyAction } from "redux";
|
||||
import { StateObservable, ofType } from "redux-observable";
|
||||
import { ofType, StateObservable } from "redux-observable";
|
||||
import { kernels, sessions } from "rx-jupyter";
|
||||
import { EMPTY, Observable, Observer, Subject, Subscriber, concat, from, interval, merge, of, timer } from "rxjs";
|
||||
import { concat, EMPTY, from, interval, merge, Observable, Observer, of, Subject, Subscriber, timer } from "rxjs";
|
||||
import {
|
||||
catchError,
|
||||
concatMap,
|
||||
@@ -35,17 +35,17 @@ import {
|
||||
import { webSocket } from "rxjs/webSocket";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { Areas } from "../../../Common/Constants";
|
||||
import { ActionModifiers, Action as TelemetryAction } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import { useTabs } from "../../../hooks/useTabs";
|
||||
import { Action as TelemetryAction, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { logConsoleError, logConsoleInfo } from "../../../Utils/NotificationConsoleUtils";
|
||||
import { useTabs } from "../../../hooks/useTabs";
|
||||
import { useDialog } from "../../Controls/Dialog";
|
||||
import * as FileSystemUtil from "../FileSystemUtil";
|
||||
import * as cdbActions from "../NotebookComponent/actions";
|
||||
import { NotebookContentProviderType, NotebookUtil } from "../NotebookUtil";
|
||||
import * as CdbActions from "./actions";
|
||||
import * as TextFile from "./contents/file/text-file";
|
||||
import { CdbAppState, JupyterMessage } from "./types";
|
||||
import { CdbAppState } from "./types";
|
||||
|
||||
interface NotebookServiceConfig extends JupyterServerConfig {
|
||||
userPuid?: string;
|
||||
@@ -106,8 +106,10 @@ const formWebSocketURL = (serverConfig: NotebookServiceConfig, kernelId: string,
|
||||
if (sessionId) {
|
||||
params.append("session_id", sessionId);
|
||||
}
|
||||
|
||||
const q = params.toString();
|
||||
const suffix = q !== "" ? `?${q}` : "";
|
||||
|
||||
const url = (serverConfig.endpoint.slice(0, -1) || "") + `api/kernels/${kernelId}/channels${suffix}`;
|
||||
|
||||
return url.replace(/^http(s)?/, "ws$1");
|
||||
@@ -239,10 +241,10 @@ const connect = (serverConfig: NotebookServiceConfig, kernelID: string, sessionI
|
||||
...message,
|
||||
header: {
|
||||
session: sessionID,
|
||||
token: serverConfig.token,
|
||||
...message.header,
|
||||
},
|
||||
};
|
||||
|
||||
wsSubject.next(sessionizedMessage);
|
||||
} else {
|
||||
console.error("Message must be an object, the app sent", message);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { CellId } from "@nteract/commutable";
|
||||
import { AppState } from "@nteract/core";
|
||||
import { MessageType } from "@nteract/messaging";
|
||||
import * as Immutable from "immutable";
|
||||
import { Notebook } from "../../../Common/Constants";
|
||||
|
||||
@@ -54,26 +53,3 @@ export const makeCdbRecord = Immutable.Record<CdbRecordProps>({
|
||||
pendingSnapshotRequest: undefined,
|
||||
notebookSnapshotError: undefined,
|
||||
});
|
||||
|
||||
export interface JupyterMessage<MT extends MessageType = MessageType, C = any> {
|
||||
header: JupyterMessageHeader<MT>;
|
||||
parent_header:
|
||||
| JupyterMessageHeader<any>
|
||||
| {
|
||||
msg_id?: string;
|
||||
};
|
||||
metadata: object;
|
||||
content: C;
|
||||
channel: string;
|
||||
buffers?: Uint8Array | null;
|
||||
}
|
||||
|
||||
export interface JupyterMessageHeader<MT extends MessageType = MessageType> {
|
||||
msg_id: string;
|
||||
username: string;
|
||||
date: string;
|
||||
msg_type: MT;
|
||||
version: string;
|
||||
session: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ export interface PanelContainerProps {
|
||||
panelContent?: JSX.Element;
|
||||
isConsoleExpanded: boolean;
|
||||
isOpen: boolean;
|
||||
isConsoleAnimationFinished?: boolean;
|
||||
panelWidth?: string;
|
||||
onRenderNavigationContent?: IRenderFunction<IPanelProps>;
|
||||
}
|
||||
@@ -29,7 +28,7 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
|
||||
};
|
||||
}
|
||||
|
||||
omponentDidMount(): void {
|
||||
componentDidMount(): void {
|
||||
window.addEventListener("resize", () => this.setState({ height: this.getPanelHeight() }));
|
||||
}
|
||||
|
||||
@@ -37,15 +36,6 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
|
||||
window.removeEventListener("resize", () => this.setState({ height: this.getPanelHeight() }));
|
||||
}
|
||||
|
||||
componentDidUpdate(): void {
|
||||
if (useNotificationConsole.getState().consoleAnimationFinished || this.state.height !== this.getPanelHeight()) {
|
||||
this.setState({
|
||||
height: this.getPanelHeight(),
|
||||
});
|
||||
useNotificationConsole.getState().setConsoleAnimationFinished(false);
|
||||
}
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
if (!this.props.panelContent) {
|
||||
return <></>;
|
||||
@@ -69,7 +59,7 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
|
||||
header: { padding: "0 0 8px 34px" },
|
||||
commands: { marginTop: 8 },
|
||||
}}
|
||||
style={{ height: this.state.height }}
|
||||
style={{ height: this.getPanelHeight() }}
|
||||
>
|
||||
{this.props.panelContent}
|
||||
</Panel>
|
||||
@@ -85,22 +75,16 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
|
||||
};
|
||||
|
||||
private getPanelHeight = (): string => {
|
||||
const notificationConsole = document.getElementById("explorerNotificationConsole");
|
||||
if (notificationConsole) {
|
||||
return window.innerHeight - notificationConsole.clientHeight + "px";
|
||||
}
|
||||
return (
|
||||
window.innerHeight -
|
||||
(this.props.isConsoleExpanded
|
||||
? PanelContainerComponent.consoleContentHeight + PanelContainerComponent.consoleHeaderHeight
|
||||
: PanelContainerComponent.consoleHeaderHeight) +
|
||||
"px"
|
||||
);
|
||||
const consoleHeight = this.props.isConsoleExpanded
|
||||
? PanelContainerComponent.consoleContentHeight + PanelContainerComponent.consoleHeaderHeight
|
||||
: PanelContainerComponent.consoleHeaderHeight;
|
||||
const panelHeight = window.innerHeight - consoleHeight;
|
||||
return panelHeight + "px";
|
||||
};
|
||||
}
|
||||
|
||||
export const SidePanel: React.FC = () => {
|
||||
const isConsoleExpanded = useNotificationConsole((state) => state.isExpanded);
|
||||
const isConsoleAnimationFinished = useNotificationConsole((state) => state.consoleAnimationFinished);
|
||||
const { isOpen, panelContent, panelWidth, headerText } = useSidePanel((state) => {
|
||||
return {
|
||||
isOpen: state.isOpen,
|
||||
@@ -118,7 +102,6 @@ export const SidePanel: React.FC = () => {
|
||||
headerText={headerText}
|
||||
isConsoleExpanded={isConsoleExpanded}
|
||||
panelWidth={panelWidth}
|
||||
isConsoleAnimationFinished={isConsoleAnimationFinished}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { PrimaryButton } from "@fluentui/react";
|
||||
import React, { CSSProperties } from "react";
|
||||
import React from "react";
|
||||
|
||||
export interface PanelFooterProps {
|
||||
buttonLabel: string;
|
||||
isButtonDisabled?: boolean;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
export const PanelFooterComponent: React.FunctionComponent<PanelFooterProps> = ({
|
||||
buttonLabel,
|
||||
isButtonDisabled,
|
||||
style,
|
||||
}: PanelFooterProps): JSX.Element => (
|
||||
<div className="panelFooter" style={style}>
|
||||
<div className="panelFooter">
|
||||
<PrimaryButton
|
||||
type="submit"
|
||||
id="sidePanelOkButton"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { CSSProperties, FunctionComponent, ReactNode } from "react";
|
||||
import React, { FunctionComponent, ReactNode } from "react";
|
||||
import { PanelFooterComponent } from "../PanelFooterComponent";
|
||||
import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent";
|
||||
import { PanelLoadingScreen } from "../PanelLoadingScreen";
|
||||
@@ -11,7 +11,6 @@ export interface RightPaneFormProps {
|
||||
isSubmitButtonHidden?: boolean;
|
||||
isSubmitButtonDisabled?: boolean;
|
||||
children?: ReactNode;
|
||||
footerStyle?: CSSProperties;
|
||||
}
|
||||
|
||||
export const RightPaneForm: FunctionComponent<RightPaneFormProps> = ({
|
||||
@@ -22,7 +21,6 @@ export const RightPaneForm: FunctionComponent<RightPaneFormProps> = ({
|
||||
isSubmitButtonHidden = false,
|
||||
isSubmitButtonDisabled = false,
|
||||
children,
|
||||
footerStyle,
|
||||
}: RightPaneFormProps) => {
|
||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
@@ -35,11 +33,7 @@ export const RightPaneForm: FunctionComponent<RightPaneFormProps> = ({
|
||||
{formError && <PanelInfoErrorComponent messageType="error" message={formError} showErrorDetails={true} />}
|
||||
{children}
|
||||
{!isSubmitButtonHidden && (
|
||||
<PanelFooterComponent
|
||||
buttonLabel={submitButtonText}
|
||||
isButtonDisabled={isSubmitButtonDisabled}
|
||||
style={footerStyle}
|
||||
/>
|
||||
<PanelFooterComponent buttonLabel={submitButtonText} isButtonDisabled={isSubmitButtonDisabled} />
|
||||
)}
|
||||
</form>
|
||||
{isExecuting && <PanelLoadingScreen />}
|
||||
|
||||
@@ -139,11 +139,10 @@ export const SaveQueryPane: FunctionComponent<SaveQueryPaneProps> = ({
|
||||
onSubmit: () => {
|
||||
isSaveQueryEnabled() ? submit() : setupQueries();
|
||||
},
|
||||
footerStyle: isSaveQueryEnabled() ? { flexGrow: 0 } : {},
|
||||
};
|
||||
return (
|
||||
<RightPaneForm {...props}>
|
||||
<div className="panelFormWrapper" style={{ flexGrow: 1 }}>
|
||||
<div className="panelFormWrapper">
|
||||
<div className="panelMainContent">
|
||||
{!isSaveQueryEnabled() ? (
|
||||
<Text variant="small">{setupSaveQueriesText}</Text>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
exports[`Save Query Pane should render Default properly 1`] = `
|
||||
<RightPaneForm
|
||||
footerStyle={Object {}}
|
||||
formError=""
|
||||
isExecuting={false}
|
||||
onSubmit={[Function]}
|
||||
@@ -10,11 +9,6 @@ exports[`Save Query Pane should render Default properly 1`] = `
|
||||
>
|
||||
<div
|
||||
className="panelFormWrapper"
|
||||
style={
|
||||
Object {
|
||||
"flexGrow": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="panelMainContent"
|
||||
|
||||
@@ -2,12 +2,12 @@ import { Checkbox, ChoiceGroup, IChoiceGroupOption, SpinButton } from "@fluentui
|
||||
import * as Constants from "Common/Constants";
|
||||
import { InfoTooltip } from "Common/Tooltip/InfoTooltip";
|
||||
import { configContext } from "ConfigContext";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import React, { FunctionComponent, MouseEvent, useState } from "react";
|
||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import * as StringUtility from "Shared/StringUtility";
|
||||
import { userContext } from "UserContext";
|
||||
import { logConsoleInfo } from "Utils/NotificationConsoleUtils";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import React, { FunctionComponent, MouseEvent, useState } from "react";
|
||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||
|
||||
export const SettingsPane: FunctionComponent = () => {
|
||||
@@ -29,7 +29,7 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
const [crossPartitionQueryEnabled, setCrossPartitionQueryEnabled] = useState<boolean>(
|
||||
LocalStorageUtility.hasItem(StorageKey.IsCrossPartitionQueryEnabled)
|
||||
? LocalStorageUtility.getEntryString(StorageKey.IsCrossPartitionQueryEnabled) === "true"
|
||||
: false
|
||||
: true
|
||||
);
|
||||
const [graphAutoVizDisabled, setGraphAutoVizDisabled] = useState<string>(
|
||||
LocalStorageUtility.hasItem(StorageKey.IsGraphAutoVizDisabled)
|
||||
|
||||
@@ -142,7 +142,7 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
</div>
|
||||
<StyledCheckboxBase
|
||||
ariaLabel="Enable cross partition query"
|
||||
checked={false}
|
||||
checked={true}
|
||||
className="padding"
|
||||
onChange={[Function]}
|
||||
styles={
|
||||
|
||||
@@ -13,8 +13,11 @@ import {
|
||||
} from "@fluentui/react";
|
||||
import { QueryCopilotSampleDatabaseId, StyleConstants } from "Common/Constants";
|
||||
import { handleError } from "Common/ErrorHandlingUtils";
|
||||
import { createCollection } from "Common/dataAccess/createCollection";
|
||||
import * as DataModels from "Contracts/DataModels";
|
||||
import { ContainerSampleGenerator } from "Explorer/DataSamples/ContainerSampleGenerator";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { AllPropertiesIndexed } from "Explorer/Panes/AddCollectionPanel";
|
||||
import { PromptCard } from "Explorer/QueryCopilot/PromptCard";
|
||||
import { useDatabases } from "Explorer/useDatabases";
|
||||
import { useCarousel } from "hooks/useCarousel";
|
||||
@@ -75,27 +78,30 @@ export const QueryCopilotCarousel: React.FC<QueryCopilotCarouselProps> = ({
|
||||
};
|
||||
|
||||
const createSampleDatabase = async (): Promise<void> => {
|
||||
// const database = useDatabases.getState().findDatabaseWithId(QueryCopilotSampleDatabaseId);
|
||||
const database = useDatabases.getState().findDatabaseWithId(QueryCopilotSampleDatabaseId);
|
||||
if (database) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// setIsCreatingDatabase(true);
|
||||
// setSpinnerText("Setting up your database...");
|
||||
// const params: DataModels.CreateCollectionParams = {
|
||||
// createNewDatabase: false,
|
||||
// collectionId: "SampleContainer",
|
||||
// databaseId: QueryCopilotSampleDatabaseId,
|
||||
// databaseLevelThroughput: true,
|
||||
// autoPilotMaxThroughput: 1000,
|
||||
// offerThroughput: undefined,
|
||||
// indexingPolicy: AllPropertiesIndexed,
|
||||
// partitionKey: {
|
||||
// paths: ["/categoryId"],
|
||||
// kind: "Hash",
|
||||
// version: 2,
|
||||
// },
|
||||
// };
|
||||
// await createCollection(params);
|
||||
// await explorer.refreshAllDatabases();
|
||||
setIsCreatingDatabase(true);
|
||||
setSpinnerText("Setting up your database...");
|
||||
const params: DataModels.CreateCollectionParams = {
|
||||
createNewDatabase: true,
|
||||
collectionId: "SampleContainer",
|
||||
databaseId: QueryCopilotSampleDatabaseId,
|
||||
databaseLevelThroughput: true,
|
||||
autoPilotMaxThroughput: 1000,
|
||||
offerThroughput: undefined,
|
||||
indexingPolicy: AllPropertiesIndexed,
|
||||
partitionKey: {
|
||||
paths: ["/categoryId"],
|
||||
kind: "Hash",
|
||||
version: 2,
|
||||
},
|
||||
};
|
||||
await createCollection(params);
|
||||
await explorer.refreshAllDatabases();
|
||||
const database = useDatabases.getState().findDatabaseWithId(QueryCopilotSampleDatabaseId);
|
||||
await database.loadCollections();
|
||||
const collection = database.findCollectionWithId("SampleContainer");
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
.modalContentPadding {
|
||||
padding-top: 15px;
|
||||
width: 513px;
|
||||
height: 638px;
|
||||
}
|
||||
|
||||
.exitPadding {
|
||||
padding: 0px 7px 0px 0px;
|
||||
}
|
||||
|
||||
.previewMargin {
|
||||
margin: 8px 10px 0px 0;
|
||||
}
|
||||
|
||||
.preview {
|
||||
padding: 0px 4px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 8px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.exitIcon {
|
||||
margin: 3px 7px 0px 0px;
|
||||
color: #424242;
|
||||
}
|
||||
|
||||
.text {
|
||||
width: 348px;
|
||||
padding: 8px 16px 8px 16px;
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.imageTextPadding {
|
||||
padding: 0px 5px 0px 0px;
|
||||
}
|
||||
|
||||
.buttonPadding {
|
||||
padding: 15px 0px 0px 0px;
|
||||
}
|
||||
|
||||
.tryButton {
|
||||
border-radius: 4px;
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import { IconButton, Image, Link, Modal, PrimaryButton, Stack, StackItem, Text } from "@fluentui/react";
|
||||
import { useBoolean } from "@fluentui/react-hooks";
|
||||
import React from "react";
|
||||
import Database from "../../../../images/CopilotDatabase.svg";
|
||||
import Flash from "../../../../images/CopilotFlash.svg";
|
||||
import Thumb from "../../../../images/CopilotThumb.svg";
|
||||
import CoplilotWelcomeIllustration from "../../../../images/CopliotWelcomeIllustration.svg";
|
||||
import "./WelcomeModal.css";
|
||||
|
||||
export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element => {
|
||||
const [isModalVisible, { setFalse: hideModal }] = useBoolean(visible);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (visible) {
|
||||
window.localStorage.setItem("hideWelcomeModal", "true");
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal isOpen={isModalVisible} onDismiss={hideModal} isBlocking={false}>
|
||||
<Stack className="modalContentPadding">
|
||||
<Stack horizontal>
|
||||
<Stack horizontal grow={4} horizontalAlign="end">
|
||||
<Stack.Item>
|
||||
<Image src={CoplilotWelcomeIllustration} />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Stack horizontal grow={1} horizontalAlign="end" verticalAlign="start" className="exitPadding">
|
||||
<Stack.Item className="previewMargin">
|
||||
<Text className="preview">Preview</Text>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<IconButton
|
||||
onClick={hideModal}
|
||||
iconProps={{ iconName: "Cancel" }}
|
||||
title="Exit"
|
||||
ariaLabel="Exit"
|
||||
className="exitIcon"
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Stack horizontalAlign="center">
|
||||
<Stack.Item align="center">
|
||||
<Text className="title bold">Welcome to Copilot in CosmosDB</Text>
|
||||
</Stack.Item>
|
||||
<Stack.Item align="center" className="text">
|
||||
<Stack horizontal>
|
||||
<StackItem align="start" className="imageTextPadding">
|
||||
<Image src={Flash} />
|
||||
</StackItem>
|
||||
<StackItem align="start">
|
||||
<Text className="bold">
|
||||
Let copilot do the work for you
|
||||
<br />
|
||||
</Text>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
<Text>
|
||||
Ask Copilot to generate a query by describing the query in your words.
|
||||
<br />
|
||||
<Link href="">Learn more</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
<Stack.Item align="center" className="text">
|
||||
<Stack horizontal>
|
||||
<StackItem align="start" className="imageTextPadding">
|
||||
<Image src={Thumb} />
|
||||
</StackItem>
|
||||
<StackItem align="start">
|
||||
<Text className="bold">
|
||||
Use your judgement
|
||||
<br />
|
||||
</Text>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
<Text>
|
||||
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
||||
<br />
|
||||
<Link href="">Read preview terms</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
<Stack.Item align="center" className="text">
|
||||
<Stack horizontal>
|
||||
<StackItem align="start" className="imageTextPadding">
|
||||
<Image src={Database} />
|
||||
</StackItem>
|
||||
<StackItem align="start">
|
||||
<Text className="bold">
|
||||
Copilot currently works only a sample database
|
||||
<br />
|
||||
</Text>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
<Text>
|
||||
Copilot is setup on a sample database we have configured for you at no cost
|
||||
<br />
|
||||
<Link href="">Learn more</Link>
|
||||
</Text>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Stack className="buttonPadding">
|
||||
<Stack.Item align="center">
|
||||
<PrimaryButton onClick={hideModal} className="tryButton">
|
||||
Try Copilot
|
||||
</PrimaryButton>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -5,15 +5,7 @@ import { DeletePopup } from "./DeletePopup";
|
||||
|
||||
describe("Delete Popup snapshot test", () => {
|
||||
it("should render when showDeletePopup is true", () => {
|
||||
const wrapper = shallow(
|
||||
<DeletePopup
|
||||
showDeletePopup={true}
|
||||
setShowDeletePopup={() => any}
|
||||
setQuery={() => any}
|
||||
clearFeedback={() => any}
|
||||
showFeedbackBar={() => any}
|
||||
/>
|
||||
);
|
||||
const wrapper = shallow(<DeletePopup showDeletePopup={true} setShowDeletePopup={() => any} setQuery={() => any} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,20 +5,14 @@ export const DeletePopup = ({
|
||||
showDeletePopup,
|
||||
setShowDeletePopup,
|
||||
setQuery,
|
||||
clearFeedback,
|
||||
showFeedbackBar,
|
||||
}: {
|
||||
showDeletePopup: boolean;
|
||||
setShowDeletePopup: Dispatch<SetStateAction<boolean>>;
|
||||
setQuery: Dispatch<SetStateAction<string>>;
|
||||
clearFeedback: Dispatch<SetStateAction<void>>;
|
||||
showFeedbackBar: Dispatch<SetStateAction<boolean>>;
|
||||
}): JSX.Element => {
|
||||
const deleteCode = () => {
|
||||
setQuery("");
|
||||
setShowDeletePopup(false);
|
||||
clearFeedback();
|
||||
showFeedbackBar(false);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
import { submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React from "react";
|
||||
import { getUserEmail } from "../../Utils/UserUtils";
|
||||
|
||||
export const QueryCopilotFeedbackModal: React.FC = (): JSX.Element => {
|
||||
const {
|
||||
@@ -27,7 +26,6 @@ export const QueryCopilotFeedbackModal: React.FC = (): JSX.Element => {
|
||||
const [isContactAllowed, setIsContactAllowed] = React.useState<boolean>(true);
|
||||
const [description, setDescription] = React.useState<string>("");
|
||||
const [doNotShowAgainChecked, setDoNotShowAgainChecked] = React.useState<boolean>(false);
|
||||
const [contact, setContact] = React.useState<string>(getUserEmail());
|
||||
return (
|
||||
<Modal isOpen={showFeedbackModal}>
|
||||
<Stack style={{ padding: 24 }}>
|
||||
@@ -71,10 +69,7 @@ export const QueryCopilotFeedbackModal: React.FC = (): JSX.Element => {
|
||||
{ key: "no", text: "No, do not contact me." },
|
||||
]}
|
||||
selectedKey={isContactAllowed ? "yes" : "no"}
|
||||
onChange={(_, option) => {
|
||||
setIsContactAllowed(option.key === "yes");
|
||||
setContact(option.key === "yes" ? getUserEmail() : "");
|
||||
}}
|
||||
onChange={(_, option) => setIsContactAllowed(option.key === "yes")}
|
||||
></ChoiceGroup>
|
||||
<Text style={{ fontSize: 12, marginBottom: 14 }}>
|
||||
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your
|
||||
@@ -97,7 +92,7 @@ export const QueryCopilotFeedbackModal: React.FC = (): JSX.Element => {
|
||||
onClick={() => {
|
||||
closeFeedbackModal();
|
||||
setHideFeedbackModalForLikedQueries(doNotShowAgainChecked);
|
||||
submitFeedback({ generatedQuery, likeQuery, description, userPrompt, contact });
|
||||
submitFeedback({ generatedQuery, likeQuery, description, userPrompt });
|
||||
}}
|
||||
>
|
||||
Submit
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable no-console */
|
||||
import { FeedOptions, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
||||
import { FeedOptions } from "@azure/cosmos";
|
||||
import {
|
||||
Callout,
|
||||
CommandBarButton,
|
||||
@@ -12,11 +12,9 @@ import {
|
||||
Separator,
|
||||
Spinner,
|
||||
Stack,
|
||||
TeachingBubble,
|
||||
Text,
|
||||
TextField,
|
||||
} from "@fluentui/react";
|
||||
import { useBoolean } from "@fluentui/react-hooks";
|
||||
import {
|
||||
QueryCopilotSampleContainerId,
|
||||
QueryCopilotSampleContainerSchema,
|
||||
@@ -25,8 +23,7 @@ import {
|
||||
import { getErrorMessage, handleError } from "Common/ErrorHandlingUtils";
|
||||
import { shouldEnableCrossPartitionKey } from "Common/HeadersUtility";
|
||||
import { MinimalQueryIterator } from "Common/IteratorUtilities";
|
||||
import { sampleDataClient } from "Common/SampleDataClient";
|
||||
import { getCommonQueryOptions } from "Common/dataAccess/queryDocuments";
|
||||
import { queryDocuments } from "Common/dataAccess/queryDocuments";
|
||||
import { queryDocumentsPage } from "Common/dataAccess/queryDocumentsPage";
|
||||
import { QueryResults } from "Contracts/ViewModels";
|
||||
import { CommandButtonComponentProps } from "Explorer/Controls/CommandButton/CommandButtonComponent";
|
||||
@@ -34,7 +31,6 @@ import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { useCommandBar } from "Explorer/Menus/CommandBar/CommandBarComponentAdapter";
|
||||
import { SaveQueryPane } from "Explorer/Panes/SaveQueryPane/SaveQueryPane";
|
||||
import { WelcomeModal } from "Explorer/QueryCopilot/Modal/WelcomeModal";
|
||||
import { CopyPopup } from "Explorer/QueryCopilot/Popup/CopyPopup";
|
||||
import { DeletePopup } from "Explorer/QueryCopilot/Popup/DeletePopup";
|
||||
import { submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities";
|
||||
@@ -44,22 +40,16 @@ import { userContext } from "UserContext";
|
||||
import { queryPagesUntilContentPresent } from "Utils/QueryUtils";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import React, { useRef, useState } from "react";
|
||||
import React, { useState } from "react";
|
||||
import SplitterLayout from "react-splitter-layout";
|
||||
import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
|
||||
import HintIcon from "../../../images/Hint.svg";
|
||||
import CopilotIcon from "../../../images/QueryCopilotNewLogo.svg";
|
||||
import RecentIcon from "../../../images/Recent.svg";
|
||||
import SamplePromptsIcon from "../../../images/SamplePromptsIcon.svg";
|
||||
import XErrorMessage from "../../../images/X-errorMessage.svg";
|
||||
import SaveQueryIcon from "../../../images/save-cosmos.svg";
|
||||
import { useTabs } from "../../hooks/useTabs";
|
||||
|
||||
interface SuggestedPrompt {
|
||||
id: number;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface QueryCopilotTabProps {
|
||||
initialInput: string;
|
||||
explorer: Explorer;
|
||||
@@ -90,19 +80,15 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
const [isGeneratingQuery, setIsGeneratingQuery] = useState<boolean>(false);
|
||||
const [isExecuting, setIsExecuting] = useState<boolean>(false);
|
||||
const [likeQuery, setLikeQuery] = useState<boolean>();
|
||||
const [dislikeQuery, setDislikeQuery] = useState<boolean>();
|
||||
const [showCallout, setShowCallout] = useState<boolean>(false);
|
||||
const [showSamplePrompts, setShowSamplePrompts] = useState<boolean>(false);
|
||||
const [queryIterator, setQueryIterator] = useState<MinimalQueryIterator>();
|
||||
const [queryResults, setQueryResults] = useState<QueryResults>();
|
||||
const [errorMessage, setErrorMessage] = useState<string>("");
|
||||
const [copilotTeachingBubbleVisible, { toggle: toggleCopilotTeachingBubbleVisible }] = useBoolean(false);
|
||||
const inputEdited = useRef(false);
|
||||
const [isSamplePromptsOpen, setIsSamplePromptsOpen] = useState<boolean>(false);
|
||||
const [showDeletePopup, setShowDeletePopup] = useState<boolean>(false);
|
||||
const [showFeedbackBar, setShowFeedbackBar] = useState<boolean>(false);
|
||||
const [showCopyPopup, setshowCopyPopup] = useState<boolean>(false);
|
||||
const [showErrorMessageBar, setShowErrorMessageBar] = useState<boolean>(false);
|
||||
|
||||
const sampleProps: SamplePromptsProps = {
|
||||
isSamplePromptsOpen: isSamplePromptsOpen,
|
||||
@@ -130,41 +116,16 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
const cachedHistoriesString = localStorage.getItem(`${userContext.databaseAccount?.id}-queryCopilotHistories`);
|
||||
const cachedHistories = cachedHistoriesString?.split(",");
|
||||
const [histories, setHistories] = useState<string[]>(cachedHistories || []);
|
||||
const suggestedPrompts: SuggestedPrompt[] = [
|
||||
{ id: 1, text: "Give me all customers whose names start with C" },
|
||||
{ id: 2, text: "Show me all customers" },
|
||||
{ id: 3, text: "Show me all customers who bought a bike in 2019" },
|
||||
];
|
||||
const [filteredHistories, setFilteredHistories] = useState<string[]>(histories);
|
||||
const [filteredSuggestedPrompts, setFilteredSuggestedPrompts] = useState<SuggestedPrompt[]>(suggestedPrompts);
|
||||
|
||||
const handleUserPromptChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
inputEdited.current = true;
|
||||
const { value } = event.target;
|
||||
setUserPrompt(value);
|
||||
|
||||
// Filter history prompts
|
||||
const filteredHistory = histories.filter((history) => history.toLowerCase().includes(value.toLowerCase()));
|
||||
setFilteredHistories(filteredHistory);
|
||||
|
||||
// Filter suggested prompts
|
||||
const filteredSuggested = suggestedPrompts.filter((prompt) =>
|
||||
prompt.text.toLowerCase().includes(value.toLowerCase())
|
||||
);
|
||||
setFilteredSuggestedPrompts(filteredSuggested);
|
||||
};
|
||||
|
||||
const updateHistories = (): void => {
|
||||
const newHistories = histories.length < 3 ? [userPrompt, ...histories] : [userPrompt, histories[1], histories[2]];
|
||||
setHistories(newHistories);
|
||||
localStorage.setItem(`${userContext.databaseAccount.id}-queryCopilotHistories`, newHistories.join(","));
|
||||
};
|
||||
|
||||
const generateSQLQuery = async (): Promise<void> => {
|
||||
try {
|
||||
setIsGeneratingQuery(true);
|
||||
useTabs.getState().setIsTabExecuting(true);
|
||||
useTabs.getState().setIsQueryErrorThrown(false);
|
||||
const payload = {
|
||||
containerSchema: QueryCopilotSampleContainerSchema,
|
||||
userPrompt: userPrompt,
|
||||
@@ -190,8 +151,6 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, "executeNaturalLanguageQuery");
|
||||
useTabs.getState().setIsQueryErrorThrown(true);
|
||||
setShowErrorMessageBar(true);
|
||||
throw error;
|
||||
} finally {
|
||||
setIsGeneratingQuery(false);
|
||||
@@ -200,17 +159,9 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const querySampleDocuments = (query: string, options: FeedOptions): QueryIterator<ItemDefinition & Resource> => {
|
||||
options = getCommonQueryOptions(options);
|
||||
return sampleDataClient()
|
||||
.database(QueryCopilotSampleDatabaseId)
|
||||
.container(QueryCopilotSampleContainerId)
|
||||
.items.query(query, options);
|
||||
};
|
||||
|
||||
const onExecuteQueryClick = async (): Promise<void> => {
|
||||
const queryToExecute = selectedQuery || query;
|
||||
const queryIterator = querySampleDocuments(queryToExecute, {
|
||||
const queryIterator = queryDocuments(QueryCopilotSampleDatabaseId, QueryCopilotSampleContainerId, queryToExecute, {
|
||||
enableCrossPartitionQuery: shouldEnableCrossPartitionKey(),
|
||||
} as FeedOptions);
|
||||
setQueryIterator(queryIterator);
|
||||
@@ -224,7 +175,6 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
try {
|
||||
setIsExecuting(true);
|
||||
useTabs.getState().setIsTabExecuting(true);
|
||||
useTabs.getState().setIsQueryErrorThrown(false);
|
||||
const queryResults: QueryResults = await queryPagesUntilContentPresent(
|
||||
firstItemIndex,
|
||||
async (firstItemIndex: number) =>
|
||||
@@ -237,8 +187,6 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
const errorMessage = getErrorMessage(error);
|
||||
setErrorMessage(errorMessage);
|
||||
handleError(errorMessage, "executeQueryCopilotTab");
|
||||
useTabs.getState().setIsQueryErrorThrown(true);
|
||||
setShowErrorMessageBar(true);
|
||||
} finally {
|
||||
setIsExecuting(false);
|
||||
useTabs.getState().setIsTabExecuting(false);
|
||||
@@ -277,102 +225,48 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
|
||||
return [executeQueryBtn, saveQueryBtn, samplePromptsBtn];
|
||||
};
|
||||
const showTeachingBubble = (): void => {
|
||||
if (!inputEdited.current) {
|
||||
setTimeout(() => {
|
||||
if (!inputEdited.current) {
|
||||
toggleCopilotTeachingBubbleVisible();
|
||||
inputEdited.current = true;
|
||||
}
|
||||
}, 30000);
|
||||
}
|
||||
};
|
||||
|
||||
const resetButtonState = () => {
|
||||
setDislikeQuery(false);
|
||||
setLikeQuery(false);
|
||||
setShowCallout(false);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
useCommandBar.getState().setContextButtons(getCommandbarButtons());
|
||||
}, [query, selectedQuery]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (initialInput) {
|
||||
generateSQLQuery();
|
||||
}
|
||||
showTeachingBubble();
|
||||
useTabs.getState().setIsQueryErrorThrown(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Stack className="tab-pane" style={{ padding: 24, width: "100%", height: "100%" }}>
|
||||
<Stack horizontal verticalAlign="center">
|
||||
<Image src={CopilotIcon} />
|
||||
<Text style={{ marginLeft: 8, fontWeight: 600, fontSize: 16 }}>Copilot</Text>
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="center" style={{ marginTop: 16, width: "100%", position: "relative" }}>
|
||||
<Stack horizontal verticalAlign="center" style={{ marginTop: 16, width: "100%" }}>
|
||||
<TextField
|
||||
id="naturalLanguageInput"
|
||||
value={userPrompt}
|
||||
onChange={handleUserPromptChange}
|
||||
onClick={() => {
|
||||
inputEdited.current = true;
|
||||
setShowSamplePrompts(true);
|
||||
}}
|
||||
onChange={(_, newValue) => setUserPrompt(newValue)}
|
||||
style={{ lineHeight: 30 }}
|
||||
styles={{ root: { width: "95%" } }}
|
||||
disabled={isGeneratingQuery}
|
||||
autoComplete="off"
|
||||
onClick={() => setShowSamplePrompts(true)}
|
||||
/>
|
||||
{copilotTeachingBubbleVisible && (
|
||||
<TeachingBubble
|
||||
calloutProps={{ directionalHint: DirectionalHint.bottomCenter }}
|
||||
target="#naturalLanguageInput"
|
||||
hasCloseButton={true}
|
||||
closeButtonAriaLabel="Close"
|
||||
onDismiss={toggleCopilotTeachingBubbleVisible}
|
||||
hasSmallHeadline={true}
|
||||
headline="Write a prompt"
|
||||
>
|
||||
Write a prompt here and Copilot will generate the query for you. You can also choose from our{" "}
|
||||
<Link
|
||||
onClick={() => {
|
||||
setShowSamplePrompts(true);
|
||||
toggleCopilotTeachingBubbleVisible();
|
||||
}}
|
||||
style={{ color: "white", fontWeight: 600 }}
|
||||
>
|
||||
sample prompts
|
||||
</Link>{" "}
|
||||
or write your own query
|
||||
</TeachingBubble>
|
||||
)}
|
||||
<IconButton
|
||||
iconProps={{ iconName: "Send" }}
|
||||
disabled={isGeneratingQuery || !userPrompt.trim()}
|
||||
disabled={isGeneratingQuery}
|
||||
style={{ marginLeft: 8 }}
|
||||
onClick={() => {
|
||||
updateHistories();
|
||||
generateSQLQuery();
|
||||
resetButtonState();
|
||||
}}
|
||||
/>
|
||||
{isGeneratingQuery && <Spinner style={{ marginLeft: 8 }} />}
|
||||
{showSamplePrompts && (
|
||||
<Callout
|
||||
styles={{ root: { minWidth: 400 } }}
|
||||
style={{ padding: "8px 0" }}
|
||||
target="#naturalLanguageInput"
|
||||
isBeakVisible={false}
|
||||
onDismiss={() => setShowSamplePrompts(false)}
|
||||
directionalHintFixed={true}
|
||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||
alignTargetEdge={true}
|
||||
gapSpace={4}
|
||||
>
|
||||
<Stack>
|
||||
{filteredHistories?.length > 0 && (
|
||||
{histories?.length > 0 && (
|
||||
<Stack>
|
||||
<Text
|
||||
style={{
|
||||
@@ -386,7 +280,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
>
|
||||
Recent
|
||||
</Text>
|
||||
{filteredHistories.map((history, i) => (
|
||||
{histories.map((history, i) => (
|
||||
<DefaultButton
|
||||
key={i}
|
||||
onClick={() => {
|
||||
@@ -413,27 +307,37 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
>
|
||||
Suggested Prompts
|
||||
</Text>
|
||||
{filteredSuggestedPrompts.map((prompt) => (
|
||||
<DefaultButton
|
||||
key={prompt.id}
|
||||
onClick={() => {
|
||||
setUserPrompt(prompt.text);
|
||||
setShowSamplePrompts(false);
|
||||
}}
|
||||
onRenderIcon={() => <Image src={HintIcon} />}
|
||||
styles={promptStyles}
|
||||
>
|
||||
{prompt.text}
|
||||
</DefaultButton>
|
||||
))}
|
||||
<Separator
|
||||
styles={{
|
||||
root: {
|
||||
selectors: { "::before": { background: "#E1DFDD" } },
|
||||
padding: 0,
|
||||
},
|
||||
<DefaultButton
|
||||
onClick={() => {
|
||||
setUserPrompt("Give me all customers whose names start with C");
|
||||
setShowSamplePrompts(false);
|
||||
}}
|
||||
/>
|
||||
onRenderIcon={() => <Image src={HintIcon} />}
|
||||
styles={promptStyles}
|
||||
>
|
||||
Give me all customers whose names start with C
|
||||
</DefaultButton>
|
||||
<DefaultButton
|
||||
onClick={() => {
|
||||
setUserPrompt("Show me all customers");
|
||||
setShowSamplePrompts(false);
|
||||
}}
|
||||
onRenderIcon={() => <Image src={HintIcon} />}
|
||||
styles={promptStyles}
|
||||
>
|
||||
Show me all customers
|
||||
</DefaultButton>
|
||||
<DefaultButton
|
||||
onClick={() => {
|
||||
setUserPrompt("Show me all customers who bought a bike in 2019");
|
||||
setShowSamplePrompts(false);
|
||||
}}
|
||||
onRenderIcon={() => <Image src={HintIcon} />}
|
||||
styles={promptStyles}
|
||||
>
|
||||
Show me all customers who bought a bike in 2019
|
||||
</DefaultButton>
|
||||
<Separator styles={{ root: { selectors: { "::before": { background: "#E1DFDD" } }, padding: 0 } }} />
|
||||
<Text
|
||||
style={{
|
||||
width: "100%",
|
||||
@@ -451,23 +355,14 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
</Callout>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<Text style={{ marginTop: 8, marginBottom: 24, fontSize: 12 }}>
|
||||
AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.{" "}
|
||||
<Link href="" target="_blank">
|
||||
Read preview terms
|
||||
</Link>
|
||||
{showErrorMessageBar && (
|
||||
<Stack style={{ backgroundColor: "#FEF0F1", padding: "4px 8px" }} horizontal verticalAlign="center">
|
||||
<Image src={XErrorMessage} style={{ marginRight: "8px" }} />
|
||||
<Text style={{ fontSize: 12 }}>
|
||||
We ran into an error and were not able to execute query. Please try again after sometime
|
||||
</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</Text>
|
||||
|
||||
{showFeedbackBar && (
|
||||
{showFeedbackBar ? (
|
||||
<Stack style={{ backgroundColor: "#FFF8F0", padding: "2px 8px" }} horizontal verticalAlign="center">
|
||||
<Text style={{ fontWeight: 600, fontSize: 12 }}>Provide feedback on the query generated</Text>
|
||||
{showCallout && !hideFeedbackModalForLikedQueries && (
|
||||
@@ -498,23 +393,17 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
style={{ marginLeft: 20 }}
|
||||
iconProps={{ iconName: likeQuery === true ? "LikeSolid" : "Like" }}
|
||||
onClick={() => {
|
||||
setShowCallout(!likeQuery);
|
||||
setLikeQuery(!likeQuery);
|
||||
if (dislikeQuery) {
|
||||
setDislikeQuery(!dislikeQuery);
|
||||
}
|
||||
setLikeQuery(true);
|
||||
setShowCallout(true);
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
style={{ margin: "0 10px" }}
|
||||
iconProps={{ iconName: dislikeQuery === true ? "DislikeSolid" : "Dislike" }}
|
||||
iconProps={{ iconName: likeQuery === false ? "DislikeSolid" : "Dislike" }}
|
||||
onClick={() => {
|
||||
if (!dislikeQuery) {
|
||||
useQueryCopilot.getState().openFeedbackModal(generatedQuery, false, userPrompt);
|
||||
setLikeQuery(false);
|
||||
}
|
||||
setDislikeQuery(!dislikeQuery);
|
||||
setLikeQuery(false);
|
||||
setShowCallout(false);
|
||||
useQueryCopilot.getState().openFeedbackModal(generatedQuery, false, userPrompt);
|
||||
}}
|
||||
/>
|
||||
<Separator vertical style={{ color: "#EDEBE9" }} />
|
||||
@@ -526,15 +415,15 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
Copy code
|
||||
</CommandBarButton>
|
||||
<CommandBarButton
|
||||
onClick={() => {
|
||||
setShowDeletePopup(true);
|
||||
}}
|
||||
onClick={() => setShowDeletePopup(true)}
|
||||
iconProps={{ iconName: "Delete" }}
|
||||
style={{ margin: "0 10px", backgroundColor: "#FFF8F0", transition: "background-color 0.3s ease" }}
|
||||
>
|
||||
Delete code
|
||||
</CommandBarButton>
|
||||
</Stack>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
<Stack className="tabPaneContentContainer">
|
||||
@@ -558,16 +447,11 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
||||
/>
|
||||
</SplitterLayout>
|
||||
</Stack>
|
||||
<WelcomeModal visible={localStorage.getItem("hideWelcomeModal") !== "true"} />
|
||||
{isSamplePromptsOpen && <SamplePrompts sampleProps={sampleProps} />}
|
||||
{query !== "" && query.trim().length !== 0 && (
|
||||
<DeletePopup
|
||||
showDeletePopup={showDeletePopup}
|
||||
setShowDeletePopup={setShowDeletePopup}
|
||||
setQuery={setQuery}
|
||||
clearFeedback={resetButtonState}
|
||||
showFeedbackBar={setShowFeedbackBar}
|
||||
/>
|
||||
{isSamplePromptsOpen ? <SamplePrompts sampleProps={sampleProps} /> : <></>}
|
||||
{query !== "" && query.trim().length !== 0 ? (
|
||||
<DeletePopup showDeletePopup={showDeletePopup} setShowDeletePopup={setShowDeletePopup} setQuery={setQuery} />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<CopyPopup showCopyPopup={showCopyPopup} setShowCopyPopup={setshowCopyPopup} />
|
||||
</Stack>
|
||||
|
||||
@@ -35,14 +35,12 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
|
||||
style={
|
||||
Object {
|
||||
"marginTop": 16,
|
||||
"position": "relative",
|
||||
"width": "100%",
|
||||
}
|
||||
}
|
||||
verticalAlign="center"
|
||||
>
|
||||
<StyledTextFieldBase
|
||||
autoComplete="off"
|
||||
disabled={false}
|
||||
id="naturalLanguageInput"
|
||||
onChange={[Function]}
|
||||
@@ -126,9 +124,6 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
|
||||
/>
|
||||
</t>
|
||||
</Stack>
|
||||
<WelcomeModal
|
||||
visible={true}
|
||||
/>
|
||||
<CopyPopup
|
||||
setShowCopyPopup={[Function]}
|
||||
showCopyPopup={false}
|
||||
|
||||
@@ -32,7 +32,7 @@ export const QuickstartTab: React.FC<QuickstartTabProps> = ({ explorer }: Quicks
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path: firewallRulesUri,
|
||||
method: "GET",
|
||||
apiVersion: "2022-11-08",
|
||||
apiVersion: "2020-10-05-privatepreview",
|
||||
});
|
||||
const firewallRules: PostgresFirewallRule[] = response?.data?.value || response?.value || [];
|
||||
const isEnabled = firewallRules.some(
|
||||
|
||||
@@ -14,7 +14,6 @@ import ko from "knockout";
|
||||
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
|
||||
import errorIcon from "../../../images/close-black.svg";
|
||||
import errorQuery from "../../../images/error_no_outline.svg";
|
||||
import { useObservable } from "../../hooks/useObservable";
|
||||
import { ReactTabKind, useTabs } from "../../hooks/useTabs";
|
||||
import TabsBase from "./TabsBase";
|
||||
@@ -117,14 +116,6 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
|
||||
{isTabExecuting(tab, tabKind) && (
|
||||
<img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" />
|
||||
)}
|
||||
{isQueryErrorThrown(tab, tabKind) && (
|
||||
<img
|
||||
src={errorQuery}
|
||||
title="Error"
|
||||
alt="Error"
|
||||
style={{ marginTop: 4, marginLeft: 4, width: 10, height: 11 }}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
<span className="tabNavText">{useObservable(tab?.tabTitle || getReactTabTitle())}</span>
|
||||
{tabKind !== ReactTabKind.Home && (
|
||||
@@ -229,19 +220,6 @@ const isTabExecuting = (tab?: Tab, tabKind?: ReactTabKind): boolean => {
|
||||
return false;
|
||||
};
|
||||
|
||||
const isQueryErrorThrown = (tab?: Tab, tabKind?: ReactTabKind): boolean => {
|
||||
if (
|
||||
!tab?.isExecuting &&
|
||||
tabKind !== undefined &&
|
||||
tabKind !== ReactTabKind.Home &&
|
||||
useTabs.getState()?.isQueryErrorThrown &&
|
||||
!useTabs.getState()?.isTabExecuting
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
|
||||
switch (activeReactTab) {
|
||||
case ReactTabKind.Connect:
|
||||
|
||||
@@ -134,7 +134,7 @@ export default class TerminalTab extends TabsBase {
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path: firewallRulesUri,
|
||||
method: "GET",
|
||||
apiVersion: "2022-11-08",
|
||||
apiVersion: "2020-10-05-privatepreview",
|
||||
});
|
||||
const firewallRules: DataModels.PostgresFirewallRule[] = response?.data?.value || response?.value || [];
|
||||
const isEnabled = firewallRules.some(
|
||||
|
||||
@@ -790,11 +790,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
||||
{!isNotebookEnabled && isSampleDataEnabled && (
|
||||
<>
|
||||
<AccordionComponent>
|
||||
<AccordionItemComponent
|
||||
title={"MY DATA"}
|
||||
isExpanded={!gitHubNotebooksContentRoot}
|
||||
styles={{ maxHeight: 230 }}
|
||||
>
|
||||
<AccordionItemComponent title={"MY DATA"} isExpanded={!gitHubNotebooksContentRoot}>
|
||||
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
||||
</AccordionItemComponent>
|
||||
<AccordionItemComponent title={"SAMPLE DATA"}>
|
||||
@@ -808,11 +804,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
||||
{isNotebookEnabled && isSampleDataEnabled && (
|
||||
<>
|
||||
<AccordionComponent>
|
||||
<AccordionItemComponent
|
||||
title={"MY DATA"}
|
||||
isExpanded={!gitHubNotebooksContentRoot}
|
||||
styles={{ maxHeight: 130 }}
|
||||
>
|
||||
<AccordionItemComponent title={"MY DATA"} isExpanded={!gitHubNotebooksContentRoot}>
|
||||
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
||||
</AccordionItemComponent>
|
||||
<AccordionItemComponent title={"SAMPLE DATA"}>
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { useCommandBar } from "Explorer/Menus/CommandBar/CommandBarComponentAdapter";
|
||||
import TabsBase from "Explorer/Tabs/TabsBase";
|
||||
import { useSelectedNode } from "Explorer/useSelectedNode";
|
||||
import { useTabs } from "hooks/useTabs";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
|
||||
import CollectionIcon from "../../../images/tree-collection.svg";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import * as ResourceTreeContextMenuButtonFactory from "../ContextMenuButtonFactory";
|
||||
import { TreeComponent, TreeNode } from "../Controls/TreeComponent/TreeComponent";
|
||||
|
||||
export const SampleDataTree = ({
|
||||
@@ -20,34 +15,14 @@ export const SampleDataTree = ({
|
||||
if (sampleDataResourceTokenCollection) {
|
||||
const updatedSampleTree: TreeNode = {
|
||||
label: sampleDataResourceTokenCollection.databaseId,
|
||||
isExpanded: false,
|
||||
isExpanded: true,
|
||||
iconSrc: CosmosDBIcon,
|
||||
className: "databaseHeader",
|
||||
children: [
|
||||
{
|
||||
label: sampleDataResourceTokenCollection.id(),
|
||||
iconSrc: CollectionIcon,
|
||||
isExpanded: false,
|
||||
className: "dataResourceTree",
|
||||
contextMenu: ResourceTreeContextMenuButtonFactory.createSampleCollectionContextMenuButton(),
|
||||
onClick: () => {
|
||||
// Rewritten version of expandCollapseCollection
|
||||
useSelectedNode.getState().setSelectedNode(sampleDataResourceTokenCollection);
|
||||
useCommandBar.getState().setContextButtons([]);
|
||||
useTabs().refreshActiveTab(
|
||||
(tab: TabsBase) =>
|
||||
tab.collection?.id() === sampleDataResourceTokenCollection.id() &&
|
||||
tab.collection.databaseId === sampleDataResourceTokenCollection.databaseId
|
||||
);
|
||||
},
|
||||
isSelected: () =>
|
||||
useSelectedNode
|
||||
.getState()
|
||||
.isDataNodeSelected(
|
||||
sampleDataResourceTokenCollection.databaseId,
|
||||
sampleDataResourceTokenCollection.id()
|
||||
),
|
||||
onContextMenuOpen: () => useSelectedNode.getState().setSelectedNode(sampleDataResourceTokenCollection),
|
||||
isExpanded: true,
|
||||
className: "collectionHeader",
|
||||
children: [
|
||||
{
|
||||
label: "Items",
|
||||
@@ -60,5 +35,7 @@ export const SampleDataTree = ({
|
||||
}
|
||||
}, [sampleDataResourceTokenCollection]);
|
||||
|
||||
return <TreeComponent className="dataResourceTree" rootNode={root || { label: "Sample data not initialized." }} />;
|
||||
return (
|
||||
<TreeComponent className="sampleDataResourceTree" rootNode={root || { label: "Sample data not initialized." }} />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { ConnectionStatusType, QueryCopilotSampleContainerId, QueryCopilotSampleDatabaseId } from "Common/Constants";
|
||||
import { ConnectionStatusType } from "Common/Constants";
|
||||
import { useNotebook } from "Explorer/Notebook/useNotebook";
|
||||
import create, { UseStore } from "zustand";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { useTabs } from "../hooks/useTabs";
|
||||
|
||||
export interface SelectedNodeState {
|
||||
selectedNode: ViewModels.TreeNode;
|
||||
setSelectedNode: (node: ViewModels.TreeNode) => void;
|
||||
@@ -14,7 +15,6 @@ export interface SelectedNodeState {
|
||||
subnodeKinds?: ViewModels.CollectionTabKind[]
|
||||
) => boolean;
|
||||
isConnectedToContainer: () => boolean;
|
||||
isQueryCopilotCollectionSelected: () => boolean;
|
||||
}
|
||||
|
||||
export const useSelectedNode: UseStore<SelectedNodeState> = create((set, get) => ({
|
||||
@@ -65,15 +65,4 @@ export const useSelectedNode: UseStore<SelectedNodeState> = create((set, get) =>
|
||||
isConnectedToContainer: (): boolean => {
|
||||
return useNotebook.getState().connectionInfo?.status === ConnectionStatusType.Connected;
|
||||
},
|
||||
isQueryCopilotCollectionSelected: (): boolean => {
|
||||
const selectedNode = get().selectedNode;
|
||||
if (
|
||||
selectedNode &&
|
||||
selectedNode.id() === QueryCopilotSampleContainerId &&
|
||||
(selectedNode as ViewModels.Collection)?.databaseId === QueryCopilotSampleDatabaseId
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -18,7 +18,6 @@ import "../externals/jquery.typeahead.min.js";
|
||||
// Image Dependencies
|
||||
import { QueryCopilotCarousel } from "Explorer/QueryCopilot/CopilotCarousel";
|
||||
import { QueryCopilotFeedbackModal } from "Explorer/QueryCopilot/QueryCopilotFeedbackModal";
|
||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import "../images/CosmosDB_rgb_ui_lighttheme.ico";
|
||||
import hdeConnectImage from "../images/HdeConnectCosmosDB.svg";
|
||||
import "../images/favicon.ico";
|
||||
@@ -63,8 +62,7 @@ initializeIcons();
|
||||
const App: React.FunctionComponent = () => {
|
||||
const [isLeftPaneExpanded, setIsLeftPaneExpanded] = useState<boolean>(true);
|
||||
const isCarouselOpen = useCarousel((state) => state.shouldOpen);
|
||||
// const isCopilotCarouselOpen = useCarousel((state) => state.showCopilotCarousel);
|
||||
const shouldShowModal = useQueryCopilot((state) => state.showFeedbackModal);
|
||||
const isCopilotCarouselOpen = useCarousel((state) => state.showCopilotCarousel);
|
||||
|
||||
const config = useConfig();
|
||||
const explorer = useKnockoutExplorer(config?.platform);
|
||||
@@ -127,8 +125,8 @@ const App: React.FunctionComponent = () => {
|
||||
{<QuickstartCarousel isOpen={isCarouselOpen} />}
|
||||
{<SQLQuickstartTutorial />}
|
||||
{<MongoQuickstartTutorial />}
|
||||
{<QueryCopilotCarousel isOpen={true} explorer={explorer} />}
|
||||
{shouldShowModal && <QueryCopilotFeedbackModal />}
|
||||
{<QueryCopilotCarousel isOpen={isCopilotCarouselOpen} explorer={explorer} />}
|
||||
{<QueryCopilotFeedbackModal />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -47,10 +47,6 @@ export class JupyterLabAppFactory {
|
||||
}
|
||||
|
||||
public async createTerminalApp(serverSettings: ServerConnection.ISettings): Promise<ITerminalConnection | undefined> {
|
||||
//Need to add this after we remove passing token through url
|
||||
//const configurationSettings: Partial<ServerConnection.ISettings> = serverSettings;
|
||||
//(configurationSettings.appendToken as boolean) = false;
|
||||
//serverSettings = ServerConnection.makeSettings(configurationSettings);
|
||||
const manager = new TerminalManager({
|
||||
serverSettings: serverSettings,
|
||||
});
|
||||
@@ -68,11 +64,6 @@ export class JupyterLabAppFactory {
|
||||
}
|
||||
}, this);
|
||||
|
||||
let internalSend = session.send;
|
||||
session.send = (message: IMessage) => {
|
||||
message?.content?.push(serverSettings?.token);
|
||||
internalSend.call(session, message);
|
||||
};
|
||||
const term = new Terminal(session, { theme: "dark", shutdownOnClose: true });
|
||||
|
||||
if (!term) {
|
||||
|
||||
@@ -18,10 +18,7 @@ export const getNetworkSettingsWarningMessage = (): string => {
|
||||
}
|
||||
|
||||
// public network access is disabled
|
||||
if (
|
||||
accountProperties.publicNetworkAccess !== "Enabled" &&
|
||||
accountProperties.publicNetworkAccess !== "SecuredByPerimeter"
|
||||
) {
|
||||
if (accountProperties.publicNetworkAccess !== "Enabled") {
|
||||
return "The Network settings for this account are preventing access from Data Explorer. Please enable public access to proceed.";
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,3 @@ export const getFullName = (): string => {
|
||||
const { name } = decryptJWTToken(authorizationToken);
|
||||
return name;
|
||||
};
|
||||
|
||||
export const getUserEmail = (): string => {
|
||||
const { authorizationToken } = userContext;
|
||||
const { upn } = decryptJWTToken(authorizationToken);
|
||||
return upn;
|
||||
};
|
||||
|
||||
@@ -62,6 +62,10 @@ export function useKnockoutExplorer(platform: Platform): Explorer {
|
||||
setExplorer(explorer);
|
||||
}
|
||||
}
|
||||
|
||||
if (userContext.features.enableCopilot) {
|
||||
await updateContextForSampleData();
|
||||
}
|
||||
};
|
||||
effect();
|
||||
}, [platform]);
|
||||
@@ -69,9 +73,6 @@ export function useKnockoutExplorer(platform: Platform): Explorer {
|
||||
useEffect(() => {
|
||||
if (explorer) {
|
||||
applyExplorerBindings(explorer);
|
||||
if (userContext.features.enableCopilot) {
|
||||
updateContextForSampleData(explorer);
|
||||
}
|
||||
}
|
||||
}, [explorer]);
|
||||
|
||||
@@ -414,7 +415,7 @@ interface PortalMessage {
|
||||
inputs?: DataExplorerInputsFrame;
|
||||
}
|
||||
|
||||
async function updateContextForSampleData(explorer: Explorer): Promise<void> {
|
||||
async function updateContextForSampleData(): Promise<void> {
|
||||
if (!userContext.features.enableCopilot) {
|
||||
return;
|
||||
}
|
||||
@@ -434,8 +435,6 @@ async function updateContextForSampleData(explorer: Explorer): Promise<void> {
|
||||
const data: SampledataconnectionResponse = await response.json();
|
||||
const sampleDataConnectionInfo = parseResourceTokenConnectionString(data.connectionString);
|
||||
updateUserContext({ sampleDataConnectionInfo });
|
||||
|
||||
await explorer.refreshSampleData();
|
||||
}
|
||||
|
||||
interface SampledataconnectionResponse {
|
||||
|
||||
@@ -5,26 +5,21 @@ export interface NotificationConsoleState {
|
||||
isExpanded: boolean;
|
||||
inProgressConsoleDataIdToBeDeleted: string;
|
||||
consoleData: ConsoleData | undefined;
|
||||
consoleAnimationFinished: boolean;
|
||||
expandConsole: () => void;
|
||||
// TODO Remove this method. Add a `closeConsole` method instead
|
||||
setIsExpanded: (isExpanded: boolean) => void;
|
||||
// TODO These two methods badly need a refactor. Not very react friendly.
|
||||
setNotificationConsoleData: (consoleData: ConsoleData) => void;
|
||||
setInProgressConsoleDataIdToBeDeleted: (id: string) => void;
|
||||
setConsoleAnimationFinished: (consoleAnimationFinished: boolean) => void;
|
||||
}
|
||||
|
||||
export const useNotificationConsole: UseStore<NotificationConsoleState> = create((set) => ({
|
||||
isExpanded: false,
|
||||
consoleData: undefined,
|
||||
inProgressConsoleDataIdToBeDeleted: "",
|
||||
consoleAnimationFinished: false,
|
||||
expandConsole: () => set((state) => ({ ...state, isExpanded: true })),
|
||||
setIsExpanded: (isExpanded) => set((state) => ({ ...state, isExpanded })),
|
||||
setNotificationConsoleData: (consoleData: ConsoleData) => set((state) => ({ ...state, consoleData })),
|
||||
setInProgressConsoleDataIdToBeDeleted: (id: string) =>
|
||||
set((state) => ({ ...state, inProgressConsoleDataIdToBeDeleted: id })),
|
||||
setConsoleAnimationFinished: (consoleAnimationFinished: boolean) =>
|
||||
set({ consoleAnimationFinished: consoleAnimationFinished }),
|
||||
}));
|
||||
|
||||
@@ -12,7 +12,6 @@ interface TabsState {
|
||||
networkSettingsWarning: string;
|
||||
queryCopilotTabInitialInput: string;
|
||||
isTabExecuting: boolean;
|
||||
isQueryErrorThrown: boolean;
|
||||
activateTab: (tab: TabsBase) => void;
|
||||
activateNewTab: (tab: TabsBase) => void;
|
||||
activateReactTab: (tabkind: ReactTabKind) => void;
|
||||
@@ -27,7 +26,6 @@ interface TabsState {
|
||||
setNetworkSettingsWarning: (warningMessage: string) => void;
|
||||
setQueryCopilotTabInitialInput: (input: string) => void;
|
||||
setIsTabExecuting: (state: boolean) => void;
|
||||
setIsQueryErrorThrown: (state: boolean) => void;
|
||||
}
|
||||
|
||||
export enum ReactTabKind {
|
||||
@@ -45,7 +43,6 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
networkSettingsWarning: "",
|
||||
queryCopilotTabInitialInput: "",
|
||||
isTabExecuting: false,
|
||||
isQueryErrorThrown: false,
|
||||
activateTab: (tab: TabsBase): void => {
|
||||
if (get().openedTabs.some((openedTab) => openedTab.tabId === tab.tabId)) {
|
||||
set({ activeTab: tab, activeReactTab: undefined });
|
||||
@@ -160,7 +157,4 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
setIsTabExecuting: (state: boolean) => {
|
||||
set({ isTabExecuting: state });
|
||||
},
|
||||
setIsQueryErrorThrown: (state: boolean) => {
|
||||
set({ isQueryErrorThrown: state });
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -39,7 +39,7 @@ test("Resource token", async () => {
|
||||
await page.type("input[class='inputToken']", resourceTokenConnectionString);
|
||||
await page.click("input[value='Connect']");
|
||||
await page.waitForSelector("iframe");
|
||||
const explorer = await page.frame({
|
||||
const explorer = page.frame({
|
||||
name: "explorer",
|
||||
});
|
||||
await explorer.textContent(`css=.dataResourceTree >> "${collectionId}"`);
|
||||
|
||||
Reference in New Issue
Block a user