156 lines
4.2 KiB
TypeScript
156 lines
4.2 KiB
TypeScript
import { normalizePath } from '@renderer/utils/pathNormalize';
|
|
|
|
import type { Project, RepositoryGroup } from '@renderer/types/data';
|
|
import type { TeamSummary } from '@shared/types';
|
|
|
|
export interface ResolveTeamProjectSelectionInput {
|
|
repositoryGroups: readonly RepositoryGroup[];
|
|
projects: readonly Project[];
|
|
selectedRepositoryId: string | null;
|
|
selectedWorktreeId: string | null;
|
|
selectedProjectId: string | null;
|
|
activeProjectId: string | null;
|
|
}
|
|
|
|
export interface ResolvedTeamProjectSelection {
|
|
projectPath: string | null;
|
|
repositoryId: string | null;
|
|
worktreeId: string | null;
|
|
projectId: string | null;
|
|
}
|
|
|
|
export type TeamProjectSelectionTarget =
|
|
| {
|
|
kind: 'grouped';
|
|
repositoryId: string;
|
|
worktreeId: string;
|
|
projectPath: string;
|
|
}
|
|
| {
|
|
kind: 'flat';
|
|
projectId: string;
|
|
projectPath: string;
|
|
};
|
|
|
|
function findWorktreeSelection(
|
|
repositoryGroups: readonly RepositoryGroup[],
|
|
worktreeId: string
|
|
): { repositoryId: string; worktreeId: string; projectPath: string } | null {
|
|
for (const repositoryGroup of repositoryGroups) {
|
|
const worktree = repositoryGroup.worktrees.find((candidate) => candidate.id === worktreeId);
|
|
if (worktree) {
|
|
return {
|
|
repositoryId: repositoryGroup.id,
|
|
worktreeId: worktree.id,
|
|
projectPath: worktree.path,
|
|
};
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function resolveTeamProjectSelection({
|
|
repositoryGroups,
|
|
projects,
|
|
selectedRepositoryId,
|
|
selectedWorktreeId,
|
|
selectedProjectId,
|
|
activeProjectId,
|
|
}: ResolveTeamProjectSelectionInput): ResolvedTeamProjectSelection {
|
|
const effectiveWorktreeId = selectedWorktreeId ?? activeProjectId ?? selectedProjectId ?? null;
|
|
if (effectiveWorktreeId) {
|
|
const worktreeSelection = findWorktreeSelection(repositoryGroups, effectiveWorktreeId);
|
|
if (worktreeSelection) {
|
|
return {
|
|
projectPath: worktreeSelection.projectPath,
|
|
repositoryId: worktreeSelection.repositoryId,
|
|
worktreeId: worktreeSelection.worktreeId,
|
|
projectId: worktreeSelection.worktreeId,
|
|
};
|
|
}
|
|
}
|
|
|
|
const effectiveProjectId = activeProjectId ?? selectedProjectId ?? null;
|
|
if (effectiveProjectId) {
|
|
const project = projects.find((candidate) => candidate.id === effectiveProjectId);
|
|
if (project) {
|
|
return {
|
|
projectPath: project.path,
|
|
repositoryId: null,
|
|
worktreeId: null,
|
|
projectId: project.id,
|
|
};
|
|
}
|
|
}
|
|
|
|
if (selectedRepositoryId) {
|
|
const repositoryGroup = repositoryGroups.find(
|
|
(candidate) => candidate.id === selectedRepositoryId
|
|
);
|
|
const fallbackWorktree = repositoryGroup?.worktrees[0] ?? null;
|
|
if (fallbackWorktree) {
|
|
return {
|
|
projectPath: fallbackWorktree.path,
|
|
repositoryId: repositoryGroup?.id ?? null,
|
|
worktreeId: fallbackWorktree.id,
|
|
projectId: fallbackWorktree.id,
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
projectPath: null,
|
|
repositoryId: null,
|
|
worktreeId: null,
|
|
projectId: null,
|
|
};
|
|
}
|
|
|
|
export function findTeamProjectSelectionTarget(
|
|
repositoryGroups: readonly RepositoryGroup[],
|
|
projects: readonly Project[],
|
|
projectPath: string
|
|
): TeamProjectSelectionTarget | null {
|
|
const normalizedProjectPath = normalizePath(projectPath);
|
|
|
|
for (const repositoryGroup of repositoryGroups) {
|
|
const worktree = repositoryGroup.worktrees.find(
|
|
(candidate) => normalizePath(candidate.path) === normalizedProjectPath
|
|
);
|
|
if (worktree) {
|
|
return {
|
|
kind: 'grouped',
|
|
repositoryId: repositoryGroup.id,
|
|
worktreeId: worktree.id,
|
|
projectPath: worktree.path,
|
|
};
|
|
}
|
|
}
|
|
|
|
const project = projects.find(
|
|
(candidate) => normalizePath(candidate.path) === normalizedProjectPath
|
|
);
|
|
if (project) {
|
|
return {
|
|
kind: 'flat',
|
|
projectId: project.id,
|
|
projectPath: project.path,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function teamMatchesProjectSelection(team: TeamSummary, projectPath: string): boolean {
|
|
const normalizedProjectPath = normalizePath(projectPath);
|
|
if (team.projectPath && normalizePath(team.projectPath) === normalizedProjectPath) {
|
|
return true;
|
|
}
|
|
|
|
return (
|
|
team.projectPathHistory?.some(
|
|
(candidate) => normalizePath(candidate) === normalizedProjectPath
|
|
) ?? false
|
|
);
|
|
}
|