summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/hooks/usePrivacySettings.ts
diff options
context:
space:
mode:
authorTommaso Sciortino <[email protected]>2025-06-27 12:07:38 -0700
committerGitHub <[email protected]>2025-06-27 19:07:38 +0000
commita2a46c7c6700edc6840faa2675d92695d2d3104d (patch)
treee0a10e0e5f83f9c55d8a4b459077822626937405 /packages/cli/src/ui/hooks/usePrivacySettings.ts
parent4fbffdf617b2fb87c1b663391fbe488c5c81beb8 (diff)
Add privacy notice slash command (#2059)
Diffstat (limited to 'packages/cli/src/ui/hooks/usePrivacySettings.ts')
-rw-r--r--packages/cli/src/ui/hooks/usePrivacySettings.ts135
1 files changed, 135 insertions, 0 deletions
diff --git a/packages/cli/src/ui/hooks/usePrivacySettings.ts b/packages/cli/src/ui/hooks/usePrivacySettings.ts
new file mode 100644
index 00000000..44824def
--- /dev/null
+++ b/packages/cli/src/ui/hooks/usePrivacySettings.ts
@@ -0,0 +1,135 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { GaxiosError } from 'gaxios';
+import { useState, useEffect, useCallback } from 'react';
+import { Config, CodeAssistServer, UserTierId } from '@google/gemini-cli-core';
+
+export interface PrivacyState {
+ isLoading: boolean;
+ error?: string;
+ isFreeTier?: boolean;
+ dataCollectionOptIn?: boolean;
+}
+
+export const usePrivacySettings = (config: Config) => {
+ const [privacyState, setPrivacyState] = useState<PrivacyState>({
+ isLoading: true,
+ });
+
+ useEffect(() => {
+ const fetchInitialState = async () => {
+ setPrivacyState({
+ isLoading: true,
+ });
+ try {
+ const server = getCodeAssistServer(config);
+ const tier = await getTier(server);
+ if (tier !== UserTierId.FREE) {
+ // We don't need to fetch opt-out info since non-free tier
+ // data gathering is already worked out some other way.
+ setPrivacyState({
+ isLoading: false,
+ isFreeTier: false,
+ });
+ return;
+ }
+
+ const optIn = await getRemoteDataCollectionOptIn(server);
+ setPrivacyState({
+ isLoading: false,
+ isFreeTier: true,
+ dataCollectionOptIn: optIn,
+ });
+ } catch (e) {
+ setPrivacyState({
+ isLoading: false,
+ error: e instanceof Error ? e.message : String(e),
+ });
+ }
+ };
+ fetchInitialState();
+ }, [config]);
+
+ const updateDataCollectionOptIn = useCallback(
+ async (optIn: boolean) => {
+ try {
+ const server = getCodeAssistServer(config);
+ const updatedOptIn = await setRemoteDataCollectionOptIn(server, optIn);
+ setPrivacyState({
+ isLoading: false,
+ isFreeTier: true,
+ dataCollectionOptIn: updatedOptIn,
+ });
+ } catch (e) {
+ setPrivacyState({
+ isLoading: false,
+ error: e instanceof Error ? e.message : String(e),
+ });
+ }
+ },
+ [config],
+ );
+
+ return {
+ privacyState,
+ updateDataCollectionOptIn,
+ };
+};
+
+function getCodeAssistServer(config: Config): CodeAssistServer {
+ const server = config.getGeminiClient().getContentGenerator();
+ // Neither of these cases should ever happen.
+ if (!(server instanceof CodeAssistServer)) {
+ throw new Error('Oauth not being used');
+ } else if (!server.projectId) {
+ throw new Error('Oauth not being used');
+ }
+ return server;
+}
+
+async function getTier(server: CodeAssistServer): Promise<UserTierId> {
+ const loadRes = await server.loadCodeAssist({
+ cloudaicompanionProject: server.projectId,
+ metadata: {
+ ideType: 'IDE_UNSPECIFIED',
+ platform: 'PLATFORM_UNSPECIFIED',
+ pluginType: 'GEMINI',
+ duetProject: server.projectId,
+ },
+ });
+ if (!loadRes.currentTier) {
+ throw new Error('User does not have a current tier');
+ }
+ return loadRes.currentTier.id;
+}
+
+async function getRemoteDataCollectionOptIn(
+ server: CodeAssistServer,
+): Promise<boolean> {
+ try {
+ const resp = await server.getCodeAssistGlobalUserSetting();
+ return resp.freeTierDataCollectionOptin;
+ } catch (e) {
+ if (e instanceof GaxiosError) {
+ if (e.response?.status === 404) {
+ return true;
+ }
+ }
+ throw e;
+ }
+}
+
+async function setRemoteDataCollectionOptIn(
+ server: CodeAssistServer,
+ optIn: boolean,
+): Promise<boolean> {
+ const resp = await server.setCodeAssistGlobalUserSetting({
+ cloudaicompanionProject: server.projectId,
+ freeTierDataCollectionOptin: optIn,
+ });
+ return resp.freeTierDataCollectionOptin;
+}