Compare commits

..

8 Commits

Author SHA1 Message Date
dependabot[bot]
868844d6de Bump eslint-plugin-react-hooks from 4.2.0 to 4.6.0
Bumps [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/HEAD/packages/eslint-plugin-react-hooks) from 4.2.0 to 4.6.0.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/HEAD/packages/eslint-plugin-react-hooks)

---
updated-dependencies:
- dependency-name: eslint-plugin-react-hooks
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-10 22:38:10 +00:00
Predrag Klepic
9f7783f3f9 [Query Copilot] Revise Copilot UI texts (#1569)
* Revise Copilot UI texts

* Test snapshots updated

---------

Co-authored-by: Predrag Klepic <v-prklepic@microsoft.com>
2023-08-09 21:43:55 +02:00
sindhuba
daa26d289b Fix sendMessage in DE (#1570)
* Fix issue in sendMessage in DE

* Run npm format
2023-08-09 09:28:25 -07:00
sindhuba
879cb08949 Fix issue with feature flag (#1567) 2023-08-08 08:03:42 -07:00
sindhuba
92f43c28a7 Add logic in DE to show NPS Survey (#1565)
* Send messages from DE to Portal to display NPS Survey

* Address comments
2023-08-04 13:24:30 -07:00
bogercraig
5f0c7bcea2 Users/bogercraig/endpointvalidation (#1554)
* Adding example endpoint with trailing forward slash.

* Move backend and ARM endpoint validation to configContext for initialization from config.json.

* Added debugging script and attempts to relocate endpoint validation list.

* Move default endpoint list to endpoint validation code and allow falling back to the default list during unit tests if configContext is not initialized.

* Remove leftover debugger statements.

* Remove test debug script in package.json for debugging unit tests in browser.

* Run prettier on modified files.

* Overwriting with package.json from master.

* Overwriting with version from master.

* Remove test ARM endpoint.

* Replace ternary operator with || for more concise arguments per Victor's feedback.

---------

Co-authored-by: Craig Boger <craig.boger@microsoft.com>
2023-08-03 14:47:50 -04:00
Predrag Klepic
fa55d528ad [Query Copilot] Maintain Query Copilot state when switching tabs (#1559)
* Sample implementation for saving states

* Maintaining Query Copilot state

* Fixing failed PR checks

* Additional changes based on checks

* snapshots updated

* Changes based on merging previous PR

* test mock changed

* Fixing minor bug for close button

* Destruct of queryCopilotState

* passing only function in Tabs component

* Maintaining copilot state with zustand store

* additional test changes

* test snapshot updated

---------

Co-authored-by: Predrag Klepic <v-prklepic@microsoft.com>
2023-08-03 09:23:31 +02:00
Predrag Klepic
c873fed7aa Disable Query Copilot Tab flickering (#1564)
Co-authored-by: Predrag Klepic <v-prklepic@microsoft.com>
2023-08-02 17:37:37 +02:00
18 changed files with 5292 additions and 2849 deletions

7780
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -148,7 +148,7 @@
"eslint-cli": "1.1.1",
"eslint-plugin-no-null": "1.0.2",
"eslint-plugin-prefer-arrow": "1.2.2",
"eslint-plugin-react-hooks": "4.2.0",
"eslint-plugin-react-hooks": "4.6.0",
"expect-playwright": "0.3.3",
"fast-glob": "3.2.5",
"file-loader": "2.0.0",

View File

@@ -1,14 +1,14 @@
import {
allowedAadEndpoints,
allowedArcadiaEndpoints,
allowedArmEndpoints,
allowedBackendEndpoints,
allowedEmulatorEndpoints,
allowedGraphEndpoints,
allowedHostedExplorerEndpoints,
allowedJunoOrigins,
allowedMongoBackendEndpoints,
allowedMsalRedirectEndpoints,
defaultAllowedArmEndpoints,
defaultAllowedBackendEndpoints,
validateEndpoint,
} from "Utils/EndpointValidation";
@@ -20,6 +20,8 @@ export enum Platform {
export interface ConfigContext {
platform: Platform;
allowedArmEndpoints: ReadonlyArray<string>;
allowedBackendEndpoints: ReadonlyArray<string>;
allowedParentFrameOrigins: ReadonlyArray<string>;
gitSha?: string;
proxyPath?: string;
@@ -49,6 +51,8 @@ export interface ConfigContext {
// Default configuration
let configContext: Readonly<ConfigContext> = {
platform: Platform.Portal,
allowedArmEndpoints: defaultAllowedArmEndpoints,
allowedBackendEndpoints: defaultAllowedBackendEndpoints,
allowedParentFrameOrigins: [
`^https:\\/\\/cosmos\\.azure\\.(com|cn|us)$`,
`^https:\\/\\/[\\.\\w]*portal\\.azure\\.(com|cn|us)$`,
@@ -77,7 +81,7 @@ let configContext: Readonly<ConfigContext> = {
export function resetConfigContext(): void {
if (process.env.NODE_ENV !== "test") {
throw new Error("resetConfigContext can only becalled in a test environment");
throw new Error("resetConfigContext can only be called in a test environment");
}
configContext = {} as ConfigContext;
}
@@ -87,7 +91,7 @@ export function updateConfigContext(newContext: Partial<ConfigContext>): void {
return;
}
if (!validateEndpoint(newContext.ARM_ENDPOINT, allowedArmEndpoints)) {
if (!validateEndpoint(newContext.ARM_ENDPOINT, configContext.allowedArmEndpoints || defaultAllowedArmEndpoints)) {
delete newContext.ARM_ENDPOINT;
}
@@ -107,7 +111,12 @@ export function updateConfigContext(newContext: Partial<ConfigContext>): void {
delete newContext.ARCADIA_ENDPOINT;
}
if (!validateEndpoint(newContext.BACKEND_ENDPOINT, allowedBackendEndpoints)) {
if (
!validateEndpoint(
newContext.BACKEND_ENDPOINT,
configContext.allowedBackendEndpoints || defaultAllowedBackendEndpoints
)
) {
delete newContext.BACKEND_ENDPOINT;
}
@@ -130,7 +139,7 @@ export function updateConfigContext(newContext: Partial<ConfigContext>): void {
Object.assign(configContext, newContext);
}
// Injected for local develpment. These will be removed in the production bundle by webpack
// Injected for local development. These will be removed in the production bundle by webpack
if (process.env.NODE_ENV === "development") {
const port: string = process.env.PORT || "1234";
updateConfigContext({

View File

@@ -1,5 +1,8 @@
import { Link } from "@fluentui/react/lib/Link";
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
import { sendMessage } from "Common/MessageHandler";
import { Platform } from "ConfigContext";
import { MessageTypes } from "Contracts/ExplorerContracts";
import { IGalleryItem } from "Juno/JunoClient";
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointValidation";
import * as ko from "knockout";
@@ -23,7 +26,7 @@ import { PhoenixClient } from "../Phoenix/PhoenixClient";
import * as ExplorerSettings from "../Shared/ExplorerSettings";
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../UserContext";
import { isAccountNewerThanThresholdInMs, userContext } from "../UserContext";
import { getCollectionName, getUploadName } from "../Utils/APITypeUtils";
import { stringToBlob } from "../Utils/BlobUtils";
import { isCapabilityEnabled } from "../Utils/CapabilityUtils";
@@ -258,6 +261,45 @@ export default class Explorer {
// TODO: return result
}
private getRandomInt(max: number) {
return Math.floor(Math.random() * max);
}
public openNPSSurveyDialog(): void {
if (!Platform.Portal) {
return;
}
const NINETY_DAYS_IN_MS = 7776000000;
const ONE_DAY_IN_MS = 86400000;
const isAccountNewerThanNinetyDays = isAccountNewerThanThresholdInMs(
userContext.databaseAccount?.systemData?.createdAt || "",
NINETY_DAYS_IN_MS
);
// Try Cosmos DB subscription - survey shown to random 25% of users at day 1 in Data Explorer.
if (userContext.isTryCosmosDBSubscription) {
if (
isAccountNewerThanThresholdInMs(userContext.databaseAccount?.systemData?.createdAt || "", ONE_DAY_IN_MS) &&
this.getRandomInt(100) < 25
) {
sendMessage({ type: MessageTypes.DisplayNPSSurvey });
}
} else {
// An existing account is lesser than 90 days old. For existing account show to random 10 % of users in Data Explorer.
if (isAccountNewerThanNinetyDays) {
if (this.getRandomInt(100) < 10) {
sendMessage({ type: MessageTypes.DisplayNPSSurvey });
}
} else {
// An existing account is greater than 90 days. For existing account show to random 25 % of users in Data Explorer.
if (this.getRandomInt(100) < 25) {
sendMessage({ type: MessageTypes.DisplayNPSSurvey });
}
}
}
}
public async refreshDatabaseForResourceToken(): Promise<void> {
const databaseId = userContext.parsedResourceToken?.databaseId;
const collectionId = userContext.parsedResourceToken?.collectionId;

View File

@@ -1425,6 +1425,10 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
this.setState({ isExecuting: false });
TelemetryProcessor.traceSuccess(Action.CreateCollection, telemetryData, startKey);
useSidePanel.getState().closeSidePanel();
// open NPS Survey Dialog once the collection is created
if (userContext.features.enableNPSSurvey) {
this.props.explorer.openNPSSurveyDialog();
}
} catch (error) {
const errorMessage: string = getErrorMessage(error);
this.setState({ isExecuting: false, errorMessage, showErrorDetails: true });

View File

@@ -78,11 +78,13 @@ export const QueryCopilotFeedbackModal: React.FC = (): JSX.Element => {
}}
></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
organization will be able to view and manage your feedback data.{" "}
<Link href="https://privacy.microsoft.com/privacystatement" target="_blank">
Privacy statement
</Link>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the{" "}
{
<Link href="https://privacy.microsoft.com/privacystatement" target="_blank">
Privacy statement
</Link>
}{" "}
for more information.
</Text>
{likeQuery && (
<Checkbox

View File

@@ -42,8 +42,8 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
</Stack>
</Stack>
<Stack horizontalAlign="center">
<Stack.Item align="center">
<Text className="title bold">Welcome to Copilot in CosmosDB</Text>
<Stack.Item align="center" style={{ textAlign: "center" }}>
<Text className="title bold">Welcome to Query Copilot for Azure Cosmos DB (Private Preview)</Text>
</Stack.Item>
<Stack.Item align="center" className="text">
<Stack horizontal>
@@ -52,7 +52,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
</StackItem>
<StackItem align="start">
<Text className="bold">
Let copilot do the work for you
Let Query Copilot do the work for you
<br />
</Text>
</StackItem>
@@ -88,13 +88,14 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
</StackItem>
<StackItem align="start">
<Text className="bold">
Copilot currently works only a sample database
Query Copilot works on a sample database.
<br />
</Text>
</StackItem>
</Stack>
<Text>
Copilot is setup on a sample database we have configured for you at no cost
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you
at no cost.
<br />
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
</Text>

View File

@@ -118,7 +118,7 @@ exports[`Query Copilot Feedback Modal snapshot test shoud render and match snaps
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -126,6 +126,8 @@ exports[`Query Copilot Feedback Modal snapshot test shoud render and match snaps
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -271,7 +273,7 @@ exports[`Query Copilot Feedback Modal snapshot test should cancel submission 1`]
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -279,6 +281,8 @@ exports[`Query Copilot Feedback Modal snapshot test should cancel submission 1`]
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -424,7 +428,7 @@ exports[`Query Copilot Feedback Modal snapshot test should close on cancel click
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -432,6 +436,8 @@ exports[`Query Copilot Feedback Modal snapshot test should close on cancel click
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -577,7 +583,7 @@ exports[`Query Copilot Feedback Modal snapshot test should get user unput 1`] =
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -585,6 +591,8 @@ exports[`Query Copilot Feedback Modal snapshot test should get user unput 1`] =
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -730,7 +738,7 @@ exports[`Query Copilot Feedback Modal snapshot test should not render dont show
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -738,6 +746,8 @@ exports[`Query Copilot Feedback Modal snapshot test should not render dont show
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -883,7 +893,7 @@ exports[`Query Copilot Feedback Modal snapshot test should record user contact c
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -891,6 +901,8 @@ exports[`Query Copilot Feedback Modal snapshot test should record user contact c
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -1036,7 +1048,7 @@ exports[`Query Copilot Feedback Modal snapshot test should record user contact c
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -1044,6 +1056,8 @@ exports[`Query Copilot Feedback Modal snapshot test should record user contact c
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -1189,7 +1203,7 @@ exports[`Query Copilot Feedback Modal snapshot test should render dont show agai
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -1197,6 +1211,8 @@ exports[`Query Copilot Feedback Modal snapshot test should render dont show agai
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<StyledCheckboxBase
checked={true}
@@ -1357,7 +1373,7 @@ exports[`Query Copilot Feedback Modal snapshot test should submit submission 1`]
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -1365,6 +1381,8 @@ exports[`Query Copilot Feedback Modal snapshot test should submit submission 1`]
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}

View File

@@ -60,11 +60,16 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
>
<StackItem
align="center"
style={
Object {
"textAlign": "center",
}
}
>
<Text
className="title bold"
>
Welcome to Copilot in CosmosDB
Welcome to Query Copilot for Azure Cosmos DB (Private Preview)
</Text>
</StackItem>
<StackItem
@@ -88,7 +93,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
<Text
className="bold"
>
Let copilot do the work for you
Let Query Copilot do the work for you
<br />
</Text>
</StackItem>
@@ -160,13 +165,13 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
<Text
className="bold"
>
Copilot currently works only a sample database
Query Copilot works on a sample database.
<br />
</Text>
</StackItem>
</Stack>
<Text>
Copilot is setup on a sample database we have configured for you at no cost
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you at no cost.
<br />
<StyledLinkBase
href="http://aka.ms/cdb-copilot-learn-more"

View File

@@ -5,9 +5,7 @@ import { QueryCopilotTab } from "./QueryCopilotTab";
describe("Query copilot tab snapshot test", () => {
it("should render with initial input", () => {
const wrapper = shallow(
<QueryCopilotTab initialInput="Write a query to return all records in this table" explorer={new Explorer()} />
);
const wrapper = shallow(<QueryCopilotTab explorer={new Explorer()} />);
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -17,7 +17,7 @@ import {
TextField,
} from "@fluentui/react";
import { useBoolean } from "@fluentui/react-hooks";
import { JunoEndpoints, QueryCopilotSampleContainerId, QueryCopilotSampleContainerSchema } from "Common/Constants";
import { QueryCopilotSampleContainerId, QueryCopilotSampleContainerSchema } from "Common/Constants";
import { getErrorMessage, handleError } from "Common/ErrorHandlingUtils";
import { shouldEnableCrossPartitionKey } from "Common/HeadersUtility";
import { MinimalQueryIterator } from "Common/IteratorUtilities";
@@ -56,7 +56,6 @@ interface SuggestedPrompt {
}
interface QueryCopilotTabProps {
initialInput: string;
explorer: Explorer;
}
@@ -73,32 +72,50 @@ const promptStyles: IButtonStyles = {
label: { fontWeight: 400, textAlign: "left", paddingLeft: 8 },
};
export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
initialInput,
explorer,
}: QueryCopilotTabProps): JSX.Element => {
const hideFeedbackModalForLikedQueries = useQueryCopilot((state) => state.hideFeedbackModalForLikedQueries);
const [userPrompt, setUserPrompt] = useState<string>(initialInput || "");
const [generatedQuery, setGeneratedQuery] = useState<string>("");
const [generatedQueryComments, setGeneratedQueryComments] = useState<string>("");
const [query, setQuery] = useState<string>("");
const [selectedQuery, setSelectedQuery] = useState<string>("");
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>("");
export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({ explorer }: QueryCopilotTabProps): JSX.Element => {
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 {
hideFeedbackModalForLikedQueries,
userPrompt,
setUserPrompt,
generatedQuery,
setGeneratedQuery,
query,
setQuery,
selectedQuery,
setSelectedQuery,
isGeneratingQuery,
setIsGeneratingQuery,
isExecuting,
setIsExecuting,
likeQuery,
setLikeQuery,
dislikeQuery,
setDislikeQuery,
showCallout,
setShowCallout,
showSamplePrompts,
setShowSamplePrompts,
queryIterator,
setQueryIterator,
queryResults,
setQueryResults,
errorMessage,
setErrorMessage,
isSamplePromptsOpen,
setIsSamplePromptsOpen,
showDeletePopup,
setShowDeletePopup,
showFeedbackBar,
setShowFeedbackBar,
showCopyPopup,
setshowCopyPopup,
showErrorMessageBar,
setShowErrorMessageBar,
generatedQueryComments,
setGeneratedQueryComments,
} = useQueryCopilot();
const sampleProps: SamplePromptsProps = {
isSamplePromptsOpen: isSamplePromptsOpen,
@@ -174,7 +191,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
};
setShowDeletePopup(false);
useQueryCopilot.getState().refreshCorrelationId();
const response = await fetch(`${JunoEndpoints.Prod}/generateSQLQuery`, {
const response = await fetch("https://copilotorchestrater.azurewebsites.net/generateSQLQuery", {
method: "POST",
headers: {
"content-type": "application/json",
@@ -301,9 +318,10 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
return [executeQueryBtn, saveQueryBtn];
};
const showTeachingBubble = (): void => {
if (!inputEdited.current) {
const shouldShowTeachingBubble = !inputEdited.current && userPrompt.trim() === "";
if (shouldShowTeachingBubble) {
setTimeout(() => {
if (!inputEdited.current) {
if (shouldShowTeachingBubble) {
toggleCopilotTeachingBubbleVisible();
inputEdited.current = true;
}
@@ -328,16 +346,13 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
}, [query, selectedQuery]);
React.useEffect(() => {
if (initialInput) {
generateSQLQuery();
}
showTeachingBubble();
useTabs.getState().setIsQueryErrorThrown(false);
}, []);
return (
<Stack className="tab-pane" style={{ padding: 24, width: "100%" }}>
<div style={{ overflowY: "auto", height: "100%" }}>
<div style={isGeneratingQuery ? { height: "100%" } : { overflowY: "auto", height: "100%" }}>
<Stack horizontal verticalAlign="center">
<Image src={CopilotIcon} />
<Text style={{ marginLeft: 8, fontWeight: 600, fontSize: 16 }}>Copilot</Text>
@@ -517,7 +532,12 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
target="#likeBtn"
onDismiss={() => {
setShowCallout(false);
submitFeedback({ generatedQuery, likeQuery, description: "", userPrompt: userPrompt });
submitFeedback({
generatedQuery: generatedQuery,
likeQuery: likeQuery,
description: "",
userPrompt: userPrompt,
});
}}
directionalHint={DirectionalHint.topCenter}
>

View File

@@ -1,6 +1,5 @@
import { FeedOptions, Item, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
import {
JunoEndpoints,
QueryCopilotSampleContainerId,
QueryCopilotSampleContainerSchema,
QueryCopilotSampleDatabaseId,
@@ -33,7 +32,7 @@ export const submitFeedback = async (params: FeedbackParams): Promise<void> => {
contact: contact || "",
};
await fetch(`${JunoEndpoints.Prod}/feedback`, {
await fetch("https://copilotorchestrater.azurewebsites.net/feedback", {
method: "POST",
headers: {
"content-type": "application/json",

View File

@@ -67,10 +67,10 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
},
}
}
value="Write a query to return all records in this table"
value=""
/>
<CustomizedIconButton
disabled={false}
disabled={true}
iconProps={
Object {
"iconName": "Send",

View File

@@ -9,6 +9,7 @@ import { ConnectTab } from "Explorer/Tabs/ConnectTab";
import { PostgresConnectTab } from "Explorer/Tabs/PostgresConnectTab";
import { QuickstartTab } from "Explorer/Tabs/QuickstartTab";
import { userContext } from "UserContext";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import { useTeachingBubble } from "hooks/useTeachingBubble";
import ko from "knockout";
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
@@ -158,6 +159,7 @@ const CloseButton = ({
onClick={(event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
event.stopPropagation();
tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind);
tabKind === ReactTabKind.QueryCopilot && useQueryCopilot.getState().resetQueryCopilotStates();
}}
tabIndex={active ? 0 : undefined}
onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)}
@@ -251,7 +253,7 @@ const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): J
case ReactTabKind.Quickstart:
return <QuickstartTab explorer={explorer} />;
case ReactTabKind.QueryCopilot:
return <QueryCopilotTab initialInput={useTabs.getState().queryCopilotTabInitialInput} explorer={explorer} />;
return <QueryCopilotTab explorer={explorer} />;
default:
throw Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
}

View File

@@ -36,6 +36,7 @@ export type Features = {
readonly enableLegacyMongoShellV2Debug: boolean;
readonly loadLegacyMongoShellFromBE: boolean;
readonly enableCopilot: boolean;
readonly enableNPSSurvey: boolean;
// can be set via both flight and feature flag
autoscaleDefault: boolean;
@@ -104,6 +105,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
enableLegacyMongoShellV2Debug: "true" === get("enablelegacymongoshellv2debug"),
loadLegacyMongoShellFromBE: "true" === get("loadlegacymongoshellfrombe"),
enableCopilot: "true" === get("enablecopilot"),
enableNPSSurvey: "true" === get("enablenpssurvey"),
};
}

View File

@@ -91,7 +91,7 @@ const userContext: UserContext = {
collectionCreationDefaults: CollectionCreationDefaults,
};
function isAccountNewerThanThresholdInMs(createdAt: string, threshold: number) {
export function isAccountNewerThanThresholdInMs(createdAt: string, threshold: number) {
let createdAtMs: number = Date.parse(createdAt);
if (isNaN(createdAtMs)) {
createdAtMs = 0;

View File

@@ -38,7 +38,7 @@ function validateEndpointInternal(
return valid;
}
export const allowedArmEndpoints: ReadonlyArray<string> = [
export const defaultAllowedArmEndpoints: ReadonlyArray<string> = [
"https://management.azure.com",
"https://management.usgovcloudapi.net",
"https://management.chinacloudapi.cn",
@@ -46,7 +46,7 @@ export const allowedArmEndpoints: ReadonlyArray<string> = [
export const allowedAadEndpoints: ReadonlyArray<string> = ["https://login.microsoftonline.com/"];
export const allowedBackendEndpoints: ReadonlyArray<string> = [
export const defaultAllowedBackendEndpoints: ReadonlyArray<string> = [
"https://main.documentdb.ext.azure.com",
"https://main.documentdb.ext.azure.cn",
"https://main.documentdb.ext.azure.us",

View File

@@ -1,3 +1,5 @@
import { MinimalQueryIterator } from "Common/IteratorUtilities";
import { QueryResults } from "Contracts/ViewModels";
import { guid } from "Explorer/Tables/Utilities";
import create, { UseStore } from "zustand";
@@ -8,23 +10,126 @@ interface QueryCopilotState {
showFeedbackModal: boolean;
hideFeedbackModalForLikedQueries: boolean;
correlationId: string;
query: string;
selectedQuery: string;
isGeneratingQuery: boolean;
isExecuting: boolean;
dislikeQuery: boolean | undefined;
showCallout: boolean;
showSamplePrompts: boolean;
queryIterator: MinimalQueryIterator | undefined;
queryResults: QueryResults | undefined;
errorMessage: string;
isSamplePromptsOpen: boolean;
showDeletePopup: boolean;
showFeedbackBar: boolean;
showCopyPopup: boolean;
showErrorMessageBar: boolean;
generatedQueryComments: string;
openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) => void;
closeFeedbackModal: () => void;
setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) => void;
refreshCorrelationId: () => void;
setUserPrompt: (userPrompt: string) => void;
setQuery: (query: string) => void;
setGeneratedQuery: (generatedQuery: string) => void;
setSelectedQuery: (selectedQuery: string) => void;
setIsGeneratingQuery: (isGeneratingQuery: boolean) => void;
setIsExecuting: (isExecuting: boolean) => void;
setLikeQuery: (likeQuery: boolean) => void;
setDislikeQuery: (dislikeQuery: boolean | undefined) => void;
setShowCallout: (showCallout: boolean) => void;
setShowSamplePrompts: (showSamplePrompts: boolean) => void;
setQueryIterator: (queryIterator: MinimalQueryIterator | undefined) => void;
setQueryResults: (queryResults: QueryResults | undefined) => void;
setErrorMessage: (errorMessage: string) => void;
setIsSamplePromptsOpen: (isSamplePromptsOpen: boolean) => void;
setShowDeletePopup: (showDeletePopup: boolean) => void;
setShowFeedbackBar: (showFeedbackBar: boolean) => void;
setshowCopyPopup: (showCopyPopup: boolean) => void;
setShowErrorMessageBar: (showErrorMessageBar: boolean) => void;
setGeneratedQueryComments: (generatedQueryComments: string) => void;
resetQueryCopilotStates: () => void;
}
export const useQueryCopilot: UseStore<QueryCopilotState> = create((set) => ({
type QueryCopilotStore = UseStore<QueryCopilotState>;
export const useQueryCopilot: QueryCopilotStore = create((set) => ({
generatedQuery: "",
likeQuery: false,
userPrompt: "",
showFeedbackModal: false,
hideFeedbackModalForLikedQueries: false,
correlationId: "",
query: "",
selectedQuery: "",
isGeneratingQuery: false,
isExecuting: false,
dislikeQuery: undefined,
showCallout: false,
showSamplePrompts: false,
queryIterator: undefined,
queryResults: undefined,
errorMessage: "",
isSamplePromptsOpen: false,
showDeletePopup: false,
showFeedbackBar: false,
showCopyPopup: false,
showErrorMessageBar: false,
generatedQueryComments: "",
openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) =>
set({ generatedQuery, likeQuery, userPrompt, showFeedbackModal: true }),
closeFeedbackModal: () => set({ generatedQuery: "", likeQuery: false, userPrompt: "", showFeedbackModal: false }),
setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) =>
set({ hideFeedbackModalForLikedQueries }),
refreshCorrelationId: () => set({ correlationId: guid() }),
setUserPrompt: (userPrompt: string) => set({ userPrompt }),
setQuery: (query: string) => set({ query }),
setGeneratedQuery: (generatedQuery: string) => set({ generatedQuery }),
setSelectedQuery: (selectedQuery: string) => set({ selectedQuery }),
setIsGeneratingQuery: (isGeneratingQuery: boolean) => set({ isGeneratingQuery }),
setIsExecuting: (isExecuting: boolean) => set({ isExecuting }),
setLikeQuery: (likeQuery: boolean) => set({ likeQuery }),
setDislikeQuery: (dislikeQuery: boolean | undefined) => set({ dislikeQuery }),
setShowCallout: (showCallout: boolean) => set({ showCallout }),
setShowSamplePrompts: (showSamplePrompts: boolean) => set({ showSamplePrompts }),
setQueryIterator: (queryIterator: MinimalQueryIterator | undefined) => set({ queryIterator }),
setQueryResults: (queryResults: QueryResults | undefined) => set({ queryResults }),
setErrorMessage: (errorMessage: string) => set({ errorMessage }),
setIsSamplePromptsOpen: (isSamplePromptsOpen: boolean) => set({ isSamplePromptsOpen }),
setShowDeletePopup: (showDeletePopup: boolean) => set({ showDeletePopup }),
setShowFeedbackBar: (showFeedbackBar: boolean) => set({ showFeedbackBar }),
setshowCopyPopup: (showCopyPopup: boolean) => set({ showCopyPopup }),
setShowErrorMessageBar: (showErrorMessageBar: boolean) => set({ showErrorMessageBar }),
setGeneratedQueryComments: (generatedQueryComments: string) => set({ generatedQueryComments }),
resetQueryCopilotStates: () => {
set((state) => ({
...state,
generatedQuery: "",
likeQuery: false,
userPrompt: "",
showFeedbackModal: false,
hideFeedbackModalForLikedQueries: false,
correlationId: "",
query: "",
selectedQuery: "",
isGeneratingQuery: false,
isExecuting: false,
dislikeQuery: undefined,
showCallout: false,
showSamplePrompts: false,
queryIterator: undefined,
queryResults: undefined,
errorMessage: "",
isSamplePromptsOpen: false,
showDeletePopup: false,
showFeedbackBar: false,
showCopyPopup: false,
showErrorMessageBar: false,
generatedQueryComments: "",
}));
},
}));