重构 UI 编辑器状态存储类型
- 将 `UiDesignStateStore` 重命名为 `IUiDesignStateStore`,统一命名规范。 - 替换所有引用,移除 `mockUiDesignStateStore`,改用 `uiDesignStateStore`。 - 更新相关测试和技术文档以匹配重命名与实现更改。
This commit is contained in:
@@ -14,7 +14,7 @@ export type UiDesignStateSaveResult =
|
||||
}
|
||||
| { status: 'conflict'; current: UiDesignStateSnapshot };
|
||||
|
||||
export type UiDesignStateStore = {
|
||||
export type IUiDesignStateStore = {
|
||||
load(assetId: string): Promise<UiDesignStateSnapshot>;
|
||||
save(
|
||||
assetId: string,
|
||||
@@ -26,7 +26,7 @@ export type UiDesignStateStore = {
|
||||
export function createTauriUiDesignStateStore(
|
||||
projectPath: string,
|
||||
expectedProjectId: string,
|
||||
): UiDesignStateStore {
|
||||
): IUiDesignStateStore {
|
||||
return {
|
||||
load(assetId) {
|
||||
return invoke<UiDesignStateSnapshot>('load_ui_design_state', {
|
||||
@@ -47,17 +47,17 @@ export function createTauriUiDesignStateStore(
|
||||
};
|
||||
}
|
||||
|
||||
const mockSnapshots = new Map<string, UiDesignStateSnapshot>();
|
||||
const snapshots = new Map<string, UiDesignStateSnapshot>();
|
||||
|
||||
export const mockUiDesignStateStore: UiDesignStateStore = {
|
||||
export const uiDesignStateStore: IUiDesignStateStore = {
|
||||
async load(assetId) {
|
||||
const snapshot = mockSnapshots.get(assetId);
|
||||
const snapshot = snapshots.get(assetId);
|
||||
return snapshot
|
||||
? structuredClone(snapshot)
|
||||
: { revision: 0, state: structuredClone(EMPTY_UI_EDITOR_STATE) };
|
||||
},
|
||||
async save(assetId, expectedRevision, state) {
|
||||
const current = mockSnapshots.get(assetId) ?? {
|
||||
const current = snapshots.get(assetId) ?? {
|
||||
revision: 0,
|
||||
state: structuredClone(EMPTY_UI_EDITOR_STATE),
|
||||
};
|
||||
@@ -68,7 +68,7 @@ export const mockUiDesignStateStore: UiDesignStateStore = {
|
||||
revision: current.revision + 1,
|
||||
state: structuredClone(state),
|
||||
};
|
||||
mockSnapshots.set(assetId, next);
|
||||
snapshots.set(assetId, next);
|
||||
return {
|
||||
status: 'saved',
|
||||
state: structuredClone(next.state),
|
||||
|
||||
@@ -4,8 +4,8 @@ import { useMemo, useState } from 'react';
|
||||
import { ThemedModal } from '../../components/modal/ThemedModal';
|
||||
import {
|
||||
createTauriUiDesignStateStore,
|
||||
mockUiDesignStateStore,
|
||||
type UiDesignStateStore,
|
||||
type IUiDesignStateStore,
|
||||
uiDesignStateStore,
|
||||
} from '../../features/ui-editor/uiDesignStateStore';
|
||||
import { BindingOverview } from './components/BindingOverview';
|
||||
import { EditorDialogs } from './components/EditorDialogs';
|
||||
@@ -35,14 +35,14 @@ export default function UiEditorPage({
|
||||
projectId?: string;
|
||||
resourceLabel?: string;
|
||||
onBack?: () => void;
|
||||
stateStore?: UiDesignStateStore;
|
||||
stateStore?: IUiDesignStateStore;
|
||||
}) {
|
||||
const resolvedStore = useMemo(
|
||||
() =>
|
||||
stateStore ??
|
||||
(resourceId && projectId
|
||||
? createTauriUiDesignStateStore(projectPath, projectId)
|
||||
: mockUiDesignStateStore),
|
||||
: uiDesignStateStore),
|
||||
[projectId, projectPath, resourceId, stateStore],
|
||||
);
|
||||
const session = useUiEditorSession(projectPath, resourceId, resolvedStore);
|
||||
|
||||
@@ -29,8 +29,8 @@ import type { UIDesignImageRole } from '../../features/ui-editor/types/UIDesignI
|
||||
import type { UIDesignSuggestionTreeNode } from '../../features/ui-editor/types/UIDesignSuggestionTreeNode';
|
||||
import type { UiNodeMoveRequest } from '../../features/ui-editor/types/UiNodeMoveRequest';
|
||||
import {
|
||||
mockUiDesignStateStore,
|
||||
type UiDesignStateStore,
|
||||
type IUiDesignStateStore,
|
||||
uiDesignStateStore,
|
||||
} from '../../features/ui-editor/uiDesignStateStore';
|
||||
import { applyUiDesignSuggestions } from '../../features/ui-editor/uiDesignSuggestions';
|
||||
import { useUiEditorFontFaces } from '../../features/ui-editor/useUiEditorFontFaces';
|
||||
@@ -170,7 +170,7 @@ export type PendingWorkflowStepChange = {
|
||||
export function useUiEditorSession(
|
||||
projectPath: string,
|
||||
resourceId?: string,
|
||||
stateStore: UiDesignStateStore = mockUiDesignStateStore,
|
||||
stateStore: IUiDesignStateStore = uiDesignStateStore,
|
||||
) {
|
||||
const editor = useUiEditorState(EMPTY_UI_EDITOR_STATE);
|
||||
const replaceEditorState = editor.replaceState;
|
||||
|
||||
@@ -6,26 +6,26 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
import {
|
||||
createTauriUiDesignStateStore,
|
||||
mockUiDesignStateStore,
|
||||
uiDesignStateStore,
|
||||
} from '../src/features/ui-editor/uiDesignStateStore';
|
||||
|
||||
describe('UI 设计 State mock store', () => {
|
||||
it('按资源保留快照并拒绝过期 revision', async () => {
|
||||
const first = await mockUiDesignStateStore.load('ui-1');
|
||||
const first = await uiDesignStateStore.load('ui-1');
|
||||
first.state.ui_trees.push({} as never);
|
||||
await expect(
|
||||
mockUiDesignStateStore.save('ui-1', first.revision, first.state),
|
||||
uiDesignStateStore.save('ui-1', first.revision, first.state),
|
||||
).resolves.toMatchObject({
|
||||
status: 'saved',
|
||||
revision: 1,
|
||||
});
|
||||
|
||||
await expect(mockUiDesignStateStore.load('ui-1')).resolves.toMatchObject({
|
||||
await expect(uiDesignStateStore.load('ui-1')).resolves.toMatchObject({
|
||||
revision: 1,
|
||||
state: { ui_trees: [{}] },
|
||||
});
|
||||
await expect(
|
||||
mockUiDesignStateStore.save('ui-1', first.revision, first.state),
|
||||
uiDesignStateStore.save('ui-1', first.revision, first.state),
|
||||
).resolves.toMatchObject({ status: 'conflict', current: { revision: 1 } });
|
||||
});
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Node as UiNode } from '../src/features/ui-editor/types/Node';
|
||||
import type { State } from '../src/features/ui-editor/types/State';
|
||||
import type {
|
||||
IUiDesignStateStore,
|
||||
UiDesignStateSnapshot,
|
||||
UiDesignStateStore,
|
||||
} from '../src/features/ui-editor/uiDesignStateStore';
|
||||
import UiEditorPage from '../src/view/ui-editor';
|
||||
import { useUiEditorSession } from '../src/view/ui-editor/useUiEditorPage';
|
||||
@@ -78,6 +78,7 @@ function node(id: string, children: UiNode[] = []): UiNode {
|
||||
source: 'System',
|
||||
},
|
||||
components: [],
|
||||
children_display_mode: undefined,
|
||||
children,
|
||||
};
|
||||
}
|
||||
@@ -133,7 +134,7 @@ function stateWithPages(pageIds: string[]): State {
|
||||
}
|
||||
|
||||
async function renderLoadedSession(state: State) {
|
||||
const stateStore: UiDesignStateStore = {
|
||||
const stateStore: IUiDesignStateStore = {
|
||||
load: vi.fn().mockResolvedValue({ revision: 0, state }),
|
||||
save: vi.fn(),
|
||||
};
|
||||
@@ -158,7 +159,7 @@ describe('UiEditorPage', () => {
|
||||
configurable: true,
|
||||
value: { core: { invoke } },
|
||||
});
|
||||
const stateStore: UiDesignStateStore = {
|
||||
const stateStore: IUiDesignStateStore = {
|
||||
load: vi.fn().mockResolvedValue({
|
||||
revision: 0,
|
||||
state: stateWithPages(['page']),
|
||||
@@ -216,7 +217,7 @@ describe('UiEditorPage', () => {
|
||||
|
||||
it('does not cancel a preview scope before state loading creates one', () => {
|
||||
vi.mocked(invoke).mockClear();
|
||||
const stateStore: UiDesignStateStore = {
|
||||
const stateStore: IUiDesignStateStore = {
|
||||
load: vi.fn(() => new Promise(() => undefined)),
|
||||
save: vi.fn(),
|
||||
};
|
||||
@@ -533,7 +534,7 @@ describe('UiEditorPage', () => {
|
||||
});
|
||||
|
||||
it('shows a page-level save failure and allows a retry', async () => {
|
||||
const stateStore: UiDesignStateStore = {
|
||||
const stateStore: IUiDesignStateStore = {
|
||||
load: vi.fn().mockResolvedValue(structuredClone(EMPTY_SNAPSHOT)),
|
||||
save: vi.fn().mockRejectedValue(new Error('临时存储不可用')),
|
||||
};
|
||||
@@ -563,7 +564,7 @@ describe('UiEditorPage', () => {
|
||||
});
|
||||
|
||||
it('keeps the dedicated message for a save conflict', async () => {
|
||||
const stateStore: UiDesignStateStore = {
|
||||
const stateStore: IUiDesignStateStore = {
|
||||
load: vi.fn().mockResolvedValue(structuredClone(EMPTY_SNAPSHOT)),
|
||||
save: vi.fn().mockResolvedValue({
|
||||
status: 'conflict',
|
||||
|
||||
Reference in New Issue
Block a user