import type { Priority, VersionWithContext } from './derive'; export type VersionListScope = | { type: 'all' } | { type: 'product'; productId: string } | { type: 'project'; projectId: string }; export interface VersionProjectNode { projectId: string; projectName: string; count: number; } export interface VersionProductNode { productId: string; productName: string; count: number; projects: VersionProjectNode[]; } export interface VersionListFilter { scope: VersionListScope; keyword: string; priority: Priority | 'all'; } function matchesKeyword(values: Array, keyword: string): boolean { const normalized = keyword.trim().toLowerCase(); if (!normalized) return true; return values.some((value) => value?.toLowerCase().includes(normalized)); } export function buildVersionScopeTree(versions: VersionWithContext[], keyword: string): VersionProductNode[] { const normalized = keyword.trim().toLowerCase(); const productMap = new Map; }>(); for (const version of versions) { const productMatches = matchesKeyword([version.productName], normalized); const projectMatches = matchesKeyword([version.projectName], normalized); const versionMatches = matchesKeyword([version.name], normalized); if (normalized && !productMatches && !projectMatches && !versionMatches) continue; let product = productMap.get(version.productId); if (!product) { product = { productId: version.productId, productName: version.productName, projects: new Map(), }; productMap.set(version.productId, product); } const project = product.projects.get(version.projectId) ?? { projectId: version.projectId, projectName: version.projectName, count: 0, }; project.count += 1; product.projects.set(version.projectId, project); } return Array.from(productMap.values()).map((product) => { const projects = Array.from(product.projects.values()).sort((a, b) => a.projectName.localeCompare(b.projectName, 'zh-Hans-CN')); return { productId: product.productId, productName: product.productName, count: projects.reduce((sum, project) => sum + project.count, 0), projects, }; }).sort((a, b) => a.productName.localeCompare(b.productName, 'zh-Hans-CN')); } export function filterVersionsForList(versions: VersionWithContext[], filter: VersionListFilter): VersionWithContext[] { const filtered = versions.filter((version) => { if (filter.scope.type === 'product' && version.productId !== filter.scope.productId) return false; if (filter.scope.type === 'project' && version.projectId !== filter.scope.projectId) return false; if (filter.priority !== 'all' && (version.priority ?? 'P2') !== filter.priority) return false; return matchesKeyword([version.name], filter.keyword); }); return filtered; }