d1581892d7
- 素材重命名(跨范围契约):`rename_local_project_asset` 现在要求 `expectedProjectId` + `expectedProjectRevision`,前端按删除 / 分类保存同一套 CAS 口径补齐——先 `get_local_game_project_revision` 读当前 revision 再连同项目身份提交,不用可能过期的本地缓存值 - 失败文案统一:新增 `projectAssetCommandErrorMessage`,把 `project-identity-conflict` / `project-revision-conflict` 翻成用户可读中文,重命名 / 删除 / 分类保存三条链路共用一份映射,其余错误原样透出 - index.tsx:资源面板下载按 `resolveDownloadablePanelEntries` 过滤,版本卡这类合成 path 的条目不再进入落盘链路 - index.tsx:`characterAnimationPanel` 纳入画布浮层开关判据(抽 `resolveResourceCanvasFloatingPanelOpen`),「生成动画」面板与快速编辑 / 信息浮层共用同一条「点外部 / Esc 关闭」规则 - index.tsx:去掉 `ResourceBookScene` 上重复的 `onWheel`,滚轮只由 manager 上的原生 `passive:false` 监听处理,平移 / 缩放不再被翻倍 - index.tsx:快速编辑的源资源在层 id 命中不到时回落到已正规化的 `asset:<id>`,重试不再静默什么都不做;取不到时给出可见失败 - ResourceCanvasPanelView.tsx:下载按钮按可下载条数判可用、不再在上传中显示下载转圈;上传中禁掉 × / Esc / 遮罩三条关闭路径;预览占位文案抽 helper - GameRunVersionPicker.tsx:portal 菜单在滚动 / 缩放后重算位置;外部点击判定沿用共享 `useImageCanvasFloatingOptionDismiss` + `menuRef` 边界(review 该条已修,保留现状并补位置用例) - ResourceCanvasGenerationPanelView.tsx:`submitting` 改 `finally` 收回,成功路径不再永久锁住面板 - ResourceAssetDeleteDialog.tsx / ResourceRenameDialog.tsx / ResourceClassificationPanel.tsx:在飞时 `closeOnEscape` / `closeOnBackdrop` 与头部 × 一起挡住 - resourceEditModel.ts / resourceCanvasToolbarModel.ts / useProjectResourceCardPreviews.ts / projectResourceLiveUpdateModel.ts:抽 `resourceBaseName`、`canonicalProjectedResourceMediaType` 参数收窄去掉强转、删未使用参数、补「IO 失败会 reject」的签名说明 - resourceCanvasHistoryModel.ts:`resourceCanvasSnapshotsEqual` 不再比较不可恢复的 `manuallyPlaced`,消除「压进历史但撤销是空操作」 - resourceCanvasSectionMapping.ts:删掉从未接线、且注释与实现相矛盾的 `LEGACY_RESOURCE_CANVAS_SECTION_FALLBACK` - resourceCanvasChrome.css:`.game-resource-panel-grid` 补 `flex: 1 1 auto; min-height: 0`,卡片网格成为真正的滚动区 - 用例:重命名 CAS 载荷与读序、CAS 拒绝文案、版本卡下载门禁、上传中关闭路径、浮层判据、菜单跟随滚动、分区映射
108 lines
3.1 KiB
TypeScript
108 lines
3.1 KiB
TypeScript
import { useState } from 'react';
|
||
|
||
import { PlatformActionButton } from '../../../../../packages/shared/src/components/PlatformActionButton';
|
||
import { PlatformTextField } from '../../../../../packages/shared/src/components/PlatformTextField';
|
||
import type { GameCreationAppAssetManifestEntry } from '../../../../../packages/shared/src/contracts/gameCreationApp';
|
||
import { ThemedModal } from '../../components/modal/ThemedModal';
|
||
|
||
export type RenameLocalProjectAssetResult = {
|
||
asset: GameCreationAppAssetManifestEntry;
|
||
previousLocalPath: string;
|
||
committedProjectRevision: number;
|
||
};
|
||
|
||
function assetFileName(localPath: string) {
|
||
return localPath.split(/[\\/]/u).pop() ?? localPath;
|
||
}
|
||
|
||
type ResourceRenameDialogProps = {
|
||
open: boolean;
|
||
asset: GameCreationAppAssetManifestEntry;
|
||
renaming: boolean;
|
||
error: string | null;
|
||
onClose: () => void;
|
||
onConfirm: (newFileName: string) => void;
|
||
};
|
||
|
||
/**
|
||
* 素材重命名面板。
|
||
*
|
||
* 只输入新文件名:目录由资产的 `localPath` 决定,用户不能换目录;
|
||
* 扩展名一致、同名冲突等规则由 Rust 侧 `rename_local_project_asset` 强校验,
|
||
* 这里只做输入与错误呈现。
|
||
*/
|
||
export function ResourceRenameDialog({
|
||
open,
|
||
asset,
|
||
renaming,
|
||
error,
|
||
onClose,
|
||
onConfirm,
|
||
}: ResourceRenameDialogProps) {
|
||
const [draft, setDraft] = useState(() => assetFileName(asset.localPath));
|
||
|
||
return (
|
||
<ThemedModal
|
||
open={open}
|
||
ariaLabel="重命名素材"
|
||
onClose={onClose}
|
||
// 重命名在飞时头部 × / 取消 / 重命名都已禁用,Escape 与遮罩也必须一起挡住,
|
||
// 保持同一个"在飞不可关闭"的判据。
|
||
closeOnBackdrop={!renaming}
|
||
closeOnEscape={!renaming}
|
||
panelClassName="game-approval-dialog game-resource-rename-dialog"
|
||
>
|
||
<header>
|
||
<div>
|
||
<h2>重命名素材</h2>
|
||
<p>{asset.localPath}</p>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
aria-label="关闭重命名素材"
|
||
onClick={onClose}
|
||
disabled={renaming}
|
||
>
|
||
×
|
||
</button>
|
||
</header>
|
||
<div className="game-resource-rename-body">
|
||
<PlatformTextField
|
||
aria-label="新文件名"
|
||
value={draft}
|
||
disabled={renaming}
|
||
autoFocus
|
||
onChange={(event) => setDraft(event.currentTarget.value)}
|
||
onKeyDown={(event) => {
|
||
if (event.key === 'Enter' && !renaming && draft.trim() !== '') {
|
||
event.preventDefault();
|
||
onConfirm(draft);
|
||
}
|
||
}}
|
||
/>
|
||
{error ? (
|
||
<p className="game-resource-rename-error" role="alert">
|
||
{error}
|
||
</p>
|
||
) : null}
|
||
</div>
|
||
<footer>
|
||
<PlatformActionButton
|
||
tone="secondary"
|
||
onClick={onClose}
|
||
disabled={renaming}
|
||
>
|
||
取消
|
||
</PlatformActionButton>
|
||
<PlatformActionButton
|
||
aria-label="确认重命名素材"
|
||
onClick={() => onConfirm(draft)}
|
||
disabled={renaming || draft.trim() === ''}
|
||
>
|
||
重命名
|
||
</PlatformActionButton>
|
||
</footer>
|
||
</ThemedModal>
|
||
);
|
||
}
|