mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-06-05 15:12:04 +01:00
[Query Copilot] Add telemetry for query copilot (#1555)
This commit is contained in:
parent
38d13cc74e
commit
4005128211
@ -1,3 +1,5 @@
|
|||||||
|
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||||
|
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
|
||||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import AddCollectionIcon from "../../images/AddCollection.svg";
|
import AddCollectionIcon from "../../images/AddCollection.svg";
|
||||||
@ -146,7 +148,10 @@ export const createSampleCollectionContextMenuButton = (): TreeNodeMenuItem[] =>
|
|||||||
if (userContext.apiType === "SQL") {
|
if (userContext.apiType === "SQL") {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
onClick: () => useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot),
|
onClick: () => {
|
||||||
|
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
|
||||||
|
traceOpen(Action.OpenQueryCopilotFromNewQuery, { apiType: userContext.apiType });
|
||||||
|
},
|
||||||
label: "New SQL Query",
|
label: "New SQL Query",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||||
|
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
|
||||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import AddCollectionIcon from "../../../../images/AddCollection.svg";
|
import AddCollectionIcon from "../../../../images/AddCollection.svg";
|
||||||
@ -326,6 +328,7 @@ function createNewSQLQueryButton(selectedNodeState: SelectedNodeState): CommandB
|
|||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
if (useSelectedNode.getState().isQueryCopilotCollectionSelected()) {
|
if (useSelectedNode.getState().isQueryCopilotCollectionSelected()) {
|
||||||
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
|
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
|
||||||
|
traceOpen(Action.OpenQueryCopilotFromNewQuery, { apiType: userContext.apiType });
|
||||||
} else {
|
} else {
|
||||||
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection);
|
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection);
|
||||||
|
@ -34,6 +34,8 @@ import { DeletePopup } from "Explorer/QueryCopilot/Popup/DeletePopup";
|
|||||||
import { querySampleDocuments, submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities";
|
import { querySampleDocuments, submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities";
|
||||||
import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/SamplePrompts/SamplePrompts";
|
import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/SamplePrompts/SamplePrompts";
|
||||||
import { QueryResultSection } from "Explorer/Tabs/QueryTab/QueryResultSection";
|
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 { userContext } from "UserContext";
|
||||||
import { queryPagesUntilContentPresent } from "Utils/QueryUtils";
|
import { queryPagesUntilContentPresent } from "Utils/QueryUtils";
|
||||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||||
@ -78,6 +80,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
|||||||
const hideFeedbackModalForLikedQueries = useQueryCopilot((state) => state.hideFeedbackModalForLikedQueries);
|
const hideFeedbackModalForLikedQueries = useQueryCopilot((state) => state.hideFeedbackModalForLikedQueries);
|
||||||
const [userPrompt, setUserPrompt] = useState<string>(initialInput || "");
|
const [userPrompt, setUserPrompt] = useState<string>(initialInput || "");
|
||||||
const [generatedQuery, setGeneratedQuery] = useState<string>("");
|
const [generatedQuery, setGeneratedQuery] = useState<string>("");
|
||||||
|
const [generatedQueryComments, setGeneratedQueryComments] = useState<string>("");
|
||||||
const [query, setQuery] = useState<string>("");
|
const [query, setQuery] = useState<string>("");
|
||||||
const [selectedQuery, setSelectedQuery] = useState<string>("");
|
const [selectedQuery, setSelectedQuery] = useState<string>("");
|
||||||
const [isGeneratingQuery, setIsGeneratingQuery] = useState<boolean>(false);
|
const [isGeneratingQuery, setIsGeneratingQuery] = useState<boolean>(false);
|
||||||
@ -170,10 +173,12 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
|||||||
userPrompt: userPrompt,
|
userPrompt: userPrompt,
|
||||||
};
|
};
|
||||||
setShowDeletePopup(false);
|
setShowDeletePopup(false);
|
||||||
|
useQueryCopilot.getState().refreshCorrelationId();
|
||||||
const response = await fetch("https://copilotorchestrater.azurewebsites.net/generateSQLQuery", {
|
const response = await fetch("https://copilotorchestrater.azurewebsites.net/generateSQLQuery", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
|
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
});
|
});
|
||||||
@ -188,6 +193,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
|||||||
query += generateSQLQueryResponse.sql;
|
query += generateSQLQueryResponse.sql;
|
||||||
setQuery(query);
|
setQuery(query);
|
||||||
setGeneratedQuery(generateSQLQueryResponse.sql);
|
setGeneratedQuery(generateSQLQueryResponse.sql);
|
||||||
|
setGeneratedQueryComments(generateSQLQueryResponse.explanation);
|
||||||
setShowErrorMessageBar(false);
|
setShowErrorMessageBar(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -208,6 +214,13 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onExecuteQueryClick = async (): Promise<void> => {
|
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 queryToExecute = selectedQuery || query;
|
||||||
const queryIterator = querySampleDocuments(queryToExecute, {
|
const queryIterator = querySampleDocuments(queryToExecute, {
|
||||||
enableCrossPartitionQuery: shouldEnableCrossPartitionKey(),
|
enableCrossPartitionQuery: shouldEnableCrossPartitionKey(),
|
||||||
@ -233,8 +246,15 @@ export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
|
|||||||
setQueryResults(queryResults);
|
setQueryResults(queryResults);
|
||||||
setErrorMessage("");
|
setErrorMessage("");
|
||||||
setShowErrorMessageBar(false);
|
setShowErrorMessageBar(false);
|
||||||
|
traceSuccess(Action.ExecuteQueryGeneratedFromQueryCopilot, {
|
||||||
|
correlationId: useQueryCopilot.getState().correlationId,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = getErrorMessage(error);
|
const errorMessage = getErrorMessage(error);
|
||||||
|
traceFailure(Action.ExecuteQueryGeneratedFromQueryCopilot, {
|
||||||
|
correlationId: useQueryCopilot.getState().correlationId,
|
||||||
|
errorMessage: errorMessage,
|
||||||
|
});
|
||||||
setErrorMessage(errorMessage);
|
setErrorMessage(errorMessage);
|
||||||
handleError(errorMessage, "executeQueryCopilotTab");
|
handleError(errorMessage, "executeQueryCopilotTab");
|
||||||
useTabs.getState().setIsQueryErrorThrown(true);
|
useTabs.getState().setIsQueryErrorThrown(true);
|
||||||
|
@ -4,6 +4,7 @@ import { handleError } from "Common/ErrorHandlingUtils";
|
|||||||
import { sampleDataClient } from "Common/SampleDataClient";
|
import { sampleDataClient } from "Common/SampleDataClient";
|
||||||
import * as commonUtils from "Common/dataAccess/queryDocuments";
|
import * as commonUtils from "Common/dataAccess/queryDocuments";
|
||||||
import DocumentId from "Explorer/Tree/DocumentId";
|
import DocumentId from "Explorer/Tree/DocumentId";
|
||||||
|
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||||
import { querySampleDocuments, readSampleDocument, submitFeedback } from "./QueryCopilotUtilities";
|
import { querySampleDocuments, readSampleDocument, submitFeedback } from "./QueryCopilotUtilities";
|
||||||
jest.mock("Explorer/Tree/DocumentId", () => {
|
jest.mock("Explorer/Tree/DocumentId", () => {
|
||||||
return jest.fn().mockImplementation(() => {
|
return jest.fn().mockImplementation(() => {
|
||||||
@ -56,6 +57,7 @@ describe("QueryCopilotUtilities", () => {
|
|||||||
const mockFetch = jest.fn().mockResolvedValueOnce({});
|
const mockFetch = jest.fn().mockResolvedValueOnce({});
|
||||||
|
|
||||||
globalThis.fetch = mockFetch;
|
globalThis.fetch = mockFetch;
|
||||||
|
useQueryCopilot.getState().refreshCorrelationId();
|
||||||
|
|
||||||
await submitFeedback({
|
await submitFeedback({
|
||||||
likeQuery: true,
|
likeQuery: true,
|
||||||
@ -71,6 +73,7 @@ describe("QueryCopilotUtilities", () => {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
|
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -86,6 +89,7 @@ describe("QueryCopilotUtilities", () => {
|
|||||||
const mockFetch = jest.fn().mockResolvedValueOnce({});
|
const mockFetch = jest.fn().mockResolvedValueOnce({});
|
||||||
|
|
||||||
globalThis.fetch = mockFetch;
|
globalThis.fetch = mockFetch;
|
||||||
|
useQueryCopilot.getState().refreshCorrelationId();
|
||||||
|
|
||||||
await submitFeedback({
|
await submitFeedback({
|
||||||
likeQuery: false,
|
likeQuery: false,
|
||||||
@ -101,6 +105,7 @@ describe("QueryCopilotUtilities", () => {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
|
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -10,6 +10,7 @@ import { getPartitionKeyValue } from "Common/dataAccess/getPartitionKeyValue";
|
|||||||
import { getCommonQueryOptions } from "Common/dataAccess/queryDocuments";
|
import { getCommonQueryOptions } from "Common/dataAccess/queryDocuments";
|
||||||
import DocumentId from "Explorer/Tree/DocumentId";
|
import DocumentId from "Explorer/Tree/DocumentId";
|
||||||
import { logConsoleProgress } from "Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "Utils/NotificationConsoleUtils";
|
||||||
|
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||||
|
|
||||||
interface FeedbackParams {
|
interface FeedbackParams {
|
||||||
likeQuery: boolean;
|
likeQuery: boolean;
|
||||||
@ -35,6 +36,7 @@ export const submitFeedback = async (params: FeedbackParams): Promise<void> => {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
|
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
});
|
});
|
||||||
|
@ -137,7 +137,10 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
|||||||
description={
|
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!"
|
"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
|
<SplashScreenButton
|
||||||
imgSrc={ConnectIcon}
|
imgSrc={ConnectIcon}
|
||||||
|
@ -131,6 +131,9 @@ export enum Action {
|
|||||||
LaunchUITour,
|
LaunchUITour,
|
||||||
CancelUITour,
|
CancelUITour,
|
||||||
CompleteUITour,
|
CompleteUITour,
|
||||||
|
OpenQueryCopilotFromSplashScreen,
|
||||||
|
OpenQueryCopilotFromNewQuery,
|
||||||
|
ExecuteQueryGeneratedFromQueryCopilot,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActionModifiers = {
|
export const ActionModifiers = {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { guid } from "Explorer/Tables/Utilities";
|
||||||
import create, { UseStore } from "zustand";
|
import create, { UseStore } from "zustand";
|
||||||
|
|
||||||
interface QueryCopilotState {
|
interface QueryCopilotState {
|
||||||
@ -6,9 +7,11 @@ interface QueryCopilotState {
|
|||||||
userPrompt: string;
|
userPrompt: string;
|
||||||
showFeedbackModal: boolean;
|
showFeedbackModal: boolean;
|
||||||
hideFeedbackModalForLikedQueries: boolean;
|
hideFeedbackModalForLikedQueries: boolean;
|
||||||
|
correlationId: string;
|
||||||
openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) => void;
|
openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) => void;
|
||||||
closeFeedbackModal: () => void;
|
closeFeedbackModal: () => void;
|
||||||
setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) => void;
|
setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) => void;
|
||||||
|
refreshCorrelationId: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useQueryCopilot: UseStore<QueryCopilotState> = create((set) => ({
|
export const useQueryCopilot: UseStore<QueryCopilotState> = create((set) => ({
|
||||||
@ -17,9 +20,11 @@ export const useQueryCopilot: UseStore<QueryCopilotState> = create((set) => ({
|
|||||||
userPrompt: "",
|
userPrompt: "",
|
||||||
showFeedbackModal: false,
|
showFeedbackModal: false,
|
||||||
hideFeedbackModalForLikedQueries: false,
|
hideFeedbackModalForLikedQueries: false,
|
||||||
|
correlationId: "",
|
||||||
openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) =>
|
openFeedbackModal: (generatedQuery: string, likeQuery: boolean, userPrompt: string) =>
|
||||||
set({ generatedQuery, likeQuery, userPrompt, showFeedbackModal: true }),
|
set({ generatedQuery, likeQuery, userPrompt, showFeedbackModal: true }),
|
||||||
closeFeedbackModal: () => set({ generatedQuery: "", likeQuery: false, userPrompt: "", showFeedbackModal: false }),
|
closeFeedbackModal: () => set({ generatedQuery: "", likeQuery: false, userPrompt: "", showFeedbackModal: false }),
|
||||||
setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) =>
|
setHideFeedbackModalForLikedQueries: (hideFeedbackModalForLikedQueries: boolean) =>
|
||||||
set({ hideFeedbackModalForLikedQueries }),
|
set({ hideFeedbackModalForLikedQueries }),
|
||||||
|
refreshCorrelationId: () => set({ correlationId: guid() }),
|
||||||
}));
|
}));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user