118 lines · 3.9 KB · TypeScript
RawDownload
import { scopeProjectRef } from "@t3tools/client-runtime";import type { EnvironmentId, ScopedProjectRef } from "@t3tools/contracts";import {  deriveLogicalProjectKeyFromSettings,  derivePhysicalProjectKey,  deriveProjectGroupLabel,  type ProjectGroupingSettings,} from "./logicalProject";import type { Project } from "./types"; export type EnvironmentPresence = "local-only" | "remote-only" | "mixed"; export interface SidebarProjectGroupMember extends Project {  physicalProjectKey: string;  environmentLabel: string | null;} export interface SidebarProjectSnapshot extends Project {  projectKey: string;  displayName: string;  groupedProjectCount: number;  environmentPresence: EnvironmentPresence;  memberProjects: readonly SidebarProjectGroupMember[];  memberProjectRefs: readonly ScopedProjectRef[];  remoteEnvironmentLabels: readonly string[];} export function buildPhysicalToLogicalProjectKeyMap(input: {  projects: ReadonlyArray<Project>;  settings: ProjectGroupingSettings;}): Map<string, string> {  const mapping = new Map<string, string>();  for (const project of input.projects) {    mapping.set(      derivePhysicalProjectKey(project),      deriveLogicalProjectKeyFromSettings(project, input.settings),    );  }  return mapping;} export function buildSidebarProjectSnapshots(input: {  projects: ReadonlyArray<Project>;  settings: ProjectGroupingSettings;  primaryEnvironmentId: EnvironmentId | null;  resolveEnvironmentLabel: (environmentId: EnvironmentId) => string | null;}): SidebarProjectSnapshot[] {  const groupedMembers = new Map<string, SidebarProjectGroupMember[]>();  for (const project of input.projects) {    const logicalKey = deriveLogicalProjectKeyFromSettings(project, input.settings);    const member: SidebarProjectGroupMember = {      ...project,      physicalProjectKey: derivePhysicalProjectKey(project),      environmentLabel: input.resolveEnvironmentLabel(project.environmentId),    };    const existing = groupedMembers.get(logicalKey);    if (existing) {      existing.push(member);    } else {      groupedMembers.set(logicalKey, [member]);    }  }   const result: SidebarProjectSnapshot[] = [];  const seen = new Set<string>();  for (const project of input.projects) {    const logicalKey = deriveLogicalProjectKeyFromSettings(project, input.settings);    if (seen.has(logicalKey)) {      continue;    }    seen.add(logicalKey);     const members = groupedMembers.get(logicalKey) ?? [];    const representative =      (input.primaryEnvironmentId        ? members.find((member) => member.environmentId === input.primaryEnvironmentId)        : null) ?? members[0];    if (!representative) {      continue;    }     const hasLocal =      input.primaryEnvironmentId !== null &&      members.some((member) => member.environmentId === input.primaryEnvironmentId);    const hasRemote =      input.primaryEnvironmentId !== null        ? members.some((member) => member.environmentId !== input.primaryEnvironmentId)        : false;    const remoteEnvironmentLabels = members      .filter(        (member) =>          input.primaryEnvironmentId !== null &&          member.environmentId !== input.primaryEnvironmentId,      )      .flatMap((member) => (member.environmentLabel ? [member.environmentLabel] : []))      .filter((label, index, labels) => labels.indexOf(label) === index);     result.push({      ...representative,      projectKey: logicalKey,      displayName:        members.length > 1          ? deriveProjectGroupLabel({              representative,              members,            })          : representative.name,      groupedProjectCount: members.length,      environmentPresence:        hasLocal && hasRemote ? "mixed" : hasRemote ? "remote-only" : "local-only",      memberProjects: members,      memberProjectRefs: members.map((member) => scopeProjectRef(member.environmentId, member.id)),      remoteEnvironmentLabels,    });  }   return result;}