From 9cf2a3d82fa81b61b0339349aa381caeee3f327d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 10:44:05 +0000 Subject: [PATCH 1/9] Initial plan From f7ea34b5370dd3136d8d09afd9e767415c64a01f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 10:47:58 +0000 Subject: [PATCH 2/9] Update privacy policy link in README.md Co-authored-by: tnaum-ms <171359267+tnaum-ms@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 80366fc35..06ad20704 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ This project may contain trademarks or logos for projects, products, or services # Telemetry -VS Code collects usage data and sends it to Microsoft to help improve our products and services. Read our [privacy statement](https://go.microsoft.com/fwlink/?LinkID=528096&clcid=0x409) to learn more. If you don’t wish to send usage data to Microsoft, you can set the `telemetry.enableTelemetry` setting to `false`. Learn more in our [FAQ](https://code.visualstudio.com/docs/supporting/faq#_how-to-disable-telemetry-reporting). +VS Code collects usage data and sends it to Microsoft to help improve our products and services. Read our [privacy statement](https://go.microsoft.com/fwlink/?LinkId=521839) to learn more. If you don’t wish to send usage data to Microsoft, you can set the `telemetry.enableTelemetry` setting to `false`. Learn more in our [FAQ](https://code.visualstudio.com/docs/supporting/faq#_how-to-disable-telemetry-reporting). # License From d8c1a443ccf763674c7718580020c8b499948e8e Mon Sep 17 00:00:00 2001 From: Tomasz Naumowicz Date: Thu, 20 Nov 2025 17:06:31 +0100 Subject: [PATCH 3/9] feat: disabled feedback signals when telemetry is disabled --- .../openCollectionView/openCollectionView.ts | 14 ++++++++++++++ .../collectionView/collectionViewController.ts | 1 + .../queryInsightsTab/QueryInsightsTab.tsx | 14 +++++++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/commands/openCollectionView/openCollectionView.ts b/src/commands/openCollectionView/openCollectionView.ts index 0c4a6fb03..9de16d3e3 100644 --- a/src/commands/openCollectionView/openCollectionView.ts +++ b/src/commands/openCollectionView/openCollectionView.ts @@ -5,6 +5,8 @@ import { type IActionContext } from '@microsoft/vscode-azext-utils'; import * as l10n from '@vscode/l10n'; +import * as vscode from 'vscode'; + import { ClusterSession } from '../../documentdb/ClusterSession'; import { type CollectionItem } from '../../tree/documentdb/CollectionItem'; import { CollectionViewController } from '../../webviews/documentdb/collectionView/collectionViewController'; @@ -37,11 +39,23 @@ export async function openCollectionViewInternal( */ const sessionId = await ClusterSession.initNewSession(props.clusterId); + // Enable feedback signals only when telemetry level is set to "all" + // See: https://code.visualstudio.com/docs/setup/enterprise#_configure-telemetry-level + let feedbackSignalsEnabled = false; + try { + const telemetryLevel = vscode.workspace.getConfiguration('telemetry').get('telemetryLevel'); + feedbackSignalsEnabled = telemetryLevel === 'all'; + } catch { + // If we fail to read telemetry settings, default to false + feedbackSignalsEnabled = false; + } + const view = new CollectionViewController({ sessionId: sessionId, clusterId: props.clusterId, databaseName: props.databaseName, collectionName: props.collectionName, + feedbackSignalsEnabled: feedbackSignalsEnabled, }); view.revealToForeground(); diff --git a/src/webviews/documentdb/collectionView/collectionViewController.ts b/src/webviews/documentdb/collectionView/collectionViewController.ts index 5b15d307e..6c41fac51 100644 --- a/src/webviews/documentdb/collectionView/collectionViewController.ts +++ b/src/webviews/documentdb/collectionView/collectionViewController.ts @@ -15,6 +15,7 @@ export type CollectionViewWebviewConfigurationType = { databaseName: string; collectionName: string; defaultPageSize: number; + feedbackSignalsEnabled: boolean; }; export class CollectionViewController extends WebviewController { diff --git a/src/webviews/documentdb/collectionView/components/queryInsightsTab/QueryInsightsTab.tsx b/src/webviews/documentdb/collectionView/components/queryInsightsTab/QueryInsightsTab.tsx index f327337d8..196f3e578 100644 --- a/src/webviews/documentdb/collectionView/components/queryInsightsTab/QueryInsightsTab.tsx +++ b/src/webviews/documentdb/collectionView/components/queryInsightsTab/QueryInsightsTab.tsx @@ -35,8 +35,10 @@ import { ChatMailRegular, SparkleRegular, WarningRegular } from '@fluentui/react import { CollapseRelaxed } from '@fluentui/react-motion-components-preview'; import * as l10n from '@vscode/l10n'; import { useCallback, useContext, useEffect, useState, type JSX } from 'react'; +import { useConfiguration } from '../../../../api/webview-client/useConfiguration'; import { useTrpcClient } from '../../../../api/webview-client/useTrpcClient'; import { CollectionViewContext } from '../../collectionViewContext'; +import { CollectionViewWebviewConfigurationType } from '../../collectionViewController'; import { type ImprovementCard as ImprovementCardConfig } from '../../types/queryInsights'; import { extractErrorCode } from '../../utils/errorCodeExtractor'; import { AnimatedCardList, FeedbackCard, FeedbackDialog, type AnimatedCardItem } from './components'; @@ -62,6 +64,11 @@ export const QueryInsightsMain = (): JSX.Element => { // Stage 3: AI-Powered Recommendations (opt-in) // See: docs/design-documents/performance-advisor.md + /** + * Use the configuration object to access the data passed to the webview at its creation. + */ + const configuration = useConfiguration(); + const { trpcClient } = useTrpcClient(); const [currentContext, setCurrentContext] = useContext(CollectionViewContext); const { queryInsights: queryInsightsState } = currentContext; @@ -858,9 +865,10 @@ export const QueryInsightsMain = (): JSX.Element => { /> {/* Feedback Card - hidden for RU accounts where Query Insights is not available */} - {queryInsightsState.stage1ErrorCode !== 'QUERY_INSIGHTS_PLATFORM_NOT_SUPPORTED_RU' && ( - - )} + {configuration.feedbackSignalsEnabled && + queryInsightsState.stage1ErrorCode !== 'QUERY_INSIGHTS_PLATFORM_NOT_SUPPORTED_RU' && ( + + )} From 9f1383895bbb3821a02353555fcddacea189d080 Mon Sep 17 00:00:00 2001 From: Tomasz Naumowicz Date: Thu, 20 Nov 2025 17:44:35 +0100 Subject: [PATCH 4/9] feat: updated feedback dialog, added privacy policy information --- l10n/bundle.l10n.json | 3 ++ .../components/FeedbackDialog.tsx | 49 +++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index 73a612d08..6bdf6216d 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -384,6 +384,7 @@ "HIGH PRIORITY": "HIGH PRIORITY", "How do you want to connect?": "How do you want to connect?", "How would you rate Query Insights?": "How would you rate Query Insights?", + "I have read and agree to the ": "I have read and agree to the ", "I like it": "I like it", "I want to choose the server from an online registry.": "I want to choose the server from an online registry.", "I want to connect to a local DocumentDB instance.": "I want to connect to a local DocumentDB instance.", @@ -484,6 +485,7 @@ "Manage Azure Accounts": "Manage Azure Accounts", "Manually enter a custom tenant ID": "Manually enter a custom tenant ID", "MEDIUM PRIORITY": "MEDIUM PRIORITY", + "Microsoft will process the feedback data you submit on behalf of your organization in accordance with the Data Protection Addendum between your organization and Microsoft.": "Microsoft will process the feedback data you submit on behalf of your organization in accordance with the Data Protection Addendum between your organization and Microsoft.", "Migration of connections from the Azure Databases VS Code Extension to the DocumentDB for VS Code Extension completed: {migratedCount} connections migrated.": "Migration of connections from the Azure Databases VS Code Extension to the DocumentDB for VS Code Extension completed: {migratedCount} connections migrated.", "Missing important information": "Missing important information", "Modify index?": "Modify index?", @@ -558,6 +560,7 @@ "Port number is required": "Port number is required", "Port number must be a number": "Port number must be a number", "Port number must be between 1 and 65535": "Port number must be between 1 and 65535", + "Privacy Statement": "Privacy Statement", "Procedure not found: {name}": "Procedure not found: {name}", "Process exited: \"{command}\"": "Process exited: \"{command}\"", "Project": "Project", diff --git a/src/webviews/documentdb/collectionView/components/queryInsightsTab/components/FeedbackDialog.tsx b/src/webviews/documentdb/collectionView/components/queryInsightsTab/components/FeedbackDialog.tsx index 6fd278059..006700c72 100644 --- a/src/webviews/documentdb/collectionView/components/queryInsightsTab/components/FeedbackDialog.tsx +++ b/src/webviews/documentdb/collectionView/components/queryInsightsTab/components/FeedbackDialog.tsx @@ -12,6 +12,7 @@ import { DialogContent, DialogSurface, DialogTitle, + Divider, Link, Text, } from '@fluentui/react-components'; @@ -36,11 +37,13 @@ export interface FeedbackDialogProps { export const FeedbackDialog = ({ open, onClose, sentiment, onSubmit }: FeedbackDialogProps): JSX.Element => { const [selectedReasons, setSelectedReasons] = useState>(new Set()); const [isSubmitting, setIsSubmitting] = useState(false); + const [consentChecked, setConsentChecked] = useState(false); - // Reset selected reasons when sentiment changes + // Reset selected reasons and consent when sentiment changes or dialog closes useEffect(() => { setSelectedReasons(new Set()); - }, [sentiment]); + setConsentChecked(false); + }, [sentiment, open]); const positiveReasons = [ l10n.t('Data shown was correct'), @@ -88,10 +91,15 @@ export const FeedbackDialog = ({ open, onClose, sentiment, onSubmit }: FeedbackD const handleClose = () => { if (!isSubmitting) { setSelectedReasons(new Set()); + setConsentChecked(false); onClose(); } }; + const consentNoticeText = l10n.t( + 'Microsoft will process the feedback data you submit on behalf of your organization in accordance with the Data Protection Addendum between your organization and Microsoft.', + ); + return ( !data.open && handleClose()}> @@ -141,11 +149,10 @@ export const FeedbackDialog = ({ open, onClose, sentiment, onSubmit }: FeedbackD gap: '8px', }} > - + {l10n.t( 'These signals help us improve, but more context in a discussion, issue report, or a direct message adds even more value. ', )} -
+ + {/* Horizontal divider */} + + + {/* Privacy consent section */} +
+ {/* Consent checkbox */} + setConsentChecked(data.checked === true)} + label={ + + {l10n.t('I have read and agree to the ')}{' '} + + {l10n.t('Privacy Statement')} + + + } + /> + + {/* Privacy notice text */} + {consentNoticeText} +
-