add feedback policies integration with copilot (#1745)

* add feedback policies integration with copilot

* remove teaching bubble and welcome modal

* force prod phoenix endpoint in MPAC

* force prod phoenix endpoint in MPAC
This commit is contained in:
sunghyunkang1111 2024-03-06 10:33:21 -06:00 committed by GitHub
parent b3837a089d
commit 56c0049e9a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 103 additions and 99 deletions

View File

@ -1,5 +1,5 @@
{ {
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com", "JUNO_ENDPOINT": "https://tools.cosmos.azure.com",
"isTerminalEnabled" : true, "isTerminalEnabled": true,
"isPhoenixEnabled" : true "isPhoenixEnabled": true
} }

View File

@ -407,6 +407,7 @@ export interface DataExplorerInputsFrame {
features?: { features?: {
[key: string]: string; [key: string]: string;
}; };
feedbackPolicies?: any;
} }
export interface SelfServeFrameInputs { export interface SelfServeFrameInputs {

View File

@ -486,4 +486,4 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
isButtonDisabled={false} isButtonDisabled={false}
/> />
</form> </form>
`; `;

View File

@ -21,7 +21,6 @@ import {
import { HttpStatusCodes } from "Common/Constants"; import { HttpStatusCodes } from "Common/Constants";
import { handleError } from "Common/ErrorHandlingUtils"; import { handleError } from "Common/ErrorHandlingUtils";
import { createUri } from "Common/UrlUtility"; import { createUri } from "Common/UrlUtility";
import { WelcomeModal } from "Explorer/QueryCopilot/Modal/WelcomeModal";
import { CopyPopup } from "Explorer/QueryCopilot/Popup/CopyPopup"; import { CopyPopup } from "Explorer/QueryCopilot/Popup/CopyPopup";
import { DeletePopup } from "Explorer/QueryCopilot/Popup/DeletePopup"; import { DeletePopup } from "Explorer/QueryCopilot/Popup/DeletePopup";
import { import {
@ -272,28 +271,11 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
} }
}; };
const showTeachingBubble = (): void => {
if (showPromptTeachingBubble && !inputEdited.current) {
setTimeout(() => {
if (!inputEdited.current && !isWelcomModalVisible()) {
setCopilotTeachingBubbleVisible(true);
inputEdited.current = true;
}
}, 30000);
} else {
toggleCopilotTeachingBubbleVisible(false);
}
};
const toggleCopilotTeachingBubbleVisible = (visible: boolean): void => { const toggleCopilotTeachingBubbleVisible = (visible: boolean): void => {
setCopilotTeachingBubbleVisible(visible); setCopilotTeachingBubbleVisible(visible);
setShowPromptTeachingBubble(visible); setShowPromptTeachingBubble(visible);
}; };
const isWelcomModalVisible = (): boolean => {
return localStorage.getItem("hideWelcomeModal") !== "true";
};
const clearFeedback = () => { const clearFeedback = () => {
resetButtonState(); resetButtonState();
resetQueryResults(); resetQueryResults();
@ -322,7 +304,6 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
}; };
React.useEffect(() => { React.useEffect(() => {
showTeachingBubble();
useTabs.getState().setIsQueryErrorThrown(false); useTabs.getState().setIsQueryErrorThrown(false);
}, []); }, []);
@ -539,84 +520,90 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
</Stack> </Stack>
{showFeedbackBar && ( {showFeedbackBar && (
<Stack style={{ backgroundColor: "#FFF8F0", padding: "2px 8px" }} horizontal verticalAlign="center"> <Stack
<Text style={{ fontWeight: 600, fontSize: 12 }}>Provide feedback on the query generated</Text> style={{ backgroundColor: "#FFF8F0", padding: "2px 8px", minHeight: 32 }}
{showCallout && !hideFeedbackModalForLikedQueries && ( horizontal
<Callout verticalAlign="center"
role="status" >
style={{ padding: 8 }} {userContext.feedbackPolicies?.policyAllowFeedback && (
target="#likeBtn" <Stack horizontal verticalAlign="center">
onDismiss={() => { <Text style={{ fontWeight: 600, fontSize: 12 }}>Provide feedback on the query generated</Text>
setShowCallout(false); {showCallout && !hideFeedbackModalForLikedQueries && (
SubmitFeedback({ <Callout
params: { role="status"
generatedQuery: generatedQuery, style={{ padding: 8 }}
likeQuery: likeQuery, target="#likeBtn"
description: "", onDismiss={() => {
userPrompt: userPrompt,
},
explorer,
databaseId,
containerId,
mode: isSampleCopilotActive ? "Sample" : "User",
});
}}
directionalHint={DirectionalHint.topCenter}
>
<Text>
Thank you. Need to give{" "}
<Link
onClick={() => {
setShowCallout(false); setShowCallout(false);
openFeedbackModal(generatedQuery, true, userPrompt); SubmitFeedback({
params: {
generatedQuery: generatedQuery,
likeQuery: likeQuery,
description: "",
userPrompt: userPrompt,
},
explorer,
databaseId,
containerId,
mode: isSampleCopilotActive ? "Sample" : "User",
});
}} }}
directionalHint={DirectionalHint.topCenter}
> >
more feedback? <Text>
</Link> Thank you. Need to give{" "}
</Text> <Link
</Callout> onClick={() => {
setShowCallout(false);
openFeedbackModal(generatedQuery, true, userPrompt);
}}
>
more feedback?
</Link>
</Text>
</Callout>
)}
<IconButton
id="likeBtn"
style={{ marginLeft: 20 }}
aria-label="Like"
role="toggle"
iconProps={{ iconName: likeQuery === true ? "LikeSolid" : "Like" }}
onClick={() => {
setShowCallout(!likeQuery);
setLikeQuery(!likeQuery);
if (likeQuery === true) {
document.getElementById("likeStatus").innerHTML = "Unpressed";
}
if (likeQuery === false) {
document.getElementById("likeStatus").innerHTML = "Liked";
}
if (dislikeQuery) {
setDislikeQuery(!dislikeQuery);
}
}}
/>
<IconButton
style={{ margin: "0 10px" }}
role="toggle"
aria-label="Dislike"
iconProps={{ iconName: dislikeQuery === true ? "DislikeSolid" : "Dislike" }}
onClick={() => {
let toggleStatusValue = "Unpressed";
if (!dislikeQuery) {
openFeedbackModal(generatedQuery, false, userPrompt);
setLikeQuery(false);
toggleStatusValue = "Disliked";
}
setDislikeQuery(!dislikeQuery);
setShowCallout(false);
document.getElementById("likeStatus").innerHTML = toggleStatusValue;
}}
/>
<span role="status" style={{ position: "absolute", left: "-9999px" }} id="likeStatus"></span>
<Separator vertical style={{ color: "#EDEBE9" }} />
</Stack>
)} )}
<IconButton
id="likeBtn"
style={{ marginLeft: 20 }}
aria-label="Like"
role="toggle"
iconProps={{ iconName: likeQuery === true ? "LikeSolid" : "Like" }}
onClick={() => {
setShowCallout(!likeQuery);
setLikeQuery(!likeQuery);
if (likeQuery === true) {
document.getElementById("likeStatus").innerHTML = "Unpressed";
}
if (likeQuery === false) {
document.getElementById("likeStatus").innerHTML = "Liked";
}
if (dislikeQuery) {
setDislikeQuery(!dislikeQuery);
}
}}
/>
<IconButton
style={{ margin: "0 10px" }}
role="toggle"
aria-label="Dislike"
iconProps={{ iconName: dislikeQuery === true ? "DislikeSolid" : "Dislike" }}
onClick={() => {
let toggleStatusValue = "Unpressed";
if (!dislikeQuery) {
openFeedbackModal(generatedQuery, false, userPrompt);
setLikeQuery(false);
toggleStatusValue = "Disliked";
}
setDislikeQuery(!dislikeQuery);
setShowCallout(false);
document.getElementById("likeStatus").innerHTML = toggleStatusValue;
}}
/>
<span role="status" style={{ position: "absolute", left: "-9999px" }} id="likeStatus"></span>
<Separator vertical style={{ color: "#EDEBE9" }} />
<CommandBarButton <CommandBarButton
className="copyQuery" className="copyQuery"
onClick={copyGeneratedCode} onClick={copyGeneratedCode}
@ -637,7 +624,6 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
</CommandBarButton> </CommandBarButton>
</Stack> </Stack>
)} )}
<WelcomeModal visible={isWelcomModalVisible()} />
{isSamplePromptsOpen && <SamplePrompts sampleProps={sampleProps} />} {isSamplePromptsOpen && <SamplePrompts sampleProps={sampleProps} />}
{query !== "" && query.trim().length !== 0 && ( {query !== "" && query.trim().length !== 0 && (
<DeletePopup <DeletePopup

View File

@ -53,6 +53,21 @@ interface FabricContext {
isReadOnly: boolean; isReadOnly: boolean;
} }
export type AdminFeedbackControlPolicy =
| "connectedExperiences"
| "policyAllowFeedback"
| "policyAllowSurvey"
| "policyAllowScreenshot"
| "policyAllowContact"
| "policyAllowContent"
| "policyEmailCollectionDefault"
| "policyScreenshotDefault"
| "policyContentSamplesDefault";
export type AdminFeedbackPolicySettings = {
[key in AdminFeedbackControlPolicy]: boolean;
};
interface UserContext { interface UserContext {
readonly fabricContext?: FabricContext; readonly fabricContext?: FabricContext;
readonly authType?: AuthType; readonly authType?: AuthType;
@ -84,6 +99,7 @@ interface UserContext {
collectionCreationDefaults: CollectionCreationDefaults; collectionCreationDefaults: CollectionCreationDefaults;
sampleDataConnectionInfo?: ParsedResourceTokenConnectionString; sampleDataConnectionInfo?: ParsedResourceTokenConnectionString;
readonly vcoreMongoConnectionParams?: VCoreMongoConnectionParams; readonly vcoreMongoConnectionParams?: VCoreMongoConnectionParams;
readonly feedbackPolicies?: AdminFeedbackPolicySettings;
} }
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres" | "VCoreMongo"; export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres" | "VCoreMongo";

View File

@ -499,6 +499,7 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
hasWriteAccess: inputs.hasWriteAccess ?? true, hasWriteAccess: inputs.hasWriteAccess ?? true,
collectionCreationDefaults: inputs.defaultCollectionThroughput, collectionCreationDefaults: inputs.defaultCollectionThroughput,
isTryCosmosDBSubscription: inputs.isTryCosmosDBSubscription, isTryCosmosDBSubscription: inputs.isTryCosmosDBSubscription,
feedbackPolicies: inputs.feedbackPolicies,
}); });
if (inputs.isPostgresAccount) { if (inputs.isPostgresAccount) {