From 563181c05854b41261f371404dbcd75f3d85e106 Mon Sep 17 00:00:00 2001 From: Alan Lail Date: Mon, 5 Oct 2026 11:32:06 -0400 Subject: [PATCH] Hides canvas views behind a feature flag for MVP --- apps/editor/src/ui/editor/EditorCanvas.tsx | 34 +++++++++++++------ .../src/ui/editor/components/CanvasHeader.tsx | 10 ++++-- apps/editor/src/ui/editor/featureFlags.ts | 9 +++++ 3 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 apps/editor/src/ui/editor/featureFlags.ts diff --git a/apps/editor/src/ui/editor/EditorCanvas.tsx b/apps/editor/src/ui/editor/EditorCanvas.tsx index 8690e77..7ebc016 100644 --- a/apps/editor/src/ui/editor/EditorCanvas.tsx +++ b/apps/editor/src/ui/editor/EditorCanvas.tsx @@ -19,6 +19,7 @@ import RemoteFrameworkItemsPanel from '@/ui/editor/components/RemoteFrameworkIte import AssociationTypePickerDialog from '@/ui/editor/components/AssociationTypePickerDialog' import ViewCFPackageDialog from '@/ui/editor/components/ViewCFPackageDialog' import TreePanelView from '@/ui/editor/treePanel/TreePanelView' +import { CANVAS_VIEW_ENABLED } from '@/ui/editor/featureFlags' import { CaseApiClient } from '@/infrastructure/caseApi/CaseApiClient' import { createFetchHttpClient, formatApiErrorMessage } from '@/infrastructure/caseApi/http' import { getAppConfig } from '@/app/config' @@ -31,7 +32,7 @@ import { import { useEditor } from '@/ui/editor/state/EditorContext' import { isFrameworkNode, getNodeSize } from '@/ui/editor/state/helpers/nodeGeometry' import type { CaseEditorNodeType, CaseEditorEdge } from '@/ui/editor/reactflow/types' -import type { CFDocument, CFItem, CFPackage } from '@/domain/case/types' +import type { CFAssociationGrouping, CFDocument, CFItem, CFPackage } from '@/domain/case/types' import type { HomeFramework } from '@/ui/home/frameworkStore' import { useAuth } from '@/app/providers/AuthProvider' import { fromEditorGraph } from '@/ui/editor/reactflow/mapping/fromEditorGraph' @@ -56,6 +57,8 @@ const REACT_FLOW_DEFAULT_EDGE_OPTIONS = { const REACT_FLOW_PRO_OPTIONS = { hideAttribution: true } const REACT_FLOW_BACKGROUND_STYLE = { backgroundColor: '#f0f0f2' } const minimapNodeColor = (node: CaseEditorNodeType) => (node.selected ? '#8b5cf6' : '#e2e8f0') // violet-500 if selected, slate-200 otherwise +const NO_EDGES: CaseEditorEdge[] = [] +const NO_GROUPINGS: CFAssociationGrouping[] = [] const minimapNodeStrokeColor = (node: CaseEditorNodeType) => (node.selected ? '#7c3aed' : '#cbd5e1') // violet-600 if selected, slate-300 otherwise type ReactFlowGraphProps = { @@ -325,17 +328,20 @@ export default function EditorCanvas({ onBack, onSaveToServer, onArchiveFramewor const [saveError, setSaveError] = useState(null) const [selectedRemoteEdgeIds, setSelectedRemoteEdgeIds] = useState([]) + const [activeView, setActiveView] = useState<'canvas' | 'tree'>('tree') + + // The edge derivations below exist only to feed . Skip them + // entirely while the canvas view is disabled (see featureFlags.ts) so they + // don't add per-keystroke cost to Tree View on large frameworks. const remoteLinkEdges = useMemo( - () => buildRemoteLinkEdges(nodesWithCallbacks, remoteLinks, selectedRemoteEdgeIds), + () => (CANVAS_VIEW_ENABLED ? buildRemoteLinkEdges(nodesWithCallbacks, remoteLinks, selectedRemoteEdgeIds) : NO_EDGES), [nodesWithCallbacks, remoteLinks, selectedRemoteEdgeIds], ) const allEditorEdges = useMemo( - () => [...editorEdges, ...remoteLinkEdges], + () => (CANVAS_VIEW_ENABLED ? [...editorEdges, ...remoteLinkEdges] : NO_EDGES), [editorEdges, remoteLinkEdges], ) - - const [activeView, setActiveView] = useState<'canvas' | 'tree'>('tree') const [forkWarningOpen, setForkWarningOpen] = useState(false) // Baseline Framework snapshot for fork-detection — captured once when this @@ -467,8 +473,11 @@ export default function EditorCanvas({ onBack, onSaveToServer, onArchiveFramewor await doSave(openCasePackage, framework) }, [mirrorStatus, doSave]) - // Compute in-use groupings from actual edges (for filter dropdown) + // Compute in-use groupings from actual edges (for filter dropdown). + // Pathway highlighting only affects canvas edges, so with the canvas view + // disabled the dropdown is hidden by reporting no groupings in use. const inUseGroupings = useMemo(() => { + if (!CANVAS_VIEW_ENABLED) return NO_GROUPINGS const seenIds = new Set() for (const e of editorEdges) { const gId = e.data?.cfAssociation?.CFAssociationGroupingURI?.identifier @@ -496,6 +505,7 @@ export default function EditorCanvas({ onBack, onSaveToServer, onArchiveFramewor const edgesCacheRef = useRef(new Map()) const edgesWithType = useMemo(() => { + if (!CANVAS_VIEW_ENABLED) return NO_EDGES const prev = edgesCacheRef.current const next = new Map() const globalEdgeType = settings.edgeType @@ -1748,9 +1758,9 @@ export default function EditorCanvas({ onBack, onSaveToServer, onArchiveFramewor : undefined } onOpenSettings={() => setSettingsOpen(true)} - onResetHierarchy={() => { setActiveView('canvas'); applyHierarchyLayout() }} - onResetStar={() => { setActiveView('canvas'); applyStarLayout() }} - onSwitchTreeView={() => setActiveView(activeView === 'tree' ? 'canvas' : 'tree')} + onResetHierarchy={CANVAS_VIEW_ENABLED ? () => { setActiveView('canvas'); applyHierarchyLayout() } : undefined} + onResetStar={CANVAS_VIEW_ENABLED ? () => { setActiveView('canvas'); applyStarLayout() } : undefined} + onSwitchTreeView={CANVAS_VIEW_ENABLED ? () => setActiveView(activeView === 'tree' ? 'canvas' : 'tree') : undefined} activeView={activeView} cfAssociationGroupings={inUseGroupings} activeGroupingFilter={activeGroupingFilter} @@ -1770,7 +1780,9 @@ export default function EditorCanvas({ onBack, onSaveToServer, onArchiveFramewor ) : null} - + /> : null}