diff --git a/src/components/Home/PipelineSection/PipelineRow.tsx b/src/components/Home/PipelineSection/PipelineRow.tsx
index 0c1af9cca..380902a82 100644
--- a/src/components/Home/PipelineSection/PipelineRow.tsx
+++ b/src/components/Home/PipelineSection/PipelineRow.tsx
@@ -30,7 +30,7 @@ import {
import { Paragraph } from "@/components/ui/typography";
import { cn } from "@/lib/utils";
import { useAnalytics } from "@/providers/AnalyticsProvider";
-import { EDITOR_PATH } from "@/routes/router";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import { deletePipeline } from "@/services/pipelineService";
import { getPipelineTagsFromSpec } from "@/utils/annotations";
import type { ComponentReferenceWithSpec } from "@/utils/componentStore";
@@ -107,17 +107,15 @@ const PipelineRow = withSuspenseWrapper(
return;
}
+ if (!name) return;
+
if (e.ctrlKey || e.metaKey) {
- if (name) {
- rowTrack("pipeline_opened", { open_mode: "editor_new_tab" });
- }
- window.open(`${EDITOR_PATH}/${name}`, "_blank");
+ rowTrack("pipeline_opened", { open_mode: "editor_new_tab" });
+ window.open(getDefaultEditorPath(name), "_blank");
return;
}
- if (name) {
- rowTrack("pipeline_opened", { open_mode: "editor_same_tab" });
- }
- navigate({ to: `${EDITOR_PATH}/${name}` });
+ rowTrack("pipeline_opened", { open_mode: "editor_same_tab" });
+ navigate({ to: getDefaultEditorPath(name) });
};
const handleCheckboxChange = (checked: boolean | "indeterminate") => {
diff --git a/src/components/Learn/useImportPipeline.ts b/src/components/Learn/useImportPipeline.ts
index 6d9ee4288..a436a591a 100644
--- a/src/components/Learn/useImportPipeline.ts
+++ b/src/components/Learn/useImportPipeline.ts
@@ -2,7 +2,7 @@ import { useMutation } from "@tanstack/react-query";
import { useNavigate } from "@tanstack/react-router";
import useToastNotification from "@/hooks/useToastNotification";
-import { EDITOR_PATH } from "@/routes/router";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import { importPipelineFromUrl } from "./importPipelineFromUrl";
@@ -15,7 +15,7 @@ export function useImportPipeline() {
onSuccess: (result) => {
notify(`Pipeline "${result.name}" created successfully`, "success");
navigate({
- to: `${EDITOR_PATH}/${encodeURIComponent(result.name)}`,
+ to: getDefaultEditorPath(result.name),
});
},
});
diff --git a/src/components/PipelineRun/RunToolbar.tsx b/src/components/PipelineRun/RunToolbar.tsx
index 38b637db9..ef22656b0 100644
--- a/src/components/PipelineRun/RunToolbar.tsx
+++ b/src/components/PipelineRun/RunToolbar.tsx
@@ -5,6 +5,7 @@ import { useUserDetails } from "@/hooks/useUserDetails";
import { cn } from "@/lib/utils";
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
import { useExecutionData } from "@/providers/ExecutionDataProvider";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import { extractCanonicalName } from "@/utils/canonicalPipelineName";
import {
countInProgressFromStats,
@@ -30,7 +31,7 @@ export const RunToolbar = () => {
const { data: currentUserDetails } = useUserDetails();
const editorRoute = componentSpec.name
- ? `/editor/${encodeURIComponent(componentSpec.name)}`
+ ? getDefaultEditorPath(componentSpec.name)
: "";
const canAccessEditorSpec = useCheckComponentSpecFromPath(
diff --git a/src/components/PipelineRun/components/InspectPipelineButton.test.tsx b/src/components/PipelineRun/components/InspectPipelineButton.test.tsx
index 5200e67e3..35a7717f9 100644
--- a/src/components/PipelineRun/components/InspectPipelineButton.test.tsx
+++ b/src/components/PipelineRun/components/InspectPipelineButton.test.tsx
@@ -16,6 +16,6 @@ describe("", () => {
render();
const inspectButton = screen.getByTestId("inspect-pipeline-button");
act(() => fireEvent.click(inspectButton));
- expect(mockNavigate).toHaveBeenCalledWith({ to: "/editor/foo" });
+ expect(mockNavigate).toHaveBeenCalledWith({ to: "/editor-v2/foo" });
});
});
diff --git a/src/components/PipelineRun/components/InspectPipelineButton.tsx b/src/components/PipelineRun/components/InspectPipelineButton.tsx
index 3b12ebd16..db7c9ea42 100644
--- a/src/components/PipelineRun/components/InspectPipelineButton.tsx
+++ b/src/components/PipelineRun/components/InspectPipelineButton.tsx
@@ -7,6 +7,7 @@ import {
import TooltipButton from "@/components/shared/Buttons/TooltipButton";
import { Icon } from "@/components/ui/icon";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
type InspectPipelineButtonProps = {
pipelineName: string;
@@ -25,7 +26,7 @@ export const InspectPipelineButton = ({
const handleInspect = useCallback(
(e: MouseEvent) => {
- const clickThroughUrl = `/editor/${encodeURIComponent(pipelineName)}`;
+ const clickThroughUrl = getDefaultEditorPath(pipelineName);
if (e.ctrlKey || e.metaKey) {
window.open(clickThroughUrl, "_blank");
diff --git a/src/components/layout/AiModelQuickSelect.test.tsx b/src/components/layout/AiModelQuickSelect.test.tsx
index bde57d31a..0e984559b 100644
--- a/src/components/layout/AiModelQuickSelect.test.tsx
+++ b/src/components/layout/AiModelQuickSelect.test.tsx
@@ -30,6 +30,7 @@ describe("AiModelQuickSelect", () => {
});
it("does not render when both AI features are disabled", () => {
+ enableFlags({ "ai-assistant": false, "component-search-v2": false });
window.localStorage.setItem(
STORAGE_KEY,
JSON.stringify({
diff --git a/src/components/shared/EditorV2WelcomeSpotlight.tsx b/src/components/shared/EditorV2WelcomeSpotlight.tsx
new file mode 100644
index 000000000..3289eb9c1
--- /dev/null
+++ b/src/components/shared/EditorV2WelcomeSpotlight.tsx
@@ -0,0 +1,210 @@
+import {
+ type RefObject,
+ useEffect,
+ useLayoutEffect,
+ useRef,
+ useState,
+} from "react";
+import { createPortal } from "react-dom";
+
+import { Button } from "@/components/ui/button";
+import { BlockStack } from "@/components/ui/layout";
+import { Paragraph, Text } from "@/components/ui/typography";
+import { getStorage } from "@/utils/typedStorage";
+
+interface EditorV2WelcomeStorage {
+ "seen-editor-v2-welcome": boolean;
+}
+
+const storage = getStorage<
+ keyof EditorV2WelcomeStorage,
+ EditorV2WelcomeStorage
+>();
+const STORAGE_KEY = "seen-editor-v2-welcome";
+const SPOTLIGHT_PADDING = 16;
+const CARD_WIDTH = 320;
+const SPOTLIGHT_COLOR = "#5B35F5";
+const SPOTLIGHT_HALO_COLOR = "rgba(91, 53, 245, 0.35)";
+
+interface SpotlightRect {
+ centerX: number;
+ centerY: number;
+ radius: number;
+}
+
+export function hasSeenEditorV2Welcome(): boolean {
+ return storage.getItem(STORAGE_KEY) === true;
+}
+
+export function markEditorV2WelcomeSeen() {
+ storage.setItem(STORAGE_KEY, true);
+}
+
+function clamp(value: number, min: number, max: number): number {
+ return Math.min(Math.max(value, min), max);
+}
+
+function getSpotlightRect(target: HTMLElement): SpotlightRect {
+ const rect = target.getBoundingClientRect();
+ return {
+ centerX: rect.left + rect.width / 2,
+ centerY: rect.top + rect.height / 2,
+ radius: Math.max(rect.width, rect.height) / 2 + SPOTLIGHT_PADDING,
+ };
+}
+
+interface ClickBlockersProps {
+ spotlight: SpotlightRect;
+ onDismiss: () => void;
+}
+
+function ClickBlockers({ spotlight, onDismiss }: ClickBlockersProps) {
+ const { centerX, centerY, radius } = spotlight;
+ const top = Math.max(centerY - radius, 0);
+ const bottom = Math.min(centerY + radius, window.innerHeight);
+ const left = Math.max(centerX - radius, 0);
+ const right = Math.min(centerX + radius, window.innerWidth);
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
+
+interface EditorV2WelcomeSpotlightProps {
+ targetRef: RefObject;
+ onDismiss: () => void;
+}
+
+export function EditorV2WelcomeSpotlight({
+ targetRef,
+ onDismiss,
+}: EditorV2WelcomeSpotlightProps) {
+ const [spotlight, setSpotlight] = useState(null);
+ const gotItRef = useRef(null);
+
+ useLayoutEffect(() => {
+ const update = () => {
+ if (!targetRef.current) return;
+ setSpotlight(getSpotlightRect(targetRef.current));
+ };
+
+ update();
+ const animationFrame = window.requestAnimationFrame(update);
+ window.addEventListener("resize", update);
+ window.addEventListener("scroll", update, true);
+
+ return () => {
+ window.cancelAnimationFrame(animationFrame);
+ window.removeEventListener("resize", update);
+ window.removeEventListener("scroll", update, true);
+ };
+ }, [targetRef]);
+
+ useEffect(() => {
+ gotItRef.current?.focus();
+
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === "Escape") {
+ onDismiss();
+ return;
+ }
+ if (event.key === "Tab") {
+ event.preventDefault();
+ gotItRef.current?.focus();
+ }
+ };
+
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [onDismiss]);
+
+ if (!spotlight) return null;
+
+ const cardTop = clamp(
+ spotlight.centerY + spotlight.radius + 16,
+ 16,
+ window.innerHeight - 180,
+ );
+ const cardLeft = clamp(
+ spotlight.centerX - CARD_WIDTH / 2,
+ 16,
+ window.innerWidth - CARD_WIDTH - 16,
+ );
+
+ return createPortal(
+ <>
+
+
+
+
+
+
+
+ Welcome to the new editor
+
+
+ You can easily switch between the new and old editor here.
+
+
+
+
+
+ >,
+ document.body,
+ );
+}
diff --git a/src/components/shared/EditorVersionToggle.tsx b/src/components/shared/EditorVersionToggle.tsx
index 35ced979e..7a85e5f30 100644
--- a/src/components/shared/EditorVersionToggle.tsx
+++ b/src/components/shared/EditorVersionToggle.tsx
@@ -1,7 +1,14 @@
import { useLocation, useNavigate } from "@tanstack/react-router";
+import { useCallback, useRef, useState } from "react";
import TooltipButton from "@/components/shared/Buttons/TooltipButton";
+import {
+ EditorV2WelcomeSpotlight,
+ hasSeenEditorV2Welcome,
+ markEditorV2WelcomeSeen,
+} from "@/components/shared/EditorV2WelcomeSpotlight";
import { Icon } from "@/components/ui/icon";
+import { cn } from "@/lib/utils";
import { APP_ROUTES, EDITOR_PATH } from "@/routes/router";
import { useFlagValue } from "./Settings/useFlags";
@@ -18,6 +25,13 @@ export const EditorVersionToggle = () => {
const location = useLocation();
const navigate = useNavigate();
const isEnabled = useFlagValue("v2_editor");
+ const toggleRef = useRef(null);
+ const [welcomeSeen, setWelcomeSeen] = useState(hasSeenEditorV2Welcome);
+
+ const dismissWelcome = useCallback(() => {
+ markEditorV2WelcomeSeen();
+ setWelcomeSeen(true);
+ }, []);
if (!isEnabled) return null;
@@ -35,14 +49,28 @@ export const EditorVersionToggle = () => {
: `${EDITOR_PATH}/${encodeURIComponent(pipelineName)}`;
const tooltip =
targetVersion === "v2" ? "Switch to new editor" : "Switch to legacy editor";
+ const showWelcome = version === "v2" && !welcomeSeen;
return (
- navigate({ to: targetPath })}
- aria-label={tooltip}
- >
-
-
+ <>
+ {
+ if (showWelcome) dismissWelcome();
+ navigate({ to: targetPath });
+ }}
+ aria-label={tooltip}
+ >
+
+
+ {showWelcome && (
+
+ )}
+ >
);
};
diff --git a/src/components/shared/ImportPipeline.tsx b/src/components/shared/ImportPipeline.tsx
index eb97ed5a1..9438d8455 100644
--- a/src/components/shared/ImportPipeline.tsx
+++ b/src/components/shared/ImportPipeline.tsx
@@ -19,7 +19,7 @@ import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import { useAnalytics } from "@/providers/AnalyticsProvider";
-import { EDITOR_PATH } from "@/routes/router";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import {
importPipelineFromFile,
importPipelineFromYaml,
@@ -63,7 +63,7 @@ const ImportPipeline = ({
onImportComplete(importedPipeline);
} else {
navigate({
- to: `${EDITOR_PATH}/${encodeURIComponent(importedPipeline.name)}`,
+ to: getDefaultEditorPath(importedPipeline.name),
});
}
};
diff --git a/src/components/shared/NewPipelineButton.tsx b/src/components/shared/NewPipelineButton.tsx
index e8c4e26af..3721e60b2 100644
--- a/src/components/shared/NewPipelineButton.tsx
+++ b/src/components/shared/NewPipelineButton.tsx
@@ -3,7 +3,7 @@ import { generate } from "random-words";
import type { MouseEvent, ReactNode } from "react";
import { Button, type ButtonProps } from "@/components/ui/button";
-import { EDITOR_PATH } from "@/routes/router";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import { writeComponentToFileListFromText } from "@/utils/componentStore";
import {
defaultPipelineYamlWithName,
@@ -32,7 +32,7 @@ const NewPipelineButton = ({
componentText,
);
- const clickThroughUrl = `${EDITOR_PATH}/${encodeURIComponent(name)}`;
+ const clickThroughUrl = getDefaultEditorPath(name);
if (e.ctrlKey || e.metaKey) {
window.open(clickThroughUrl, "_blank");
diff --git a/src/flags.ts b/src/flags.ts
index 88e05ac27..65099b862 100644
--- a/src/flags.ts
+++ b/src/flags.ts
@@ -67,7 +67,7 @@ export const ExistingFlags: ConfigFlags = {
name: "Component Search",
description:
"Show the experimental component search that searches across standard, published, registered, and user component sources, with optional AI rerank.",
- default: false,
+ default: true,
category: "beta",
},
diff --git a/src/routes/Dashboard/TypePill.tsx b/src/routes/Dashboard/TypePill.tsx
index 24aefb9e9..c6b35c5d4 100644
--- a/src/routes/Dashboard/TypePill.tsx
+++ b/src/routes/Dashboard/TypePill.tsx
@@ -2,7 +2,8 @@ import { Icon, type IconName } from "@/components/ui/icon";
import type { FavoriteItem } from "@/hooks/useFavorites";
import type { RecentlyViewedItem } from "@/hooks/useRecentlyViewed";
import { cn } from "@/lib/utils";
-import { APP_ROUTES, EDITOR_PATH, RUNS_BASE_PATH } from "@/routes/router";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
+import { APP_ROUTES, RUNS_BASE_PATH } from "@/routes/router";
type ItemType = "pipeline" | "run" | "component";
@@ -50,12 +51,12 @@ export const TypePill = ({
};
export function getFavoriteUrl(item: FavoriteItem): string {
- if (item.type === "pipeline") return `${EDITOR_PATH}/${item.id}`;
+ if (item.type === "pipeline") return getDefaultEditorPath(item.id);
return `${RUNS_BASE_PATH}/${item.id}`;
}
export function getRecentlyViewedUrl(item: RecentlyViewedItem): string {
- if (item.type === "pipeline") return `${EDITOR_PATH}/${item.id}`;
+ if (item.type === "pipeline") return getDefaultEditorPath(item.id);
if (item.type === "run") return `${RUNS_BASE_PATH}/${item.id}`;
return APP_ROUTES.DASHBOARD_COMPONENTS;
}
diff --git a/src/routes/Import/Import.test.tsx b/src/routes/Import/Import.test.tsx
index 819b44f68..a2be0a0b2 100644
--- a/src/routes/Import/Import.test.tsx
+++ b/src/routes/Import/Import.test.tsx
@@ -142,7 +142,7 @@ describe("ImportPage", () => {
await waitFor(() => {
expect(mockNavigate).toHaveBeenCalledWith({
- to: "/editor/Test%20Pipeline",
+ to: "/editor-v2/Test%20Pipeline",
});
});
});
diff --git a/src/routes/Import/index.tsx b/src/routes/Import/index.tsx
index fd84ffd6b..69c504480 100644
--- a/src/routes/Import/index.tsx
+++ b/src/routes/Import/index.tsx
@@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button";
import { BlockStack, InlineStack } from "@/components/ui/layout";
import { Spinner } from "@/components/ui/spinner";
import { Paragraph, Text } from "@/components/ui/typography";
-import { EDITOR_PATH } from "@/routes/router";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import { importPipelineFromYaml } from "@/services/pipelineService";
/**
@@ -202,7 +202,7 @@ export const ImportPage = () => {
setPipelineName(result.name);
setStep(Step.Done);
navigate({
- to: `${EDITOR_PATH}/${encodeURIComponent(result.name)}`,
+ to: getDefaultEditorPath(result.name),
});
} else {
setError(result.errorMessage || "Failed to import pipeline from URL.");
diff --git a/src/routes/editorRoutes.ts b/src/routes/editorRoutes.ts
new file mode 100644
index 000000000..347a7c1c2
--- /dev/null
+++ b/src/routes/editorRoutes.ts
@@ -0,0 +1,17 @@
+import { isFlagEnabled } from "@/components/shared/Settings/useFlags";
+
+import { APP_ROUTES, EDITOR_PATH } from "./appRoutes";
+
+function getLegacyEditorPath(pipelineName: string): string {
+ return `${EDITOR_PATH}/${encodeURIComponent(pipelineName)}`;
+}
+
+function getEditorV2Path(pipelineName: string): string {
+ return `${APP_ROUTES.EDITOR_V2}/${encodeURIComponent(pipelineName)}`;
+}
+
+export function getDefaultEditorPath(pipelineName: string): string {
+ return isFlagEnabled("v2_editor")
+ ? getEditorV2Path(pipelineName)
+ : getLegacyEditorPath(pipelineName);
+}
diff --git a/src/routes/router.ts b/src/routes/router.ts
index fd9aaf68e..0cde964f2 100644
--- a/src/routes/router.ts
+++ b/src/routes/router.ts
@@ -288,12 +288,25 @@ const editorV2Route = createRoute({
getParentRoute: () => mainLayout,
path: APP_ROUTES.EDITOR_V2,
component: EditorV2,
+ beforeLoad: () => {
+ if (!isFlagEnabled("v2_editor")) {
+ throw redirect({ to: APP_ROUTES.DASHBOARD_PIPELINES });
+ }
+ },
});
const editorV2PipelineRoute = createRoute({
getParentRoute: () => mainLayout,
path: APP_ROUTES.EDITOR_V2_PIPELINE,
component: EditorV2,
+ beforeLoad: ({ params }) => {
+ if (!isFlagEnabled("v2_editor")) {
+ throw redirect({
+ to: APP_ROUTES.PIPELINE_EDITOR,
+ params: { name: params.pipelineName },
+ });
+ }
+ },
});
const runV2Route = createRoute({
diff --git a/src/routes/v2/pages/RunView/components/RunViewMenuBar/components/RunMenu.tsx b/src/routes/v2/pages/RunView/components/RunViewMenuBar/components/RunMenu.tsx
index ae5b68699..f0d0b6995 100644
--- a/src/routes/v2/pages/RunView/components/RunViewMenuBar/components/RunMenu.tsx
+++ b/src/routes/v2/pages/RunView/components/RunViewMenuBar/components/RunMenu.tsx
@@ -8,6 +8,7 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Icon } from "@/components/ui/icon";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import { useRunViewActions } from "@/routes/v2/pages/RunView/hooks/useRunViewActions";
import { MenuTriggerButton } from "@/routes/v2/shared/components/MenuTriggerButton";
import { tracking } from "@/utils/tracking";
@@ -41,7 +42,7 @@ export function RunMenu() {
const handleInspect = () => {
if (pipelineName) {
- navigate({ to: `/editor/${encodeURIComponent(pipelineName)}` });
+ navigate({ to: getDefaultEditorPath(pipelineName) });
}
};
diff --git a/src/routes/v2/pages/RunView/hooks/useRunViewActions.ts b/src/routes/v2/pages/RunView/hooks/useRunViewActions.ts
index 5b5e8c725..7ac2be45d 100644
--- a/src/routes/v2/pages/RunView/hooks/useRunViewActions.ts
+++ b/src/routes/v2/pages/RunView/hooks/useRunViewActions.ts
@@ -8,6 +8,7 @@ import { useCheckComponentSpecFromPath } from "@/hooks/useCheckComponentSpecFrom
import { useUserDetails } from "@/hooks/useUserDetails";
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
import { useExecutionData } from "@/providers/ExecutionDataProvider";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import { extractCanonicalName } from "@/utils/canonicalPipelineName";
import type { ComponentSpec } from "@/utils/componentSpec";
import {
@@ -80,7 +81,7 @@ export function useRunViewActions(): RunViewActions {
const { data: currentUserDetails } = useUserDetails();
const editorRoute = componentSpec?.name
- ? `/editor/${encodeURIComponent(componentSpec.name)}`
+ ? getDefaultEditorPath(componentSpec.name)
: "";
const canAccessEditorSpec = useCheckComponentSpecFromPath(
diff --git a/src/services/pipelineRunService.ts b/src/services/pipelineRunService.ts
index 026d1b75d..e148dbc6e 100644
--- a/src/services/pipelineRunService.ts
+++ b/src/services/pipelineRunService.ts
@@ -4,7 +4,7 @@ import type {
BodyCreateApiPipelineRunsPost,
ListAnnotationsApiPipelineRunsIdAnnotationsGetResponse,
} from "@/api/types.gen";
-import { APP_ROUTES } from "@/routes/router";
+import { getDefaultEditorPath } from "@/routes/editorRoutes";
import type { PipelineRun } from "@/types/pipelineRun";
import { EDITOR_FLOW_DIRECTION_ANNOTATION } from "@/utils/annotations";
import { removeCachingStrategyFromSpec } from "@/utils/cache";
@@ -161,10 +161,8 @@ export const copyRunToPipeline = async (
componentText,
);
- const urlName = encodeURIComponent(newName);
-
return {
- url: APP_ROUTES.PIPELINE_EDITOR.replace("$name", urlName),
+ url: getDefaultEditorPath(newName),
name: newName,
};
} catch (error) {
diff --git a/tests/e2e/helpers.ts b/tests/e2e/helpers.ts
index ab96423fd..66a25fc75 100644
--- a/tests/e2e/helpers.ts
+++ b/tests/e2e/helpers.ts
@@ -5,6 +5,19 @@ import { expect, type Locator, type Page } from "@playwright/test";
* Waits for the React Flow canvas to be fully loaded (past Suspense loading state).
*/
export async function createNewPipeline(page: Page): Promise {
+ // These shared E2E helpers cover the legacy editor until v2 has matching coverage.
+ await page.addInitScript(() => {
+ const flags = JSON.parse(
+ window.localStorage.getItem("betaFlags") ?? "{}",
+ ) as Record;
+
+ window.localStorage.setItem(
+ "betaFlags",
+ JSON.stringify({ ...flags, v2_editor: false }),
+ );
+ window.localStorage.setItem("seen-editor-v2-welcome", JSON.stringify(true));
+ });
+
await page.goto("/");
await page.getByTestId("new-pipeline-button").click();
await waitForFlowCanvas(page);