Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions apps/desktop/src/renderer/hooks/useIsV2CloudEnabled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FEATURE_FLAGS } from "@superset/shared/constants";
import { useFeatureFlagEnabled } from "posthog-js/react";
import { useV2LocalOverrideStore } from "renderer/stores/v2-local-override";

/**
* Returns effective v2 state: remote PostHog flag AND local override.
* Also returns the raw remote flag so the toggle can be shown conditionally.
*/
export function useIsV2CloudEnabled() {
const remoteV2Enabled =
useFeatureFlagEnabled(FEATURE_FLAGS.V2_CLOUD) ?? false;
const forceV1 = useV2LocalOverrideStore((s) => s.forceV1);

return {
/** The effective value — use this wherever you previously checked the flag directly. */
isV2CloudEnabled: remoteV2Enabled && !forceV1,
/** Whether the remote PostHog flag is on (for showing the toggle). */
isRemoteV2Enabled: remoteV2Enabled,
};
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { FEATURE_FLAGS } from "@superset/shared/constants";
import { useMatchRoute, useParams } from "@tanstack/react-router";
import { useFeatureFlagEnabled } from "posthog-js/react";
import { HiOutlineWifi } from "react-icons/hi2";
import { useIsV2CloudEnabled } from "renderer/hooks/useIsV2CloudEnabled";
import { useOnlineStatus } from "renderer/hooks/useOnlineStatus";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { getWorkspaceDisplayName } from "renderer/lib/getWorkspaceDisplayName";
Expand All @@ -14,6 +13,7 @@ import { SearchBarTrigger } from "./components/SearchBarTrigger";
import { SidebarToggle } from "./components/SidebarToggle";
import { V2WorkspaceOpenInButton } from "./components/V2WorkspaceOpenInButton";
import { V2WorkspaceSearchBarTrigger } from "./components/V2WorkspaceSearchBarTrigger";
import { VersionToggle } from "./components/VersionToggle";
import { WindowControls } from "./components/WindowControls";

export function TopBar() {
Expand All @@ -31,8 +31,7 @@ export function TopBar() {
{ enabled: !!workspaceId && !isV2WorkspaceRoute },
);
const isOnline = useOnlineStatus();
const isV2CloudEnabled =
useFeatureFlagEnabled(FEATURE_FLAGS.V2_CLOUD) ?? false;
const { isV2CloudEnabled, isRemoteV2Enabled } = useIsV2CloudEnabled();
// Default to Mac layout while loading to avoid overlap with traffic lights
const isMac = platform === undefined || platform === "darwin";

Expand All @@ -47,6 +46,7 @@ export function TopBar() {
<SidebarToggle />
<NavigationControls />
<ResourceConsumption />
{isRemoteV2Enabled && <VersionToggle />}
</div>

{isV2WorkspaceRoute ? (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip";
import { cn } from "@superset/ui/utils";
import { useV2LocalOverrideStore } from "renderer/stores/v2-local-override";

export function VersionToggle() {
const { forceV1, toggle } = useV2LocalOverrideStore();
const activeVersion = forceV1 ? "v1" : "v2";

return (
<Tooltip delayDuration={300}>
<TooltipTrigger asChild>
<button
type="button"
onClick={toggle}
className="no-drag flex items-center h-6 rounded-full bg-muted border border-border text-[11px] font-medium overflow-hidden transition-colors"
Comment on lines +11 to +15
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Segmented control acts as a blind toggle, not a selector

The entire <button> has a single onClick={toggle}. This means clicking the already-active segment also flips to the other version, which is unexpected UX for a segmented control — users expect clicking the active segment to be a no-op.

Consider splitting into two independent <button> elements that each set an explicit target state instead of toggling:

<button
  type="button"
  onClick={() => useV2LocalOverrideStore.getState().setForceV1(true)}
  className={cn("px-2 py-0.5 rounded-full transition-colors", forceV1 ? "bg-foreground text-background" : "text-muted-foreground hover:text-foreground")}
>
  v1
</button>
<button
  type="button"
  onClick={() => useV2LocalOverrideStore.getState().setForceV1(false)}
  className={cn("px-2 py-0.5 rounded-full transition-colors", !forceV1 ? "bg-foreground text-background" : "text-muted-foreground hover:text-foreground")}
>
  v2
</button>

This would require adding a setForceV1(value: boolean) action alongside toggle in the store.

Comment thread
Kitenite marked this conversation as resolved.
>
<span
className={cn(
"px-2 py-0.5 rounded-full transition-colors",
activeVersion === "v1"
? "bg-foreground text-background"
: "text-muted-foreground hover:text-foreground",
)}
>
v1
</span>
<span
className={cn(
"px-2 py-0.5 rounded-full transition-colors",
activeVersion === "v2"
? "bg-foreground text-background"
: "text-muted-foreground hover:text-foreground",
)}
>
v2
</span>
</button>
</TooltipTrigger>
<TooltipContent>
{forceV1
? "Early Access: Switch to Superset V2"
: "Switch to Superset V1"}
</TooltipContent>
Comment thread
Kitenite marked this conversation as resolved.
</Tooltip>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { VersionToggle } from "./VersionToggle";
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { FEATURE_FLAGS } from "@superset/shared/constants";
import {
createFileRoute,
Outlet,
useMatchRoute,
useNavigate,
} from "@tanstack/react-router";
import { useFeatureFlagEnabled } from "posthog-js/react";
import { useState } from "react";
import { useIsV2CloudEnabled } from "renderer/hooks/useIsV2CloudEnabled";
import { useHotkey } from "renderer/hotkeys";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { DashboardSidebar } from "renderer/routes/_authenticated/_dashboard/components/DashboardSidebar";
Expand All @@ -29,8 +28,7 @@ export const Route = createFileRoute("/_authenticated/_dashboard")({
function DashboardLayout() {
const navigate = useNavigate();
const openNewWorkspaceModal = useOpenNewWorkspaceModal();
const isV2CloudEnabled =
useFeatureFlagEnabled(FEATURE_FLAGS.V2_CLOUD) ?? false;
const { isV2CloudEnabled } = useIsV2CloudEnabled();
// Get current workspace from route to pre-select project in new workspace modal
const matchRoute = useMatchRoute();
const currentWorkspaceMatch = matchRoute({
Expand Down
6 changes: 2 additions & 4 deletions apps/desktop/src/renderer/routes/_authenticated/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { FEATURE_FLAGS } from "@superset/shared/constants";
import { Button } from "@superset/ui/button";
import { Spinner } from "@superset/ui/spinner";
import {
Expand All @@ -8,14 +7,14 @@ import {
useLocation,
useNavigate,
} from "@tanstack/react-router";
import { useFeatureFlagEnabled } from "posthog-js/react";
import { useEffect, useRef } from "react";
import { DndProvider } from "react-dnd";
import { HiOutlineWifi } from "react-icons/hi2";
import { NewWorkspaceModal } from "renderer/components/NewWorkspaceModal";
import { Paywall } from "renderer/components/Paywall";
import { useUpdateListener } from "renderer/components/UpdateToast";
import { env } from "renderer/env.renderer";
import { useIsV2CloudEnabled } from "renderer/hooks/useIsV2CloudEnabled";
import { useOnlineStatus } from "renderer/hooks/useOnlineStatus";
import { migrateHotkeyOverrides } from "renderer/hotkeys/migrate";
import { authClient, getAuthToken } from "renderer/lib/auth-client";
Expand Down Expand Up @@ -55,8 +54,7 @@ function AuthenticatedLayout() {
const setOriginRoute = useSettingsStore((s) => s.setOriginRoute);
const utils = electronTrpc.useUtils();
const shownWorkspaceInitWarningsRef = useRef(new Set<string>());
const isV2CloudEnabled =
useFeatureFlagEnabled(FEATURE_FLAGS.V2_CLOUD) ?? false;
const { isV2CloudEnabled } = useIsV2CloudEnabled();

const isSignedIn = env.SKIP_ENV_VALIDATION || !!session?.user;
const activeOrganizationId = env.SKIP_ENV_VALIDATION
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { FEATURE_FLAGS } from "@superset/shared/constants";
import { useFeatureFlagEnabled } from "posthog-js/react";
import type { ReactNode } from "react";
import { useIsV2CloudEnabled } from "renderer/hooks/useIsV2CloudEnabled";
import {
isItemVisible,
SETTING_ITEM_ID,
Expand Down Expand Up @@ -47,8 +46,7 @@ export function TerminalSettings({
pendingCreateProjectId,
onPendingCreateProjectIdChange,
}: TerminalSettingsProps) {
const isV2CloudEnabled =
useFeatureFlagEnabled(FEATURE_FLAGS.V2_CLOUD) ?? false;
const { isV2CloudEnabled } = useIsV2CloudEnabled();
const showPresets = isItemVisible(
SETTING_ITEM_ID.TERMINAL_PRESETS,
visibleItems,
Expand Down
21 changes: 21 additions & 0 deletions apps/desktop/src/renderer/stores/v2-local-override.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { create } from "zustand";
import { devtools, persist } from "zustand/middleware";

interface V2LocalOverrideState {
/** When true, forces v1 mode locally even though v2 is enabled remotely. */
forceV1: boolean;
toggle: () => void;
}

export const useV2LocalOverrideStore = create<V2LocalOverrideState>()(
devtools(
persist(
(set, get) => ({
forceV1: false,
toggle: () => set({ forceV1: !get().forceV1 }),
}),
{ name: "v2-local-override" },
),
{ name: "V2LocalOverrideStore" },
),
);
Loading