Compare commits

...

9 Commits

Author SHA1 Message Date
Victor Meng
dc63ade6c6 Update copilot endpoints 2023-08-01 16:19:52 -07:00
v-darkora
7ec5290293 [Query Copilot] Update feature flag after sample data connection info fetch (#1560)
* Update feature flag if sample data exists

* Add additional conditional

* Revert useknockout to starting condition

* Use tracked property for rendering conditiona
2023-07-28 09:43:12 +02:00
v-darkora
4005128211 [Query Copilot] Add telemetry for query copilot (#1555) 2023-07-27 11:41:41 -07:00
v-darkora
38d13cc74e [Query Copilot] Generate query on enter (#1558) 2023-07-27 10:45:42 -07:00
Predrag Klepic
4ab93a5a32 [Query Copilot] Updated Copilot links (#1556)
Co-authored-by: Predrag Klepic <v-prklepic@microsoft.com>
2023-07-27 10:43:24 -07:00
Predrag Klepic
44e25c0769 [Query Copilot] New Query button added on Items section (#1552)
Co-authored-by: Predrag Klepic <v-prklepic@microsoft.com>
2023-07-27 10:42:17 -07:00
MokireddySampath
8ea8f0230f role has been changed to heading (#1453)
* arialabel has been added to close button of invitational youtube video

* heading role has been addedd and tag has been changed to h1

* Update QuickstartCarousel.tsx

* Update QuickstartCarousel.tsx

* Update SplashScreen.tsx
2023-07-27 07:30:27 +05:30
MokireddySampath
655b998b84 outline has been added to choose columns links (#1454)
* arialabel has been added to close button of invitational youtube video

* heading role has been addedd and tag has been changed to h1

* outline has been restored to choose columns link in entities page

* Update QuickstartCarousel.tsx

* Update SplashScreen.tsx

* Update TableEntity.tsx

* outline for edit entity has been added on focus
2023-07-27 07:29:54 +05:30
Predrag Klepic
9e2f6a9c89 [Query Copilot] QueryCopilotUtilities.ts tests (#1550)
* Improving test coverage

* Not leaving empty functions

* Additional test editing

* Correction of the unit test

* Changes made so the tests work correctly

* removing problematic tests

* QueryCopilotUtilities

* Changes based on Lint suggestion

* Changes based on lint

* Additional lint suggestion solved

* sample implementation

* removing console log

* Fixing non empty lint function error

* Changed any to void in mocked function

---------

Co-authored-by: Predrag Klepic <v-prklepic@microsoft.com>
2023-07-25 09:16:10 +02:00
17 changed files with 325 additions and 35 deletions

View File

@@ -230,7 +230,7 @@ input::-webkit-inner-spin-button {
.advanced-options-panel .advanced-options .select .select-options-link {
margin-left: 4px;
cursor: pointer;
outline: none;
padding: 2px;
}
.query-panel .row .column-headers .Field {

View File

@@ -137,7 +137,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
/>
{!isEntityValueDisable && (
<TooltipHost content="Edit property" id="editTooltip">
<div tabIndex={0}>
<div>
<Image
{...imageProps}
src={EditIcon}

View File

@@ -1,3 +1,5 @@
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import { ReactTabKind, useTabs } from "hooks/useTabs";
import React from "react";
import AddCollectionIcon from "../../images/AddCollection.svg";
@@ -146,7 +148,10 @@ export const createSampleCollectionContextMenuButton = (): TreeNodeMenuItem[] =>
if (userContext.apiType === "SQL") {
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot),
onClick: () => {
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
traceOpen(Action.OpenQueryCopilotFromNewQuery, { apiType: userContext.apiType });
},
label: "New SQL Query",
});
}

View File

@@ -1,3 +1,5 @@
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import { ReactTabKind, useTabs } from "hooks/useTabs";
import * as React from "react";
import AddCollectionIcon from "../../../../images/AddCollection.svg";
@@ -326,6 +328,7 @@ function createNewSQLQueryButton(selectedNodeState: SelectedNodeState): CommandB
onCommandClick: () => {
if (useSelectedNode.getState().isQueryCopilotCollectionSelected()) {
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
traceOpen(Action.OpenQueryCopilotFromNewQuery, { apiType: userContext.apiType });
} else {
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection);

View File

@@ -112,6 +112,9 @@
margin-top: 28px;
margin-left: 4px !important;
}
.addRemoveIcon [alt="editEntity"]:focus,.addRemoveIconLabel [alt="editEntity"]:focus{
border:1px dashed #605E5C
}
.addNewParamStyle {
margin-top: 5px;
margin-left: 5px !important;

View File

@@ -80,7 +80,7 @@ export const QueryCopilotFeedbackModal: React.FC = (): JSX.Element => {
<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="" target="_blank">
<Link href="https://privacy.microsoft.com/privacystatement" target="_blank">
Privacy statement
</Link>
</Text>

View File

@@ -60,7 +60,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
<Text>
Ask Copilot to generate a query by describing the query in your words.
<br />
<Link href="">Learn more</Link>
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
</Text>
</Stack.Item>
<Stack.Item align="center" className="text">
@@ -78,7 +78,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
<Text>
AI-generated content can have mistakes. Make sure its accurate and appropriate before using it.
<br />
<Link href="">Read preview terms</Link>
<Link href="http://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
</Text>
</Stack.Item>
<Stack.Item align="center" className="text">
@@ -96,7 +96,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
<Text>
Copilot is setup on a sample database we have configured for you at no cost
<br />
<Link href="">Learn more</Link>
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
</Text>
</Stack.Item>
</Stack>

View File

@@ -121,7 +121,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement
@@ -274,7 +274,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement
@@ -427,7 +427,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement
@@ -580,7 +580,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement
@@ -733,7 +733,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement
@@ -886,7 +886,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement
@@ -1039,7 +1039,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement
@@ -1192,7 +1192,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement
@@ -1360,7 +1360,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.
<StyledLinkBase
href=""
href="https://privacy.microsoft.com/privacystatement"
target="_blank"
>
Privacy statement

View File

@@ -97,7 +97,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
Ask Copilot to generate a query by describing the query in your words.
<br />
<StyledLinkBase
href=""
href="http://aka.ms/cdb-copilot-learn-more"
>
Learn more
</StyledLinkBase>
@@ -133,7 +133,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
AI-generated content can have mistakes. Make sure its accurate and appropriate before using it.
<br />
<StyledLinkBase
href=""
href="http://aka.ms/cdb-copilot-preview-terms"
>
Read preview terms
</StyledLinkBase>
@@ -169,7 +169,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
Copilot is setup on a sample database we have configured for you at no cost
<br />
<StyledLinkBase
href=""
href="http://aka.ms/cdb-copilot-learn-more"
>
Learn more
</StyledLinkBase>

View File

@@ -17,7 +17,7 @@ import {
TextField,
} from "@fluentui/react";
import { useBoolean } from "@fluentui/react-hooks";
import { QueryCopilotSampleContainerId, QueryCopilotSampleContainerSchema } from "Common/Constants";
import { JunoEndpoints, QueryCopilotSampleContainerId, QueryCopilotSampleContainerSchema } from "Common/Constants";
import { getErrorMessage, handleError } from "Common/ErrorHandlingUtils";
import { shouldEnableCrossPartitionKey } from "Common/HeadersUtility";
import { MinimalQueryIterator } from "Common/IteratorUtilities";
@@ -34,6 +34,8 @@ import { DeletePopup } from "Explorer/QueryCopilot/Popup/DeletePopup";
import { querySampleDocuments, submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities";
import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/SamplePrompts/SamplePrompts";
import { QueryResultSection } from "Explorer/Tabs/QueryTab/QueryResultSection";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceFailure, traceStart, traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
import { queryPagesUntilContentPresent } from "Utils/QueryUtils";
import { useQueryCopilot } from "hooks/useQueryCopilot";
@@ -78,6 +80,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
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);
@@ -170,10 +173,12 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
userPrompt: userPrompt,
};
setShowDeletePopup(false);
const response = await fetch("https://copilotorchestrater.azurewebsites.net/generateSQLQuery", {
useQueryCopilot.getState().refreshCorrelationId();
const response = await fetch(`${JunoEndpoints.Prod}/generateSQLQuery`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
body: JSON.stringify(payload),
});
@@ -188,6 +193,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
query += generateSQLQueryResponse.sql;
setQuery(query);
setGeneratedQuery(generateSQLQueryResponse.sql);
setGeneratedQueryComments(generateSQLQueryResponse.explanation);
setShowErrorMessageBar(false);
}
} else {
@@ -208,6 +214,13 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
};
const onExecuteQueryClick = async (): Promise<void> => {
traceStart(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
userPrompt: userPrompt,
generatedQuery: generatedQuery,
generatedQueryComments: generatedQueryComments,
executedQuery: selectedQuery || query,
});
const queryToExecute = selectedQuery || query;
const queryIterator = querySampleDocuments(queryToExecute, {
enableCrossPartitionQuery: shouldEnableCrossPartitionKey(),
@@ -233,8 +246,15 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
setQueryResults(queryResults);
setErrorMessage("");
setShowErrorMessageBar(false);
traceSuccess(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
});
} catch (error) {
const errorMessage = getErrorMessage(error);
traceFailure(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
errorMessage: errorMessage,
});
setErrorMessage(errorMessage);
handleError(errorMessage, "executeQueryCopilotTab");
useTabs.getState().setIsQueryErrorThrown(true);
@@ -297,6 +317,12 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
setShowCallout(false);
};
const startGenerateQueryProcess = () => {
updateHistories();
generateSQLQuery();
resetButtonState();
};
React.useEffect(() => {
useCommandBar.getState().setContextButtons(getCommandbarButtons());
}, [query, selectedQuery]);
@@ -325,6 +351,11 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
inputEdited.current = true;
setShowSamplePrompts(true);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
startGenerateQueryProcess();
}
}}
style={{ lineHeight: 30 }}
styles={{ root: { width: "95%" } }}
disabled={isGeneratingQuery}
@@ -357,11 +388,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
iconProps={{ iconName: "Send" }}
disabled={isGeneratingQuery || !userPrompt.trim()}
style={{ marginLeft: 8 }}
onClick={() => {
updateHistories();
generateSQLQuery();
resetButtonState();
}}
onClick={() => startGenerateQueryProcess()}
/>
{isGeneratingQuery && <Spinner style={{ marginLeft: 8 }} />}
{showSamplePrompts && (
@@ -453,7 +480,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
}}
>
Learn about{" "}
<Link target="_blank" href="">
<Link target="_blank" href="http://aka.ms/cdb-copilot-writing">
writing effective prompts
</Link>
</Text>
@@ -467,7 +494,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
<Stack style={{ marginTop: 8, marginBottom: 24 }}>
<Text style={{ fontSize: 12 }}>
AI-generated content can have mistakes. Make sure it&apos;s accurate and appropriate before using it.{" "}
<Link href="" target="_blank">
<Link href="http://aka.ms/cdb-copilot-preview-terms" target="_blank">
Read preview terms
</Link>
{showErrorMessageBar && (

View File

@@ -0,0 +1,225 @@
import { FeedOptions } from "@azure/cosmos";
import { QueryCopilotSampleContainerSchema } from "Common/Constants";
import { handleError } from "Common/ErrorHandlingUtils";
import { sampleDataClient } from "Common/SampleDataClient";
import * as commonUtils from "Common/dataAccess/queryDocuments";
import DocumentId from "Explorer/Tree/DocumentId";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import { querySampleDocuments, readSampleDocument, submitFeedback } from "./QueryCopilotUtilities";
jest.mock("Explorer/Tree/DocumentId", () => {
return jest.fn().mockImplementation(() => {
return {
id: jest.fn(),
loadDocument: jest.fn(),
};
});
});
jest.mock("Utils/NotificationConsoleUtils", () => ({
logConsoleProgress: jest.fn(),
logConsoleError: jest.fn(),
}));
jest.mock("@azure/cosmos", () => ({
FeedOptions: jest.fn(),
QueryIterator: jest.fn(),
}));
jest.mock("Common/ErrorHandlingUtils", () => ({
handleError: jest.fn(),
}));
jest.mock("Utils/NotificationConsoleUtils", () => ({
logConsoleProgress: jest.fn().mockReturnValue((): void => undefined),
}));
jest.mock("Common/dataAccess/queryDocuments", () => ({
getCommonQueryOptions: jest.fn((options) => options),
}));
jest.mock("Common/SampleDataClient");
jest.mock("node-fetch");
describe("QueryCopilotUtilities", () => {
beforeEach(() => jest.clearAllMocks());
describe("submitFeedback", () => {
const payload = {
like: "like",
generatedSql: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
containerSchema: QueryCopilotSampleContainerSchema,
};
it("should call fetch with the payload with like", async () => {
const mockFetch = jest.fn().mockResolvedValueOnce({});
globalThis.fetch = mockFetch;
useQueryCopilot.getState().refreshCorrelationId();
await submitFeedback({
likeQuery: true,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
});
expect(mockFetch).toHaveBeenCalledWith(
"https://copilotorchestrater.azurewebsites.net/feedback",
expect.objectContaining({
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
})
);
const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(actualBody).toEqual(payload);
});
it("should call fetch with the payload with unlike and empty parameters", async () => {
payload.like = "dislike";
payload.description = "";
payload.contact = "";
const mockFetch = jest.fn().mockResolvedValueOnce({});
globalThis.fetch = mockFetch;
useQueryCopilot.getState().refreshCorrelationId();
await submitFeedback({
likeQuery: false,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: undefined,
contact: undefined,
});
expect(mockFetch).toHaveBeenCalledWith(
"https://copilotorchestrater.azurewebsites.net/feedback",
expect.objectContaining({
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
})
);
const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(actualBody).toEqual(payload);
});
it("should handle errors and call handleError", async () => {
globalThis.fetch = jest.fn().mockRejectedValueOnce(new Error("Mock error"));
await submitFeedback({
likeQuery: true,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
}).catch((error) => {
expect(error.message).toEqual("Mock error");
});
expect(handleError).toHaveBeenCalledWith(new Error("Mock error"), expect.any(String));
});
});
describe("querySampleDocuments", () => {
(sampleDataClient as jest.Mock).mockReturnValue({
database: jest.fn().mockReturnValue({
container: jest.fn().mockReturnValue({
items: {
query: jest.fn().mockReturnValue([]),
},
}),
}),
});
it("calls getCommonQueryOptions with the provided options", () => {
const query = "sample query";
const options: FeedOptions = { maxItemCount: 10 };
querySampleDocuments(query, options);
expect(commonUtils.getCommonQueryOptions).toHaveBeenCalledWith(options);
});
it("returns the result of items.query method", () => {
const query = "sample query";
const options: FeedOptions = { maxItemCount: 10 };
const mockResult = [
{ id: 1, name: "Document 1" },
{ id: 2, name: "Document 2" },
];
// Mock the items.query method to return the mockResult
(sampleDataClient().database("CopilotSampleDb").container("SampleContainer").items
.query as jest.Mock).mockReturnValue(mockResult);
const result = querySampleDocuments(query, options);
expect(result).toEqual(mockResult);
});
});
describe("readSampleDocument", () => {
it("should call the read method with the correct parameters", async () => {
(sampleDataClient as jest.Mock).mockReturnValue({
database: jest.fn().mockReturnValue({
container: jest.fn().mockReturnValue({
item: jest.fn().mockReturnValue({
read: jest.fn().mockResolvedValue({
resource: {},
}),
}),
}),
}),
});
const documentId = new DocumentId(null, "DocumentId", []);
const expectedResponse = {};
const result = await readSampleDocument(documentId);
expect(sampleDataClient).toHaveBeenCalled();
expect(sampleDataClient().database).toHaveBeenCalledWith("CopilotSampleDb");
expect(sampleDataClient().database("CopilotSampleDb").container).toHaveBeenCalledWith("SampleContainer");
expect(
sampleDataClient().database("CopilotSampleDb").container("SampleContainer").item("DocumentId", undefined).read
).toHaveBeenCalled();
expect(result).toEqual(expectedResponse);
});
it("should handle an error and re-throw it", async () => {
(sampleDataClient as jest.Mock).mockReturnValue({
database: jest.fn().mockReturnValue({
container: jest.fn().mockReturnValue({
item: jest.fn().mockReturnValue({
read: jest.fn().mockRejectedValue(new Error("Mock error")),
}),
}),
}),
});
const errorMock = new Error("Mock error");
const documentId = new DocumentId(null, "DocumentId", []);
await expect(readSampleDocument(documentId)).rejects.toStrictEqual(errorMock);
expect(sampleDataClient).toHaveBeenCalled();
expect(sampleDataClient().database).toHaveBeenCalledWith("CopilotSampleDb");
expect(sampleDataClient().database("CopilotSampleDb").container).toHaveBeenCalledWith("SampleContainer");
expect(
sampleDataClient().database("CopilotSampleDb").container("SampleContainer").item("DocumentId", undefined).read
).toHaveBeenCalled();
expect(handleError).toHaveBeenCalledWith(errorMock, "ReadDocument", expect.any(String));
});
});
});

View File

@@ -1,5 +1,6 @@
import { FeedOptions, Item, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
import {
JunoEndpoints,
QueryCopilotSampleContainerId,
QueryCopilotSampleContainerSchema,
QueryCopilotSampleDatabaseId,
@@ -10,6 +11,7 @@ import { getPartitionKeyValue } from "Common/dataAccess/getPartitionKeyValue";
import { getCommonQueryOptions } from "Common/dataAccess/queryDocuments";
import DocumentId from "Explorer/Tree/DocumentId";
import { logConsoleProgress } from "Utils/NotificationConsoleUtils";
import { useQueryCopilot } from "hooks/useQueryCopilot";
interface FeedbackParams {
likeQuery: boolean;
@@ -31,10 +33,11 @@ export const submitFeedback = async (params: FeedbackParams): Promise<void> => {
contact: contact || "",
};
await fetch("https://copilotorchestrater.azurewebsites.net/feedback", {
await fetch(`${JunoEndpoints.Prod}/feedback`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
body: JSON.stringify(payload),
});

View File

@@ -54,6 +54,7 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
id="naturalLanguageInput"
onChange={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
style={
Object {
"lineHeight": 30,
@@ -101,7 +102,7 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.
<StyledLinkBase
href=""
href="http://aka.ms/cdb-copilot-preview-terms"
target="_blank"
>
Read preview terms

View File

@@ -97,6 +97,12 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
() => this.setState({}),
(state) => state.showResetPasswordBubble
),
},
{
dispose: useDatabases.subscribe(
() => this.setState({}),
(state) => state.sampleDataResourceTokenCollection
),
}
);
}
@@ -107,7 +113,11 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
};
private getSplashScreenButtons = (): JSX.Element => {
if (userContext.features.enableCopilot && userContext.apiType === "SQL") {
if (
useDatabases.getState().sampleDataResourceTokenCollection &&
userContext.features.enableCopilot &&
userContext.apiType === "SQL"
) {
return (
<Stack style={{ width: "66%", cursor: "pointer", margin: "40px auto" }} tokens={{ childrenGap: 16 }}>
<Stack horizontal tokens={{ childrenGap: 16 }}>
@@ -137,7 +147,10 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
description={
"Copilot is your AI buddy that helps you write Azure Cosmos DB queries like a pro. Try it using our sample data set now!"
}
onClick={() => useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot)}
onClick={() => {
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
traceOpen(Action.OpenQueryCopilotFromSplashScreen, { apiType: userContext.apiType });
}}
/>
<SplashScreenButton
imgSrc={ConnectIcon}
@@ -246,8 +259,9 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
<form className="connectExplorerFormContainer">
<div className="splashScreenContainer">
<div className="splashScreen">
<div
<h1
className="title"
role="heading"
aria-label={
userContext.apiType === "Postgres"
? "Welcome to Azure Cosmos DB for PostgreSQL"
@@ -258,7 +272,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
? "Welcome to Azure Cosmos DB for PostgreSQL"
: "Welcome to Azure Cosmos DB"}
<FeaturePanelLauncher />
</div>
</h1>
<div className="subtitle">
{userContext.apiType === "Postgres"
? "Get started with our sample datasets, documentation, and additional tools."

View File

@@ -17,7 +17,7 @@ export const SampleDataTree = ({
const buildSampleDataTree = (): TreeNode => {
const updatedSampleTree: TreeNode = {
label: sampleDataResourceTokenCollection.databaseId,
isExpanded: true,
isExpanded: false,
iconSrc: CosmosDBIcon,
className: "databaseHeader",
children: [
@@ -47,6 +47,7 @@ export const SampleDataTree = ({
{
label: "Items",
onClick: () => sampleDataResourceTokenCollection.onDocumentDBDocumentsClick(),
contextMenu: ResourceTreeContextMenuButtonFactory.createSampleCollectionContextMenuButton(),
isSelected: () =>
useSelectedNode
.getState()

View File

@@ -131,6 +131,9 @@ export enum Action {
LaunchUITour,
CancelUITour,
CompleteUITour,
OpenQueryCopilotFromSplashScreen,
OpenQueryCopilotFromNewQuery,
ExecuteQueryGeneratedFromQueryCopilot,
}
export const ActionModifiers = {

View File

@@ -1,3 +1,4 @@
import { guid } from "Explorer/Tables/Utilities";
import create, { UseStore } from "zustand";
interface QueryCopilotState {
@@ -6,9 +7,11 @@ interface QueryCopilotState {
userPrompt: string;
showFeedbackModal: boolean;
hideFeedbackModalForLikedQueries: boolean;
correlationId: string;
openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) => void;
closeFeedbackModal: () => void;
setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) => void;
refreshCorrelationId: () => void;
}
export const useQueryCopilot: UseStore<QueryCopilotState> = create((set) => ({
@@ -17,9 +20,11 @@ export const useQueryCopilot: UseStore<QueryCopilotState> = create((set) => ({
userPrompt: "",
showFeedbackModal: false,
hideFeedbackModalForLikedQueries: false,
correlationId: "",
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() }),
}));