Path: blob/main/components/dashboard/src/data/featureflag-query.ts
3606 views
/**1* Copyright (c) 2023 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import { getPrimaryEmail } from "@gitpod/public-api-common/lib/user-utils";7import { useQuery } from "@tanstack/react-query";8import { getExperimentsClient } from "../experiments/client";9import { useCurrentUser } from "../user-context";10import { useCurrentOrg } from "./organizations/orgs-query";11import { ClassicPaygSunsetConfig } from "@gitpod/gitpod-protocol/lib/experiments/configcat";1213const defaultClassicPaygSunsetConfig: ClassicPaygSunsetConfig = { enabled: false, exemptedOrganizations: [] };1415const featureFlags = {16oidcServiceEnabled: false,17// Default to true to enable on gitpod dedicated until ff support is added for dedicated18orgGitAuthProviders: true,19userGitAuthProviders: false,20// Local SSH feature of VS Code Desktop Extension21gitpod_desktop_use_local_ssh_proxy: false,22enabledOrbitalDiscoveries: "",23// dummy specified dataops feature, default false24dataops: false,25enable_multi_org: false,26showBrowserExtensionPromotion: false,27enable_experimental_jbtb: false,28enabled_configuration_prebuild_full_clone: false,29enterprise_onboarding_enabled: false,30commit_annotation_setting_enabled: false,31classic_payg_sunset_enabled: defaultClassicPaygSunsetConfig,32};3334type FeatureFlags = typeof featureFlags;3536// Helper to parse JSON feature flags37function parseFeatureFlagValue<T>(flagName: string, rawValue: any, defaultValue: T): T {38// Special handling for JSON-based feature flags39if (flagName === "classic_payg_sunset_enabled") {40try {41if (typeof rawValue === "string") {42return JSON.parse(rawValue) as T;43}44// If it's already an object, return as-is45if (typeof rawValue === "object" && rawValue !== null) {46return rawValue as T;47}48} catch (error) {49console.error(`Failed to parse feature flag ${flagName}:`, error);50return defaultValue;51}52}53return rawValue;54}5556export const useFeatureFlag = <K extends keyof FeatureFlags>(featureFlag: K): FeatureFlags[K] | boolean => {57const user = useCurrentUser();58const org = useCurrentOrg().data;5960const queryKey = ["featureFlag", featureFlag, user?.id || "", org?.id || ""];6162const query = useQuery(queryKey, async () => {63const defaultValue = featureFlags[featureFlag];64// For JSON flags, send stringified default to ConfigCat65const configCatDefault =66featureFlag === "classic_payg_sunset_enabled" ? JSON.stringify(defaultValue) : defaultValue;6768const rawValue = await getExperimentsClient().getValueAsync(featureFlag, configCatDefault, {69user: user && {70id: user.id,71email: getPrimaryEmail(user),72},73teamId: org?.id,74teamName: org?.name,75gitpodHost: window.location.host,76});7778return parseFeatureFlagValue(featureFlag, rawValue, defaultValue);79});8081return query.data !== undefined ? query.data : featureFlags[featureFlag];82};8384export const useIsDataOps = () => {85return useFeatureFlag("dataops");86};878889