Skip to content
Source
Sign inSign up
Open History to see the last commit

reopenClosedView.ts

164 lines5.3 KB

1import type { EnvironmentId, ProjectId } from "@t3tools/contracts";
2​
3import type { OpenPreviewMutation } from "./browser/openFileInPreview";
4import type { ClosedView, ClosedViewEntry } from "./closedViewStore";
5import type { PullRequestListPreferences } from "./components/pullRequest/pullRequestListPreferences";
6import { openPreviewSession } from "./components/preview/openPreviewSession";
7import {
8 rightPanelHostRef,
9 type RightPanelSurface,
10 selectThreadRightPanelState,
11 type ThreadRightPanelState,
12 useRightPanelStore,
13} from "./rightPanelStore";
14​
15export interface ReopenOwnerState {
16 environmentKnown: boolean;
17 catalogReady: boolean;
18 ownerExists: boolean;
19 /** False only for a side chat tab whose thread is gone from the shell. */
20 sideChatExists: boolean;
21 shellLive: boolean;
22 panel: ThreadRightPanelState;
24​
25export function planNextReopen(
26 entries: readonly ClosedViewEntry[],
27 ownerState: (entry: ClosedViewEntry) => ReopenOwnerState,
28): { drop: ClosedViewEntry[]; restore: ClosedViewEntry | null } {
29 const drop: ClosedViewEntry[] = [];
30 for (const entry of entries) {
31 const owner = ownerState(entry);
32 if (!owner.environmentKnown) {
33 if (!owner.catalogReady) break;
34 drop.push(entry);
35 continue;
36 }
37 if (!owner.ownerExists || !owner.sideChatExists) {
38 if (owner.shellLive) continue;
39 break;
40 }
41 const alreadyOpen =
42 entry.kind === "panel-tab"
43 ? owner.panel.isOpen && owner.panel.surfaces.some((s) => s.id === entry.surface.id)
44 : owner.panel.surfaces.some(
45 (s) => s.kind === "preview" && s.resourceId === entry.snapshot.tabId,
46 );
47 if (alreadyOpen) {
48 drop.push(entry);
49 continue;
50 }
51 return { drop, restore: entry };
52 }
53 return { drop, restore: null };
55​
56type PullRequestsSearchLike = Partial<PullRequestListPreferences> & {
57 repository?: string;
58 number?: number;
59 selectedProjectId?: ProjectId;
60 selectedHost?: string;
61 selectedEnvironmentId?: EnvironmentId;
62};
63​
64export function pullRequestsSearchForRestore<S extends PullRequestsSearchLike>(
65 previous: S,
66 selected: RightPanelSurface | null,
67): S & PullRequestListPreferences {
68 const {
69 repository: _repository,
70 number: _number,
71 selectedProjectId: _projectId,
72 selectedHost: _host,
73 selectedEnvironmentId: _environmentId,
74 ...filters
75 } = previous;
76 return {
77 ...filters,
78 involvement: previous.involvement ?? "all",
79 state: previous.state ?? "open",
80 ...(selected?.kind === "pull-request"
81 ? {
82 repository: selected.repository,
83 number: selected.number,
84 selectedProjectId: selected.projectId as ProjectId,
85 ...(selected.host === undefined ? {} : { selectedHost: selected.host }),
86 ...(selected.environmentId === undefined
87 ? {}
88 : { selectedEnvironmentId: selected.environmentId as EnvironmentId }),
89 }
90 : {}),
91 } as S & PullRequestListPreferences;
93​
94export async function reopenClosedView(
95 view: ClosedView,
96 options: {
97 openPreview: OpenPreviewMutation;
98 workspaceAvailable: boolean;
99 },
100): Promise<boolean> {
101 const panels = useRightPanelStore.getState();
102 const ref = view.threadRef;
103​
104 if (view.kind === "browser") {
105 const url = view.snapshot.navStatus._tag === "Idle" ? undefined : view.snapshot.navStatus.url;
106 const result = await openPreviewSession({
107 openPreview: options.openPreview,
108 threadRef: ref,
109 ...(url === undefined ? {} : { url }),
110 ...(view.snapshot.viewport === undefined ? {} : { viewport: view.snapshot.viewport }),
111 ...(view.snapshot.profileId === undefined ? {} : { profileId: view.snapshot.profileId }),
112 });
113 if (result._tag === "Failure") return false;
114 panels.openBrowser(ref, result.value.tabId);
115 return true;
116 }
117 const surface = view.surface;
118 if (
119 !options.workspaceAvailable &&
120 (surface.kind === "files" || (surface.kind === "file" && !surface.attachment))
121 )
122 return false;
123 switch (surface.kind) {
124 case "preview":
125 if (surface.resourceId !== null) return false;
126 panels.openBrowser(ref, null);
127 break;
128 case "file":
129 if (surface.attachment) panels.openAttachment(ref, surface.attachment);
130 else {
131 panels.openFile(ref, surface.relativePath, surface.revealLine ?? undefined);
132 if (typeof surface.folderTrail === "string") {
133 panels.navigateFolder(ref, surface.id, surface.relativePath, surface.folderTrail);
134 }
135 }
136 break;
137 case "files": {
138 const rootAlreadyExists = selectThreadRightPanelState(
139 panels.byThreadKey,
140 rightPanelHostRef(ref),
141 ).surfaces.some((current) => current.kind === "files");
142 panels.open(ref, "files");
143 if (!rootAlreadyExists && typeof surface.folderTrail === "string") {
144 panels.navigateFolder(ref, surface.id, "", surface.folderTrail);
145 }
146 break;
147 }
148 case "device":
149 if (surface.target) {
150 panels.openDevice(ref, surface.target);
151 if (surface.title) panels.renameDevice(ref, surface.id, surface.title);
152 } else panels.open(ref, "device");
153 break;
154 case "pull-request":
155 panels.openPullRequest(ref, surface);
156 break;
157 case "side-chat":
158 panels.openSideChat(ref, surface.threadId);
159 break;
160 default:
161 panels.open(ref, surface.kind);
162 }
163 return true;