1import { availableScratchWorkspaceRoot } from "@t3tools/client-runtime/operations/projects";
2import { isScratchProject } from "@t3tools/client-runtime/state/projects";
3import type { EnvironmentProject } from "@t3tools/client-runtime/state/shell";
4import {
5 type EnvironmentId,
6 type ProjectId,
7 resolveEnvironmentMachineKind,
8} from "@t3tools/contracts";
9
10import type { EnvironmentOption } from "../components/BranchToolbar.logic";
11import {
12 deriveLogicalProjectKeyFromSettings,
13 selectProjectGroupingSettings,
14} from "@t3tools/client-runtime/state/project-grouping";
15import { useProjects } from "../state/entities";
16import { useEnvironments, usePrimaryEnvironmentId } from "../state/environments";
17import { useClientSettings } from "./useSettings";
18
19export function useLogicalProjectEnvironments(
20 activeProject: EnvironmentProject | null,
21 scratchDraft: boolean,
22): readonly EnvironmentOption[] {
23 const { environments } = useEnvironments();
24 const allProjects = useProjects();
25 const primaryEnvironmentId = usePrimaryEnvironmentId();
26 const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings);
27
28 if (!activeProject) return [];
29 const environmentById = new Map(
30 environments.map((environment) => [environment.environmentId, environment]),
31 );
32 const envs: EnvironmentOption[] = [];
33 const pushEnvironment = (environmentId: EnvironmentId, projectId: ProjectId | null) => {
34 const environment = environmentById.get(environmentId) ?? null;
35 envs.push({
36 environmentId,
37 projectId,
38 label: environment?.label ?? environmentId,
39 isPrimary: environmentId === primaryEnvironmentId,
40 machine: resolveEnvironmentMachineKind(environment?.serverConfig ?? null),
41 });
42 };
43 if (scratchDraft) {
44 for (const environment of environments) {
45 const scratchRoot = availableScratchWorkspaceRoot(
46 environment.connection.phase,
47 environment.serverConfig,
48 );
49 if (scratchRoot === null && environment.environmentId !== activeProject.environmentId)
50 continue;
51 const scratchProject =
52 environment.environmentId === activeProject.environmentId
53 ? activeProject
54 : allProjects.find(
55 (p) =>
56 p.environmentId === environment.environmentId && isScratchProject(p, scratchRoot),
57 );
58 pushEnvironment(environment.environmentId, scratchProject?.id ?? null);
59 }
60 } else {
61 const logicalKey = deriveLogicalProjectKeyFromSettings(activeProject, projectGroupingSettings);
62 const seen = new Set<string>();
63 for (const p of allProjects) {
64 if (seen.has(p.environmentId)) continue;
65 if (deriveLogicalProjectKeyFromSettings(p, projectGroupingSettings) !== logicalKey) continue;
66 seen.add(p.environmentId);
67 pushEnvironment(p.environmentId, p.id);
68 }
69 }
70 envs.sort((a, b) => {
71 if (a.isPrimary !== b.isPrimary) return a.isPrimary ? -1 : 1;
72 return a.label.localeCompare(b.label);
73 });
74 return envs;
75}