| 1 | import { useLayoutEffect, useRef } from "react"; |
| 2 | import { useAppNavigationStore } from "../store/appNavigation"; |
| 3 | import { useCommittedCommand } from "../lib/useCommittedCommand"; |
| 4 | import { createSubscriptionScope } from "../lib/subscriptionScope"; |
| 5 | import type { DesktopNavigationIntent } from "./desktopNavigationOwner"; |
| 6 | |
| 7 | async function finishAutomationNavigation(input: { |
| 8 | intent: number; request: DesktopNavigationIntent; |
| 9 | enqueue(request: DesktopNavigationIntent, intent: number): Promise<void>; |
| 10 | finish(intent: number): void; |
| 11 | }) { |
| 12 | try { await input.enqueue(input.request, input.intent); } |
| 13 | finally { input.finish(input.intent); } |
| 14 | } |
| 15 | |
| 16 | /** The management page owns its link until the navigation owner accepts it. */ |
| 17 | export function useAutomationNavigation(input: { |
| 18 | noteIntent(): number; |
| 19 | enqueue(intent: DesktopNavigationIntent, seq: number): Promise<void>; |
| 20 | }) { |
| 21 | const pending = useRef<{ intent: number; generation: number } | null>(null); |
| 22 | const invalidate = useCommittedCommand(() => { |
| 23 | if (!pending.current) return; |
| 24 | pending.current = null; |
| 25 | input.noteIntent(); |
| 26 | }); |
| 27 | useLayoutEffect(() => { |
| 28 | const scope = createSubscriptionScope(); |
| 29 | scope.listen(listener => useAppNavigationStore.subscribe((next, previous) => { |
| 30 | if (next.generation !== previous.generation) listener(); |
| 31 | }), invalidate); |
| 32 | return () => { pending.current = null; scope.dispose(); }; |
| 33 | }, [invalidate]); |
| 34 | const finish = useCommittedCommand((intent: number) => { |
| 35 | if (pending.current?.intent === intent) pending.current = null; |
| 36 | }); |
| 37 | const openAutomationTopic = useCommittedCommand((scope: string, workspaceRoot: string, topicId: string) => { |
| 38 | const intent = input.noteIntent(); |
| 39 | pending.current = { intent, generation: useAppNavigationStore.getState().generation }; |
| 40 | return finishAutomationNavigation({ intent, request: { kind: "topic", scope, workspaceRoot, topicId }, enqueue: input.enqueue, finish }); |
| 41 | }); |
| 42 | const topicAccepted = useCommittedCommand((intent: number) => { |
| 43 | const link = pending.current; |
| 44 | if (!link || link.intent !== intent) return; |
| 45 | pending.current = null; |
| 46 | useAppNavigationStore.getState().returnFromAutomationLink(link.generation); |
| 47 | }); |
| 48 | return { openAutomationTopic, topicAccepted }; |
| 49 | } |
| 50 |