fix(需求池): 修复列表换行和版本解绑状态

This commit is contained in:
Script Generator
2026-07-02 19:50:47 +08:00
parent 121114af6a
commit 554ab520d1
7 changed files with 194 additions and 17 deletions

View File

@@ -0,0 +1,22 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import {
REQUIREMENT_TABLE_BADGE_CLASS,
getRequirementTableTextClass,
} from './requirement-table-layout';
test('keeps requirement table badges on one line', () => {
assert.match(REQUIREMENT_TABLE_BADGE_CLASS, /\bwhitespace-nowrap\b/);
assert.match(REQUIREMENT_TABLE_BADGE_CLASS, /\bshrink-0\b/);
});
test('clips long requirement source project type and creator cells', () => {
for (const column of ['source', 'project', 'type', 'creator'] as const) {
const className = getRequirementTableTextClass(column);
assert.match(className, /\btruncate\b/);
assert.match(className, /\bblock\b/);
assert.match(className, /\bmax-w-\[/);
}
});

View File

@@ -0,0 +1,20 @@
export type RequirementTableTextColumn = 'source' | 'project' | 'type' | 'creator';
const TEXT_COLUMN_MAX_WIDTH: Record<RequirementTableTextColumn, string> = {
source: 'max-w-[170px]',
project: 'max-w-[120px]',
type: 'max-w-[96px]',
creator: 'max-w-[96px]',
};
export const REQUIREMENT_TABLE_NOWRAP_CELL_CLASS = 'px-4 py-3 whitespace-nowrap';
export const REQUIREMENT_TABLE_BADGE_CLASS =
'inline-flex h-6 min-w-[3.25rem] shrink-0 items-center justify-center whitespace-nowrap rounded-md px-2 py-0.5 text-[11px] font-medium';
export const REQUIREMENT_TABLE_SMALL_BADGE_CLASS =
'inline-flex h-5 min-w-[2.75rem] shrink-0 items-center justify-center whitespace-nowrap rounded-md px-2 py-0.5 text-[10px] font-medium';
export function getRequirementTableTextClass(column: RequirementTableTextColumn): string {
return `block truncate ${TEXT_COLUMN_MAX_WIDTH[column]}`;
}

View File

@@ -0,0 +1,63 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import type { Requirement } from './requirement';
import {
getRequirementVersionSelectionPatch,
getRequirementVersionUnlinkPatch,
} from './requirement-version-link';
function requirement(patch: Partial<Requirement> = {}): Requirement {
return {
id: 'req-1',
code: 'REQ-001',
title: 'Requirement',
description: '',
productId: 'product-1',
projectId: 'project-1',
versionId: 'version-1',
sourceType: 'internal',
sourceTarget: '',
platforms: [],
typeId: 'type-1',
status: 'planned',
priority: 'P2',
effort: 'M',
creator: 'tester',
createdAt: '2026-07-02T00:00:00.000Z',
addedToVersionBy: 'pm',
...patch,
};
}
test('unlinking a version-scoped requirement returns it to adopted', () => {
for (const status of ['planned', 'developing', 'testing', 'released'] as const) {
assert.deepEqual(getRequirementVersionUnlinkPatch(requirement({ status })), {
versionId: undefined,
addedToVersionBy: undefined,
status: 'adopted',
});
}
});
test('unlinking keeps other requirement statuses unchanged', () => {
assert.deepEqual(getRequirementVersionUnlinkPatch(requirement({ status: 'adopted' })), {
versionId: undefined,
addedToVersionBy: undefined,
});
});
test('clearing version from requirement edit uses the same unlink semantics', () => {
assert.deepEqual(getRequirementVersionSelectionPatch(requirement(), ''), {
versionId: undefined,
addedToVersionBy: undefined,
status: 'adopted',
});
});
test('selecting a version preserves the current business status', () => {
assert.deepEqual(getRequirementVersionSelectionPatch(requirement({ status: 'adopted' }), 'version-2', 'pm2'), {
versionId: 'version-2',
addedToVersionBy: 'pm2',
});
});

View File

@@ -0,0 +1,29 @@
import type { Requirement } from './requirement';
type RequirementVersionPatch = Pick<Partial<Requirement>, 'versionId' | 'addedToVersionBy' | 'status'>;
const VERSION_SCOPED_REQUIREMENT_STATUSES = new Set<Requirement['status']>(['planned', 'developing', 'testing', 'released']);
export function getRequirementVersionUnlinkPatch(
requirement: Pick<Requirement, 'status'>,
): RequirementVersionPatch {
return {
versionId: undefined,
addedToVersionBy: undefined,
...(VERSION_SCOPED_REQUIREMENT_STATUSES.has(requirement.status) ? { status: 'adopted' as const } : {}),
};
}
export function getRequirementVersionSelectionPatch(
requirement: Pick<Requirement, 'status' | 'addedToVersionBy'>,
versionId?: string,
addedBy?: string,
): RequirementVersionPatch {
if (!versionId) {
return getRequirementVersionUnlinkPatch(requirement);
}
return {
versionId,
addedToVersionBy: addedBy || requirement.addedToVersionBy,
};
}