Files
ftb-project-management/apps/web/lib/requirement-selector.ts

59 lines
2.0 KiB
TypeScript

import type { Requirement } from './requirement';
export interface RequirementOption {
id: string;
code: string;
title: string;
productOwner?: string;
status: Requirement['status'];
isHistorical?: boolean;
}
export function toRequirementOption(requirement: Requirement, isHistorical = false): RequirementOption {
return {
id: requirement.id,
code: requirement.code,
title: requirement.title,
productOwner: requirement.productOwner,
status: requirement.status,
isHistorical,
};
}
export function getProjectAdoptedRequirementCandidates(requirements: Requirement[], projectId: string): Requirement[] {
return requirements
.filter((r) => r.projectId === projectId && r.status === 'adopted')
.sort((a, b) => a.code.localeCompare(b.code, 'zh-CN'));
}
export function getVersionLinkedRequirementCandidates(requirements: Requirement[], requirementIds: string[]): Requirement[] {
const linkedOrder = new Map<string, number>();
requirementIds.forEach((id, index) => {
if (!linkedOrder.has(id)) linkedOrder.set(id, index);
});
return requirements
.filter((r) => linkedOrder.has(r.id))
.sort((a, b) => {
const orderA = linkedOrder.get(a.id) ?? Number.MAX_SAFE_INTEGER;
const orderB = linkedOrder.get(b.id) ?? Number.MAX_SAFE_INTEGER;
if (orderA !== orderB) return orderA - orderB;
return a.code.localeCompare(b.code, 'zh-CN');
});
}
export function mergeSelectedRequirementOptions(
candidates: Requirement[],
allRequirements: Requirement[],
selectedIds: string[] = [],
): RequirementOption[] {
const candidateOptions = candidates.map((r) => toRequirementOption(r));
const candidateIds = new Set(candidateOptions.map((r) => r.id));
const historical = selectedIds
.filter((id) => !candidateIds.has(id))
.map((id) => allRequirements.find((r) => r.id === id))
.filter((r): r is Requirement => Boolean(r))
.map((r) => toRequirementOption(r, true));
return [...candidateOptions, ...historical];
}