Skip to content

Commit

Permalink
refactor: move all experiment defaults in a single place (#14014)
Browse files Browse the repository at this point in the history
  • Loading branch information
timroes committed Sep 18, 2024
1 parent 55f8144 commit de12f14
Show file tree
Hide file tree
Showing 37 changed files with 85 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export const ClickToJob = (chartState: CategoricalChartState & { height: number
const { top: offsetTop = 0, bottom: offsetBottom = 0 } = offset!;
const availableHeight = height - offsetTop - offsetBottom;
const { openModal } = useModalService();
const isTimelineEnabled = useExperiment("connection.timeline", false);
const isTimelineEnabled = useExperiment("connection.timeline");

const connection = useCurrentConnection();
const createLink = useCurrentWorkspaceLink();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const useStreamsStatuses = (
streamStatuses: Map<string, StreamWithStatus>;
enabledStreams: AirbyteStreamAndConfigurationWithEnforcedStream[];
} => {
const isRateLimitedUiEnabled = useExperiment("connection.rateLimitedUI", false);
const isRateLimitedUiEnabled = useExperiment("connection.rateLimitedUI");
// memoizing the function to call to get per-stream statuses as
// otherwise breaks the Rules of Hooks by introducing a conditional;
// using ref here as react doesn't guarantee `useMemo` won't drop the reference
Expand Down
8 changes: 3 additions & 5 deletions airbyte-webapp/src/area/connector/utils/useAirbyteCloudIps.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useExperiment } from "hooks/services/Experiment";
import { defaultExperimentValues, useExperiment } from "hooks/services/Experiment";

export const useAirbyteCloudIps = () => {
const defaultIpAddresses =
"34.106.109.131, 34.106.196.165, 34.106.60.246, 34.106.229.69, 34.106.127.139, 34.106.218.58, 34.106.115.240, 34.106.225.141, 13.37.4.46, 13.37.142.60, 35.181.124.238";

const ipAddresses = useExperiment("connector.airbyteCloudIpAddresses", defaultIpAddresses) || defaultIpAddresses;
const ipAddresses =
useExperiment("connector.airbyteCloudIpAddresses") || defaultExperimentValues["connector.airbyteCloudIpAddresses"];

return ipAddresses.split(/[ ,]+/).filter(Boolean);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useMemo } from "react";
import { useExperiment } from "hooks/services/Experiment";

export const useSuggestedDestinations = () => {
const suggestedDestinationConnectors = useExperiment("connector.suggestedDestinationConnectors", "");
const suggestedDestinationConnectors = useExperiment("connector.suggestedDestinationConnectors");
return useMemo(
() => (!suggestedDestinationConnectors ? [] : suggestedDestinationConnectors.split(",").map((id) => id.trim())),
[suggestedDestinationConnectors]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useMemo } from "react";
import { useExperiment } from "hooks/services/Experiment/ExperimentService";

export const useSuggestedSources = () => {
const suggestedSourceConnectors = useExperiment("connector.suggestedSourceConnectors", "");
const suggestedSourceConnectors = useExperiment("connector.suggestedSourceConnectors");
return useMemo(
() =>
suggestedSourceConnectors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ const ContributionInfoDisplay: React.FC<ContributionInfo> = ({ actorDefinitionId
// list instead of fetching definition individually to reuse cached request and avoid 404 for net-new definitions
const sourceDefinition = useSourceDefinitionList().sourceDefinitionMap.get(actorDefinitionId);

const isContributeEditsEnabled = useExperiment("connectorBuilder.contributeEditsToMarketplace", false);
const isContributeEditsEnabled = useExperiment("connectorBuilder.contributeEditsToMarketplace");
if (!isContributeEditsEnabled) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { notificationSettingsToFormValues } from "./notificationSettingsToFormVa

export const NotificationSettingsForm: React.FC = () => {
const emailNotificationsFeatureEnabled = useFeature(FeatureItem.EmailNotifications);
const breakingChangeNotificationsExperimentEnabled = useExperiment("settings.breakingChangeNotifications", false);
const breakingChangeNotificationsExperimentEnabled = useExperiment("settings.breakingChangeNotifications");
const updateNotificationSettings = useUpdateNotificationSettings();
const { notificationSettings } = useCurrentWorkspace();
const defaultValues = notificationSettingsToFormValues(notificationSettings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export const SyncCatalogTable: FC<SyncCatalogTableProps> = ({ scrollParentContai
const watchedNamespaceFormat = useWatch<FormConnectionFormValues>({ name: "namespaceFormat", control });

const isHashingSupported = useFeature(FeatureItem.FieldHashing);
const isHashingEnabled = useExperiment("connection.hashingUI", false);
const isHashingEnabled = useExperiment("connection.hashingUI");
const showHashing = isHashingSupported && isHashingEnabled;

const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const StreamFieldNameCell: React.FC<StreamFieldNameCellProps> = ({
updateStreamField,
globalFilterValue = "",
}) => {
const isColumnSelectionEnabled = useExperiment("connection.columnSelection", true);
const isColumnSelectionEnabled = useExperiment("connection.columnSelection");
const { formatMessage } = useIntl();
const { mode } = useConnectionFormService();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ export const ConnectionOnboarding: React.FC<ConnectionOnboardingProps> = () => {
const [highlightedSource, setHighlightedSource] = useState<HighlightIndex>(1);
const [highlightedDestination, setHighlightedDestination] = useState<HighlightIndex>(0);

const sourceIds = useExperiment("connection.onboarding.sources", "").split(",");
const destinationIds = useExperiment("connection.onboarding.destinations", "").split(",");
const sourceIds = useExperiment("connection.onboarding.sources").split(",");
const destinationIds = useExperiment("connection.onboarding.destinations").split(",");

const createConnectionPath = `/${RoutePaths.Workspaces}/${workspaceId}/${RoutePaths.Connections}/${ConnectionRoutePaths.ConnectionNew}`;
const createDestinationBasePath = `/${RoutePaths.Workspaces}/${workspaceId}/${RoutePaths.Destination}/${DestinationPaths.SelectDestinationNew}`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const SimplifiedConnectionConfiguration: React.FC = () => {

const SimplifiedConnectionCreationReplication: React.FC = () => {
useTrackPage(PageTrackingCodes.CONNECTIONS_NEW_SELECT_STREAMS);
const isSyncCatalogV2Enabled = useExperiment("connection.syncCatalogV2", false);
const isSyncCatalogV2Enabled = useExperiment("connection.syncCatalogV2");
const { formatMessage } = useIntl();
const { isDirty } = useFormState<FormConnectionFormValues>();
const { trackFormChange } = useFormChangeTrackerService();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useConnectionFormService } from "hooks/services/ConnectionForm/Connecti
import { useExperiment } from "hooks/services/Experiment";

export const FreeHistoricalSyncIndicator: React.FC = () => {
const isFreeHistoricalSyncEnabled = useExperiment("billing.early-sync-enabled", false);
const isFreeHistoricalSyncEnabled = useExperiment("billing.early-sync-enabled");
const {
connection: { createdAt: connectionCreatedAt },
} = useConnectionFormService();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const StreamFieldsTable: React.FC<StreamFieldsTableProps> = ({
toggleAllFieldsSelected,
}) => {
const { formatMessage } = useIntl();
const isColumnSelectionEnabled = useExperiment("connection.columnSelection", true);
const isColumnSelectionEnabled = useExperiment("connection.columnSelection");
const checkIsCursor = useCallback((path: string[]) => isCursor(config, path), [config]);
const checkIsChildFieldCursor = useCallback((path: string[]) => isChildFieldCursor(config, path), [config]);
const checkIsPrimaryKey = useCallback((path: string[]) => isPrimaryKey(config, path), [config]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const BaseConnectorInfo: React.FC<BaseConnectorInfoProps> = ({
name,
documentationUrl,
}) => {
const isContributeEditsEnabled = useExperiment("connectorBuilder.contributeEditsToMarketplace", false);
const isContributeEditsEnabled = useExperiment("connectorBuilder.contributeEditsToMarketplace");
if (!isContributeEditsEnabled) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const AIButton = (props: ButtonProps) => {
};

const AssistConfigButton = () => {
const isAIEnabled = useExperiment("connectorBuilder.aiAssist.enabled", false);
const isAIEnabled = useExperiment("connectorBuilder.aiAssist.enabled");

const { x, y, reference, floating, strategy } = useFloating({
middleware: [offset(5), flip()],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ const ConnectorImageNameInput: React.FC<{
const [footer, setFooter] = useState<string | null>(null);
const { getCachedCheck, fetchContributionCheck } = useBuilderCheckContribution();

const isContributeEditsEnabled = useExperiment("connectorBuilder.contributeEditsToMarketplace", false);
const isContributeEditsEnabled = useExperiment("connectorBuilder.contributeEditsToMarketplace");

const updateErrorAndFooter = useCallback(
(contributionCheck: CheckContributionRead) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { act, renderHook } from "@testing-library/react";
import React from "react";
import { EMPTY, Subject } from "rxjs";

import { Experiments } from "./experiments";
import { Experiments, defaultExperimentValues } from "./experiments";
import { ExperimentProvider, ExperimentService, useExperiment } from "./ExperimentService";

type TestExperimentValueType = Experiments["connector.airbyteCloudIpAddresses"];
Expand All @@ -22,6 +22,10 @@ const removeContext = jest.fn();

describe("ExperimentService", () => {
describe("useExperiment", () => {
afterEach(() => {
jest.restoreAllMocks();
});

it("should return the value from the ExperimentService if provided", () => {
const wrapper: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => (
<ExperimentProvider
Expand All @@ -36,11 +40,12 @@ describe("ExperimentService", () => {
{children}
</ExperimentProvider>
);
const { result } = renderHook(() => useExperiment(TEST_EXPERIMENT_KEY, "10.42.0.0"), { wrapper });
const { result } = renderHook(() => useExperiment(TEST_EXPERIMENT_KEY), { wrapper });
expect(result.current).toEqual("10.0.0.0,10.1.0.0");
});

it("should return the defaultValue if ExperimentService provides undefined", () => {
jest.replaceProperty(defaultExperimentValues, "connector.airbyteCloudIpAddresses", "10.42.0.0");
const wrapper: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => (
<ExperimentProvider
value={{
Expand All @@ -55,12 +60,13 @@ describe("ExperimentService", () => {
{children}
</ExperimentProvider>
);
const { result } = renderHook(() => useExperiment(TEST_EXPERIMENT_KEY, "10.42.0.0"), { wrapper });
const { result } = renderHook(() => useExperiment(TEST_EXPERIMENT_KEY), { wrapper });
expect(result.current).toEqual("10.42.0.0");
});

it("should return the default value if no ExperimentService is provided", () => {
const { result } = renderHook(() => useExperiment(TEST_EXPERIMENT_KEY, "10.42.0.0"));
jest.replaceProperty(defaultExperimentValues, "connector.airbyteCloudIpAddresses", "10.42.0.0");
const { result } = renderHook(() => useExperiment(TEST_EXPERIMENT_KEY));
expect(result.current).toEqual("10.42.0.0");
});

Expand All @@ -80,7 +86,7 @@ describe("ExperimentService", () => {
{children}
</ExperimentProvider>
);
const { result } = renderHook(() => useExperiment(TEST_EXPERIMENT_KEY, "10.42.0.0"), {
const { result } = renderHook(() => useExperiment(TEST_EXPERIMENT_KEY), {
wrapper,
});
expect(result.current).toEqual("10.0.0.0,10.1.0.0");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { Experiments } from "./experiments";

import { createContext, useCallback, useContext, useEffect, useMemo } from "react";
import { useObservable } from "react-use";
import { EMPTY, Observable } from "rxjs";

import { isDevelopment } from "core/utils/isDevelopment";

import { defaultExperimentValues, type Experiments } from "./experiments";

export type ContextKind =
| "user"
| "organization"
Expand Down Expand Up @@ -64,7 +64,7 @@ export const useExperimentContext = (kind: Exclude<ContextKind, "user">, key: st
}, [kind, key, experimentService]);
};

function useExperimentHook<K extends keyof Experiments>(key: K, defaultValue: Experiments[K]): Experiments[K] {
function useExperimentHook<K extends keyof Experiments>(key: K): Experiments[K] {
const hasWindowOverwrites = window.hasOwnProperty("_e2eOverwrites");
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const windowOverwriteValue = hasWindowOverwrites ? (window as any)._e2eOverwrites[key] : undefined;
Expand All @@ -79,17 +79,14 @@ function useExperimentHook<K extends keyof Experiments>(key: K, defaultValue: Ex
const initialValue =
windowOverwriteValue !== undefined
? windowOverwriteValue
: experimentService?.getExperiment(key, defaultValue) ?? defaultValue;
: experimentService?.getExperiment(key, defaultExperimentValues[key]) ?? defaultExperimentValues[key];

return useObservable(onChanges$, initialValue);
}

function useExperimentWithOverwrites<K extends keyof Experiments>(
key: K,
defaultValue: Experiments[K]
): Experiments[K] {
function useExperimentWithOverwrites<K extends keyof Experiments>(key: K): Experiments[K] {
// Load the regular experiments value via the prod hook
const value = useExperimentHook(key, defaultValue);
const value = useExperimentHook(key);
// Use the overwrite value if it's available, otherwise the proper value
return key in devOverwrites ? (devOverwrites[key] as Experiments[K]) : value;
}
Expand Down
25 changes: 25 additions & 0 deletions airbyte-webapp/src/hooks/services/Experiment/experiments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,28 @@ export interface Experiments {
"billing.organizationBillingPage": boolean;
"billing.workspaceUsagePage": boolean;
}

export const defaultExperimentValues: Experiments = {
"authPage.rightSideUrl": undefined,
"billing.autoRecharge": false,
"billing.early-sync-enabled": false,
"billing.organizationBillingPage": false,
"billing.workspaceUsagePage": false,
"connection.columnSelection": true,
"connection.hashingUI": false,
"connection.onboarding.destinations": "",
"connection.onboarding.sources": "",
"connection.rateLimitedUI": false,
"connection.syncCatalogV2": false,
"connection.timeline": false,
"connection.timeline.schemaUpdates": false,
"connector.airbyteCloudIpAddresses":
"34.106.109.131, 34.106.196.165, 34.106.60.246, 34.106.229.69, 34.106.127.139, 34.106.218.58, 34.106.115.240, 34.106.225.141, 13.37.4.46, 13.37.142.60, 35.181.124.238",
"connector.suggestedDestinationConnectors": "",
"connector.suggestedSourceConnectors": "",
"connectorBuilder.aiAssist.enabled": false,
"connectorBuilder.contributeEditsToMarketplace": false,
"settings.breakingChangeNotifications": false,
"settings.showAdvancedSettings": false,
"upcomingFeaturesPage.url": "",
};
1 change: 1 addition & 0 deletions airbyte-webapp/src/hooks/services/Experiment/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { defaultExperimentValues } from "./experiments";
export { useExperiment, ExperimentProvider, useExperimentContext, useGetAllExperiments } from "./ExperimentService";
export type { ExperimentService, ContextKind } from "./ExperimentService";
4 changes: 2 additions & 2 deletions airbyte-webapp/src/packages/cloud/cloudRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ const AdvancedSettingsPage = React.lazy(() => import("pages/SettingsPage/pages/A
const MainRoutes: React.FC = () => {
const workspace = useCurrentWorkspace();
const canViewOrgSettings = useIntent("ViewOrganizationSettings", { organizationId: workspace.organizationId });
const isOrganizationBillingPageVisible = useExperiment("billing.organizationBillingPage", false);
const isWorkspaceUsagePageVisible = useExperiment("billing.workspaceUsagePage", false);
const isOrganizationBillingPageVisible = useExperiment("billing.organizationBillingPage");
const isWorkspaceUsagePageVisible = useExperiment("billing.workspaceUsagePage");

useExperimentContext("organization", workspace.organizationId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import styles from "./UpcomingFeaturesPage.module.scss";
const UpcomingFeaturesPage = () => {
const { formatMessage } = useIntl();
const user = useCurrentUser();
const url = useExperiment("upcomingFeaturesPage.url", "");
const url = useExperiment("upcomingFeaturesPage.url");
return (
<>
<HeadTitle titles={[{ id: "upcomingFeatures.title" }]} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const hasValidRightSideUrl = (url?: string): boolean => {

export const AuthLayout: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
const { formatMessage } = useIntl();
const rightSideUrl = useExperiment("authPage.rightSideUrl", undefined);
const rightSideUrl = useExperiment("authPage.rightSideUrl");

return (
<FlexContainer className={styles.container}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const LowCreditBalanceHint: React.FC = () => {
export const BillingBanners: React.FC = () => {
const { emailVerified } = useAuthService();

const isAutoRechargeEnabled = useExperiment("billing.autoRecharge", false);
const isAutoRechargeEnabled = useExperiment("billing.autoRecharge");

return (
<FlexContainer direction="column">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useExperiment } from "hooks/services/Experiment";
export const BillingBanners: React.FC = () => {
const { formatMessage } = useIntl();
const { billing } = useCurrentOrganizationInfo();
const isAutoRechargeEnabled = useExperiment("billing.autoRecharge", false);
const isAutoRechargeEnabled = useExperiment("billing.autoRecharge");

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export const CloudSettingsPage: React.FC = () => {
const supportsDataResidency = useFeature(FeatureItem.AllowChangeDataGeographies);
const workspace = useCurrentWorkspace();
const canViewOrgSettings = useIntent("ViewOrganizationSettings", { organizationId: workspace.organizationId });
const showAdvancedSettings = useExperiment("settings.showAdvancedSettings", false);
const isOrganizationBillingPageVisible = useExperiment("billing.organizationBillingPage", false);
const isWorkspaceUsagePageVisible = useExperiment("billing.workspaceUsagePage", false);
const showAdvancedSettings = useExperiment("settings.showAdvancedSettings");
const isOrganizationBillingPageVisible = useExperiment("billing.organizationBillingPage");
const isWorkspaceUsagePageVisible = useExperiment("billing.workspaceUsagePage");
const canManageOrganizationBilling = useGeneratedIntent("ManageOrganizationBilling");

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const ConnectionPageHeader = () => {
const { formatMessage } = useIntl();
const currentTab = params["*"] || ConnectionRoutePaths.Status;
const supportsDbtCloud = useFeature(FeatureItem.AllowDBTCloudIntegration);
const connectionTimeline = useExperiment("connection.timeline", false);
const connectionTimeline = useExperiment("connection.timeline");

const { connection, schemaRefreshing } = useConnectionEditService();
const breadcrumbsData = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const relevantConnectionKeys = [
export const ConnectionReplicationPage: React.FC = () => {
useTrackPage(PageTrackingCodes.CONNECTIONS_ITEM_REPLICATION);
const [scrollElement, setScrollElement] = useState<HTMLDivElement | undefined>();
const isSyncCatalogV2Enabled = useExperiment("connection.syncCatalogV2", false);
const isSyncCatalogV2Enabled = useExperiment("connection.syncCatalogV2");
const { trackSchemaEdit } = useAnalyticsTrackFunctions();

const getStateType = useGetStateTypeQuery();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
} from "../types";

export const EventLineItem: React.FC<{ event: ConnectionEvent | InferType<typeof jobRunningSchema> }> = ({ event }) => {
const showSchemaUpdates = useExperiment("connection.timeline.schemaUpdates", false);
const showSchemaUpdates = useExperiment("connection.timeline.schemaUpdates");

if (jobRunningSchema.isValidSync(event, { recursive: true, stripUnknown: true })) {
return (
Expand Down
2 changes: 1 addition & 1 deletion airbyte-webapp/src/pages/connections/ConnectionsRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const JobHistoryToTimelineRedirect = () => {
};

export const ConnectionsRoutes: React.FC = () => {
const showTimeline = useExperiment("connection.timeline", false);
const showTimeline = useExperiment("connection.timeline");

return (
<Suspense fallback={<LoadingPage />}>
Expand Down
Loading

0 comments on commit de12f14

Please sign in to comment.