修正 UI 编辑器入口对 canonical ui-design 原型的判断
- packages/shared:新增 `GAME_CREATION_APP_UI_DESIGN_ASSET_KIND`(`ui-design`)并让 canonical kind 列表与分类表引用它,避免散落裸字符串。 - project-development/index.tsx:`openResourceUiEditor` 与 `selectedResourceOpensUiEditor` 的原型判断由旧值 `ui-prototype` 改为该常量,恢复原型图的「UI 编辑器」入口。 - resourceProjectionModel.ts:`isPendingUiPrototype` 同步改用该常量,恢复待视觉验收标注。 - project-development.suite.ts:候选界面图 fixture 改用 canonical kind,并补一条原型图打开 UI 编辑器桥接的回归用例(去掉修正即转红)。
This commit is contained in:
@@ -81,6 +81,7 @@ import type {
|
||||
ProjectResourceCanvasLayoutMode,
|
||||
} from '../../../../../packages/shared/src/contracts/gameCreationApp';
|
||||
import {
|
||||
GAME_CREATION_APP_UI_DESIGN_ASSET_KIND,
|
||||
GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND,
|
||||
GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE,
|
||||
} from '../../../../../packages/shared/src/contracts/gameCreationApp';
|
||||
@@ -5300,7 +5301,7 @@ export default function ProjectDevelopmentView({
|
||||
|
||||
const openResourceUiEditor = useCallback(
|
||||
(resource: ProjectResource) => {
|
||||
if (resource.subtype === 'ui-prototype') {
|
||||
if (resource.subtype === GAME_CREATION_APP_UI_DESIGN_ASSET_KIND) {
|
||||
void openUiDesignEditor(resource);
|
||||
return;
|
||||
}
|
||||
@@ -7471,7 +7472,7 @@ export default function ProjectDevelopmentView({
|
||||
);
|
||||
const selectedResourceOpensUiEditor =
|
||||
selectedResource?.subtype === GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND ||
|
||||
selectedResource?.subtype === 'ui-prototype';
|
||||
selectedResource?.subtype === GAME_CREATION_APP_UI_DESIGN_ASSET_KIND;
|
||||
|
||||
const selectedToolbarStyle = selectedResourceLayer
|
||||
? resolveSelectedToolbarStyle({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
GAME_CREATION_APP_UI_DESIGN_ASSET_KIND,
|
||||
type GameCreationAppAssetCategory,
|
||||
gameCreationAppAssetCategory,
|
||||
gameCreationAppAssetTags,
|
||||
@@ -323,7 +324,7 @@ export function projectResourcesFromReadModels(
|
||||
}
|
||||
const assetCategory = gameCreationAppAssetCategory(asset);
|
||||
const isPendingUiPrototype =
|
||||
asset.kind === 'ui-prototype' &&
|
||||
asset.kind === GAME_CREATION_APP_UI_DESIGN_ASSET_KIND &&
|
||||
taskById.get('design-foundation')?.status !== 'completed';
|
||||
resources.push({
|
||||
id: `asset:${asset.id}`,
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
ProjectResourceCanvasPosition,
|
||||
} from '../../../../packages/shared/src/contracts/gameCreationApp';
|
||||
import {
|
||||
GAME_CREATION_APP_UI_DESIGN_ASSET_KIND,
|
||||
GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND,
|
||||
GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE,
|
||||
} from '../../../../packages/shared/src/contracts/gameCreationApp';
|
||||
@@ -6463,7 +6464,7 @@ export function registerProjectWorkbenchFoundationTests() {
|
||||
);
|
||||
manifest.assets.push({
|
||||
id: 'ui-prototype-candidate',
|
||||
kind: 'ui-prototype',
|
||||
kind: GAME_CREATION_APP_UI_DESIGN_ASSET_KIND,
|
||||
mediaType: 'image/png',
|
||||
localPath: 'assets/ui-prototype.png',
|
||||
source: {
|
||||
@@ -6513,6 +6514,85 @@ export function registerProjectWorkbenchFoundationTests() {
|
||||
).not.toBeNull();
|
||||
});
|
||||
|
||||
it('opens the UI editor bridge from a canonical ui-design prototype image', async () => {
|
||||
installResizeObserverStub();
|
||||
const manifest = createGameCreationAppManifest(
|
||||
'workbench-ui-prototype-entry',
|
||||
'UI 原型入口测试',
|
||||
);
|
||||
manifest.assets = [
|
||||
{
|
||||
id: 'ui-prototype-asset',
|
||||
kind: GAME_CREATION_APP_UI_DESIGN_ASSET_KIND,
|
||||
mediaType: 'image/png',
|
||||
localPath: 'assets/ui-prototype.png',
|
||||
source: { kind: 'canvas', taskId: 'design-foundation' },
|
||||
},
|
||||
];
|
||||
const invoke = vi.fn(
|
||||
async (command: string, args?: Record<string, unknown>) => {
|
||||
if (command === 'read_local_project_resource_graph') {
|
||||
return resourceGraphForInputs(args);
|
||||
}
|
||||
if (command === 'read_local_project_resource_canvas_layout') {
|
||||
return {
|
||||
schemaVersion: 'game-creator-resource-layout.v1',
|
||||
projectId: manifest.projectId,
|
||||
mode: args?.mode,
|
||||
revision: 0,
|
||||
positions: [],
|
||||
updatedAt: 0,
|
||||
};
|
||||
}
|
||||
if (command === 'update_local_project_resource_canvas_layout') {
|
||||
return {
|
||||
status: 'updated',
|
||||
layout: {
|
||||
schemaVersion: 'game-creator-resource-layout.v1',
|
||||
projectId: manifest.projectId,
|
||||
mode: args?.mode,
|
||||
revision: 1,
|
||||
positions: args?.positions,
|
||||
updatedAt: 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (command === 'ensure_ui_design_resource_for_prototype') {
|
||||
return null;
|
||||
}
|
||||
throw new Error(`unexpected invoke ${command}`);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
render(
|
||||
React.createElement(ProjectDevelopmentView, {
|
||||
projectName: manifest.name,
|
||||
projectPath: '/tmp/workbench-ui-prototype-entry',
|
||||
manifest,
|
||||
attachments: [],
|
||||
recentRunStatus: null,
|
||||
recentRunStopReason: null,
|
||||
supervisor: React.createElement('div', null, '项目总控'),
|
||||
onHomeOpen: vi.fn(),
|
||||
onProjectsOpen: vi.fn(),
|
||||
}),
|
||||
);
|
||||
|
||||
await openResourceBookCategory('UI 交互');
|
||||
fireEvent.click(
|
||||
await findResourceSelectButton('ui-prototype.png(待视觉验收)'),
|
||||
);
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'UI 编辑器' }));
|
||||
expect(invoke).toHaveBeenCalledWith(
|
||||
'ensure_ui_design_resource_for_prototype',
|
||||
expect.objectContaining({
|
||||
input: expect.objectContaining({
|
||||
prototypeAssetId: 'ui-prototype-asset',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('refuses to embed a non-loopback game preview in the client workbench', () => {
|
||||
const manifest = createGameCreationAppManifest(
|
||||
'workbench-remote-preview',
|
||||
|
||||
@@ -480,6 +480,9 @@ export interface GameCreationAppAssetManifestEntry {
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
/** UI 设计图(原型图与页面设计图)资产的唯一 kind。 */
|
||||
export const GAME_CREATION_APP_UI_DESIGN_ASSET_KIND = 'ui-design' as const;
|
||||
|
||||
/** UI Editor JSON 文档资产的唯一 kind 与媒体类型。 */
|
||||
export const GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND =
|
||||
'ui-design-doc' as const;
|
||||
@@ -494,7 +497,7 @@ export const GAME_CREATION_APP_CANONICAL_ASSET_KINDS = [
|
||||
'icon',
|
||||
'icon-spritesheet',
|
||||
'icon-spec',
|
||||
'ui-design',
|
||||
GAME_CREATION_APP_UI_DESIGN_ASSET_KIND,
|
||||
GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND,
|
||||
'publication-material',
|
||||
'spec',
|
||||
@@ -595,7 +598,7 @@ export const GAME_CREATION_APP_ASSET_CATEGORY_BY_KIND: Record<
|
||||
icon: 'ui-interaction',
|
||||
'icon-spritesheet': 'ui-interaction',
|
||||
'icon-spec': 'ui-interaction',
|
||||
'ui-design': 'ui-interaction',
|
||||
[GAME_CREATION_APP_UI_DESIGN_ASSET_KIND]: 'ui-interaction',
|
||||
[GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND]: 'ui-interaction',
|
||||
'publication-material': 'unclassified',
|
||||
spec: 'document',
|
||||
|
||||
Reference in New Issue
Block a user