feat: 数据集版本管理支持删除历史版本
DatasetVersionList 新增 next_version_number,API 与 Mock 补充删除版本接口与并发控制,DatasetVersionBar 增加删除操作并对初始版本与最后版本禁用,DatasetPreviewView 接入删除流程,回归脚本与设计走查同步。
This commit is contained in:
@@ -27,7 +27,10 @@ import {
|
||||
activateDatasetVersion,
|
||||
appendDatasetVersion,
|
||||
createInitialVersionState,
|
||||
deleteDatasetVersion,
|
||||
DatasetVersionMutationError,
|
||||
getActiveDatasetVersion,
|
||||
normalizeDatasetVersionState,
|
||||
} from './datasetVersions'
|
||||
import type { StoredDatasetVersion, StoredDatasetVersionState } from './datasetVersions'
|
||||
|
||||
@@ -83,7 +86,13 @@ function getVersionState(fileId: string): StoredDatasetVersionState {
|
||||
if (persisted) {
|
||||
try {
|
||||
const state = JSON.parse(persisted) as StoredDatasetVersionState
|
||||
if (state.versions?.length && state.active_version_id) return state
|
||||
if (state.versions?.length && state.active_version_id) {
|
||||
const normalizedState = normalizeDatasetVersionState(state)
|
||||
if (state.next_version_number !== normalizedState.next_version_number) {
|
||||
persistVersionState(fileId, normalizedState)
|
||||
}
|
||||
return normalizedState
|
||||
}
|
||||
} catch {
|
||||
// 版本数据损坏时回退到初始版本
|
||||
}
|
||||
@@ -100,6 +109,14 @@ function versionMetadata(version: StoredDatasetVersion) {
|
||||
return metadata
|
||||
}
|
||||
|
||||
function versionListResponse(state: StoredDatasetVersionState) {
|
||||
return {
|
||||
versions: state.versions.map(versionMetadata).sort((a, b) => b.version - a.version),
|
||||
active_version_id: state.active_version_id,
|
||||
next_version_number: state.next_version_number,
|
||||
}
|
||||
}
|
||||
|
||||
/** 通过路径 + method 匹配 mock 响应 */
|
||||
async function handleMock(config: AxiosRequestConfig) {
|
||||
await delay(150) // 模拟网络延迟
|
||||
@@ -185,10 +202,7 @@ async function handleMock(config: AxiosRequestConfig) {
|
||||
if (m && method === 'get') {
|
||||
const fileId = decodeURIComponent(m[1])
|
||||
const state = getVersionState(fileId)
|
||||
return ok({
|
||||
versions: state.versions.map(versionMetadata).sort((a, b) => b.version - a.version),
|
||||
active_version_id: state.active_version_id,
|
||||
})
|
||||
return ok(versionListResponse(state))
|
||||
}
|
||||
if (m && method === 'post') {
|
||||
const fileId = decodeURIComponent(m[1])
|
||||
@@ -249,6 +263,30 @@ async function handleMock(config: AxiosRequestConfig) {
|
||||
? ok({ version: versionMetadata(version), content: version.content })
|
||||
: fail('数据集版本不存在', 404)
|
||||
}
|
||||
if (m && method === 'delete') {
|
||||
const fileId = decodeURIComponent(m[1])
|
||||
const versionId = decodeURIComponent(m[2])
|
||||
const currentState = getVersionState(fileId)
|
||||
if (params.expected_current_version_id !== currentState.active_version_id) {
|
||||
return fail('当前版本已被其他用户更新,请刷新后重试', 409)
|
||||
}
|
||||
|
||||
let nextState: StoredDatasetVersionState
|
||||
try {
|
||||
nextState = deleteDatasetVersion(currentState, versionId)
|
||||
} catch (error) {
|
||||
if (error instanceof DatasetVersionMutationError) {
|
||||
return fail(error.message, error.status)
|
||||
}
|
||||
return fail('删除版本失败', 500)
|
||||
}
|
||||
try {
|
||||
persistVersionState(fileId, nextState)
|
||||
} catch {
|
||||
return fail('浏览器 Mock 存储空间不足', 413)
|
||||
}
|
||||
return ok(versionListResponse(nextState))
|
||||
}
|
||||
|
||||
// ==================== 训练任务 ====================
|
||||
if (url === '/fine-tune' && method === 'get') return ok(mockFineTuneList)
|
||||
|
||||
@@ -9,6 +9,18 @@ export interface StoredDatasetVersion {
|
||||
export interface StoredDatasetVersionState {
|
||||
versions: StoredDatasetVersion[]
|
||||
active_version_id: string
|
||||
/** 下次创建版本时使用的序号,确保已删除的版本号不会被复用。 */
|
||||
next_version_number: number
|
||||
}
|
||||
|
||||
export class DatasetVersionMutationError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
readonly status: number,
|
||||
) {
|
||||
super(message)
|
||||
this.name = 'DatasetVersionMutationError'
|
||||
}
|
||||
}
|
||||
|
||||
export function createInitialVersionState(
|
||||
@@ -22,7 +34,24 @@ export function createInitialVersionState(
|
||||
description: '初始版本',
|
||||
content,
|
||||
}
|
||||
return { versions: [version], active_version_id: version.id }
|
||||
return { versions: [version], active_version_id: version.id, next_version_number: 2 }
|
||||
}
|
||||
|
||||
/** 为旧版 localStorage 数据补齐单调递增的版本号游标。 */
|
||||
export function normalizeDatasetVersionState(
|
||||
state: Omit<StoredDatasetVersionState, 'next_version_number'> & {
|
||||
next_version_number?: number
|
||||
},
|
||||
): StoredDatasetVersionState {
|
||||
const minimumNextNumber = Math.max(0, ...state.versions.map((item) => item.version)) + 1
|
||||
const nextVersionNumber = Number.isInteger(state.next_version_number)
|
||||
? Math.max(minimumNextNumber, state.next_version_number as number)
|
||||
: minimumNextNumber
|
||||
|
||||
return {
|
||||
...state,
|
||||
next_version_number: nextVersionNumber,
|
||||
}
|
||||
}
|
||||
|
||||
/** 追加不可变版本快照,并自动把新版本设为当前版本。 */
|
||||
@@ -32,7 +61,7 @@ export function appendDatasetVersion(
|
||||
createTime: string,
|
||||
description = '在线编辑',
|
||||
): StoredDatasetVersionState {
|
||||
const nextNumber = Math.max(0, ...state.versions.map((item) => item.version)) + 1
|
||||
const nextNumber = state.next_version_number
|
||||
const version: StoredDatasetVersion = {
|
||||
id: `v${nextNumber}`,
|
||||
version: nextNumber,
|
||||
@@ -43,6 +72,32 @@ export function appendDatasetVersion(
|
||||
return {
|
||||
versions: [...state.versions, version],
|
||||
active_version_id: version.id,
|
||||
next_version_number: nextNumber + 1,
|
||||
}
|
||||
}
|
||||
|
||||
/** 删除非当前、非初始的历史版本,并保留版本号游标。 */
|
||||
export function deleteDatasetVersion(
|
||||
state: StoredDatasetVersionState,
|
||||
versionId: string,
|
||||
): StoredDatasetVersionState {
|
||||
const version = state.versions.find((item) => item.id === versionId)
|
||||
if (!version) {
|
||||
throw new DatasetVersionMutationError('数据集版本不存在', 404)
|
||||
}
|
||||
if (state.versions.length === 1) {
|
||||
throw new DatasetVersionMutationError('唯一版本不可删除', 400)
|
||||
}
|
||||
if (version.id === state.active_version_id) {
|
||||
throw new DatasetVersionMutationError('当前版本不可删除,请先切换到其他版本', 409)
|
||||
}
|
||||
if (version.version === 1) {
|
||||
throw new DatasetVersionMutationError('初始版本不可删除', 400)
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
versions: state.versions.filter((item) => item.id !== versionId),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user