mirror of
https://github.com/stablyai/orca.git
synced 2026-10-16 16:03:26 +00:00
Resolve lazy modal mounts before commit
This commit is contained in:
+14
-29
@@ -128,6 +128,7 @@ import {
|
||||
} from '../../shared/keybindings'
|
||||
import { isGitRepoKind } from '../../shared/repo-kind'
|
||||
import { showTerminalShortcutCaptureNotification } from '@/lib/terminal-shortcut-capture-notification'
|
||||
import { resolveMountedLazyModalIds, type LazyModalId } from './lazy-modal-mount-state'
|
||||
|
||||
const isMac = navigator.userAgent.includes('Mac')
|
||||
const isWindows = !isMac && navigator.userAgent.includes('Windows')
|
||||
@@ -473,7 +474,7 @@ function App(): React.JSX.Element {
|
||||
const canGoForwardWorktree = useAppStore(canGoForwardWorktreeHistory)
|
||||
const titlebarLeftControlsRef = useRef<HTMLDivElement | null>(null)
|
||||
const [collapsedSidebarHeaderWidth, setCollapsedSidebarHeaderWidth] = useState(0)
|
||||
const [mountedLazyModalIds, setMountedLazyModalIds] = useState(() => new Set<string>())
|
||||
const [mountedLazyModalIds, setMountedLazyModalIds] = useState<Set<LazyModalId>>(() => new Set())
|
||||
const [onboarding, setOnboarding] = useState<OnboardingState | null>(null)
|
||||
const featureTipsPromptedThisSessionRef = useRef(false)
|
||||
const featureTipsSuppressedByOnboardingThisSessionRef = useRef(false)
|
||||
@@ -1407,28 +1408,12 @@ function App(): React.JSX.Element {
|
||||
return () => observer.disconnect()
|
||||
}, [isFullScreen, settings?.showTitlebarAppName, showSidebar, workspaceActive, sidebarOpen])
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
activeModal !== 'quick-open' &&
|
||||
activeModal !== 'worktree-palette' &&
|
||||
activeModal !== 'new-workspace-composer' &&
|
||||
activeModal !== 'workspace-cleanup' &&
|
||||
activeModal !== 'feature-wall' &&
|
||||
activeModal !== 'feature-tips'
|
||||
) {
|
||||
return
|
||||
}
|
||||
setMountedLazyModalIds((currentIds) => {
|
||||
if (currentIds.has(activeModal)) {
|
||||
return currentIds
|
||||
}
|
||||
const nextIds = new Set(currentIds)
|
||||
// Why: lazy-load these modals only after first use, then keep them mounted
|
||||
// so repeat opens preserve their local state and avoid re-fetch flashes.
|
||||
nextIds.add(activeModal)
|
||||
return nextIds
|
||||
})
|
||||
}, [activeModal])
|
||||
const resolvedMountedLazyModalIds = resolveMountedLazyModalIds(activeModal, mountedLazyModalIds)
|
||||
if (resolvedMountedLazyModalIds !== mountedLazyModalIds) {
|
||||
// Why: lazy-load these modals only after first use, then keep them mounted
|
||||
// so repeat opens preserve their local state and avoid re-fetch flashes.
|
||||
setMountedLazyModalIds(new Set(resolvedMountedLazyModalIds))
|
||||
}
|
||||
|
||||
// Why: extracted so both the full-width titlebar (settings/landing) and
|
||||
// the sidebar-width left header (workspace view) can share the same
|
||||
@@ -1850,7 +1835,7 @@ function App(): React.JSX.Element {
|
||||
{/* Why: root overlays can render Radix <Tooltip>s; keep them inside
|
||||
the shared provider so lazy surfaces mount safely from any entry point. */}
|
||||
<Suspense fallback={null}>
|
||||
{mountedLazyModalIds.has('new-workspace-composer') ? (
|
||||
{resolvedMountedLazyModalIds.has('new-workspace-composer') ? (
|
||||
<RecoverableRenderErrorBoundary
|
||||
boundaryId="modal.new-workspace-composer"
|
||||
surface="modal"
|
||||
@@ -1860,7 +1845,7 @@ function App(): React.JSX.Element {
|
||||
<NewWorkspaceComposerModal />
|
||||
</RecoverableRenderErrorBoundary>
|
||||
) : null}
|
||||
{mountedLazyModalIds.has('workspace-cleanup') ? (
|
||||
{resolvedMountedLazyModalIds.has('workspace-cleanup') ? (
|
||||
<RecoverableRenderErrorBoundary
|
||||
boundaryId="modal.workspace-cleanup"
|
||||
surface="modal"
|
||||
@@ -1872,7 +1857,7 @@ function App(): React.JSX.Element {
|
||||
) : null}
|
||||
</Suspense>
|
||||
<Suspense fallback={null}>
|
||||
{mountedLazyModalIds.has('quick-open') ? (
|
||||
{resolvedMountedLazyModalIds.has('quick-open') ? (
|
||||
<RecoverableRenderErrorBoundary
|
||||
boundaryId="modal.quick-open"
|
||||
surface="modal"
|
||||
@@ -1882,7 +1867,7 @@ function App(): React.JSX.Element {
|
||||
<QuickOpen />
|
||||
</RecoverableRenderErrorBoundary>
|
||||
) : null}
|
||||
{mountedLazyModalIds.has('worktree-palette') ? (
|
||||
{resolvedMountedLazyModalIds.has('worktree-palette') ? (
|
||||
<RecoverableRenderErrorBoundary
|
||||
boundaryId="modal.worktree-palette"
|
||||
surface="modal"
|
||||
@@ -1892,7 +1877,7 @@ function App(): React.JSX.Element {
|
||||
<WorktreeJumpPalette />
|
||||
</RecoverableRenderErrorBoundary>
|
||||
) : null}
|
||||
{mountedLazyModalIds.has('feature-wall') ? (
|
||||
{resolvedMountedLazyModalIds.has('feature-wall') ? (
|
||||
<RecoverableRenderErrorBoundary
|
||||
boundaryId="modal.feature-wall"
|
||||
surface="modal"
|
||||
@@ -1902,7 +1887,7 @@ function App(): React.JSX.Element {
|
||||
<FeatureWallModal />
|
||||
</RecoverableRenderErrorBoundary>
|
||||
) : null}
|
||||
{mountedLazyModalIds.has('feature-tips') ? (
|
||||
{resolvedMountedLazyModalIds.has('feature-tips') ? (
|
||||
<RecoverableRenderErrorBoundary
|
||||
boundaryId="modal.feature-tips"
|
||||
surface="modal"
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
isLazyModalId,
|
||||
resolveMountedLazyModalIds,
|
||||
type LazyModalId
|
||||
} from './lazy-modal-mount-state'
|
||||
|
||||
describe('isLazyModalId', () => {
|
||||
it('recognizes only lazily retained root modal ids', () => {
|
||||
expect(isLazyModalId('quick-open')).toBe(true)
|
||||
expect(isLazyModalId('feature-tips')).toBe(true)
|
||||
expect(isLazyModalId('delete-worktree')).toBe(false)
|
||||
expect(isLazyModalId('none')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('resolveMountedLazyModalIds', () => {
|
||||
it('preserves set identity when the active modal is not lazy-mounted', () => {
|
||||
const mounted = new Set<LazyModalId>(['quick-open'])
|
||||
|
||||
expect(resolveMountedLazyModalIds('none', mounted)).toBe(mounted)
|
||||
})
|
||||
|
||||
it('preserves set identity when the lazy modal is already mounted', () => {
|
||||
const mounted = new Set<LazyModalId>(['workspace-cleanup'])
|
||||
|
||||
expect(resolveMountedLazyModalIds('workspace-cleanup', mounted)).toBe(mounted)
|
||||
})
|
||||
|
||||
it('adds newly opened lazy modal ids without mutating the existing set', () => {
|
||||
const mounted = new Set<LazyModalId>(['quick-open'])
|
||||
const resolved = resolveMountedLazyModalIds('feature-wall', mounted)
|
||||
|
||||
expect(resolved).toEqual(new Set(['quick-open', 'feature-wall']))
|
||||
expect(resolved).not.toBe(mounted)
|
||||
expect(mounted).toEqual(new Set(['quick-open']))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,26 @@
|
||||
const LAZY_MODAL_IDS = [
|
||||
'quick-open',
|
||||
'worktree-palette',
|
||||
'new-workspace-composer',
|
||||
'workspace-cleanup',
|
||||
'feature-wall',
|
||||
'feature-tips'
|
||||
] as const
|
||||
|
||||
export type LazyModalId = (typeof LAZY_MODAL_IDS)[number]
|
||||
|
||||
const LAZY_MODAL_ID_SET = new Set<string>(LAZY_MODAL_IDS)
|
||||
|
||||
export function isLazyModalId(value: string): value is LazyModalId {
|
||||
return LAZY_MODAL_ID_SET.has(value)
|
||||
}
|
||||
|
||||
export function resolveMountedLazyModalIds(
|
||||
activeModal: string,
|
||||
mountedIds: ReadonlySet<LazyModalId>
|
||||
): ReadonlySet<LazyModalId> {
|
||||
if (!isLazyModalId(activeModal) || mountedIds.has(activeModal)) {
|
||||
return mountedIds
|
||||
}
|
||||
return new Set([...mountedIds, activeModal])
|
||||
}
|
||||
Reference in New Issue
Block a user