修复图片画布素材上传鉴权

统一侧栏上传入口走上传工作流

未登录素材上传先弹账号入口,不再打开文件选择器

补充上传鉴权回归测试和编辑器拆分文档记录
This commit is contained in:
2026-06-17 08:35:00 +08:00
parent e07002c1dc
commit be3d91f1c5
6 changed files with 67 additions and 12 deletions

View File

@@ -1648,7 +1648,6 @@ export function ImageCanvasEditorView() {
<ImageCanvasSidebarView
activeSidebarPanel={activeSidebarPanel}
assetListRef={assetListRef}
uploadInputRef={uploadInputRef}
assetPointerDragRef={assetPointerDragRef}
suppressAssetClickRef={suppressAssetClickRef}
assets={assets}
@@ -1673,7 +1672,6 @@ export function ImageCanvasEditorView() {
setRenamingFolder={setRenamingFolder}
setRenamingAsset={setRenamingAsset}
setActiveUploadFolderId={setActiveUploadFolderId}
setUploadTarget={setUploadTarget}
setUploadDropTarget={setUploadDropTarget}
setAssetPointerDrag={setAssetPointerDrag}
setSelectedAssetIds={setSelectedAssetIds}
@@ -1684,6 +1682,7 @@ export function ImageCanvasEditorView() {
onAssetMarqueePointerUp={handleAssetMarqueePointerUp}
updateAssetMoveDropFolder={updateAssetMoveDropFolder}
addUploadedFiles={addUploadedFiles}
requestUpload={requestUpload}
moveAssetToFolder={moveAssetToFolder}
commitNewAssetFolder={commitNewAssetFolder}
toggleAssetFolder={toggleAssetFolder}

View File

@@ -57,7 +57,6 @@ type UploadFilesOptions = {
type ImageCanvasSidebarViewProps = {
activeSidebarPanel: SidebarPanel | null;
assetListRef: RefObject<HTMLDivElement | null>;
uploadInputRef: RefObject<HTMLInputElement | null>;
assetPointerDragRef: { current: AssetPointerDragState | null };
suppressAssetClickRef: { current: boolean };
assets: EditorAsset[];
@@ -86,7 +85,6 @@ type ImageCanvasSidebarViewProps = {
SetStateAction<{ assetId: string; value: string } | null>
>;
setActiveUploadFolderId: Dispatch<SetStateAction<string>>;
setUploadTarget: Dispatch<SetStateAction<UploadTarget>>;
setUploadDropTarget: Dispatch<SetStateAction<'canvas' | 'assets' | null>>;
setAssetPointerDrag: Dispatch<SetStateAction<AssetPointerDragState | null>>;
setSelectedAssetIds: Dispatch<SetStateAction<Set<string>>>;
@@ -103,6 +101,7 @@ type ImageCanvasSidebarViewProps = {
) => void;
updateAssetMoveDropFolder: (folderId: string | null) => void;
addUploadedFiles: (files: FileList | File[], options?: UploadFilesOptions) => void;
requestUpload: (target: UploadTarget) => void;
moveAssetToFolder: (assetId: string, folderId: string) => void;
commitNewAssetFolder: () => void | Promise<void>;
toggleAssetFolder: (folderId: string) => void;
@@ -133,7 +132,6 @@ type ImageCanvasSidebarViewProps = {
export function ImageCanvasSidebarView({
activeSidebarPanel,
assetListRef,
uploadInputRef,
assetPointerDragRef,
suppressAssetClickRef,
assets,
@@ -158,7 +156,6 @@ export function ImageCanvasSidebarView({
setRenamingFolder,
setRenamingAsset,
setActiveUploadFolderId,
setUploadTarget,
setUploadDropTarget,
setAssetPointerDrag,
setSelectedAssetIds,
@@ -169,6 +166,7 @@ export function ImageCanvasSidebarView({
onAssetMarqueePointerUp,
updateAssetMoveDropFolder,
addUploadedFiles,
requestUpload,
moveAssetToFolder,
commitNewAssetFolder,
toggleAssetFolder,
@@ -427,8 +425,7 @@ export function ImageCanvasSidebarView({
icon={ImagePlus}
onClick={() => {
setActiveUploadFolderId(folder.id);
setUploadTarget('asset');
uploadInputRef.current?.click();
requestUpload('asset');
}}
/>
</div>

View File

@@ -141,6 +141,9 @@ function UploadWorkflowHarness({
>
</button>
<button type="button" onClick={() => workflow.requestUpload('asset')}>
</button>
<button
type="button"
onClick={() =>
@@ -171,6 +174,12 @@ function UploadWorkflowHarness({
>
</button>
<button
type="button"
onClick={() => workflow.requestUpload('character-spec')}
>
</button>
</div>
);
}
@@ -227,6 +236,40 @@ describe('useImageCanvasUploadWorkflow', () => {
});
});
it('opens login instead of the asset file picker when protected data is unavailable', () => {
const openEditorLoginModal = vi.fn();
render(
<UploadWorkflowHarness
canAccessProtectedData={false}
openEditorLoginModal={openEditorLoginModal}
/>,
);
const uploadInput = screen.getByLabelText('上传图片文件') as HTMLInputElement;
const clickUploadInput = vi.spyOn(uploadInput, 'click');
fireEvent.click(screen.getByRole('button', { name: '请求素材上传' }));
expect(openEditorLoginModal).toHaveBeenCalledTimes(1);
expect(clickUploadInput).not.toHaveBeenCalled();
});
it('keeps generation reference uploads local and opens the file picker without login', () => {
const openEditorLoginModal = vi.fn();
render(
<UploadWorkflowHarness
canAccessProtectedData={false}
openEditorLoginModal={openEditorLoginModal}
/>,
);
const uploadInput = screen.getByLabelText('上传图片文件') as HTMLInputElement;
const clickUploadInput = vi.spyOn(uploadInput, 'click');
fireEvent.click(screen.getByRole('button', { name: '请求角色规范上传' }));
expect(openEditorLoginModal).not.toHaveBeenCalled();
expect(clickUploadInput).toHaveBeenCalledTimes(1);
});
it('creates an uploading asset card, adds a canvas layer, and patches the layer with the persisted asset id', async () => {
const deferredAsset = createDeferred<{
assetId: string;

View File

@@ -461,10 +461,24 @@ export function useImageCanvasUploadWorkflow({
],
);
const requestUpload = useCallback((target: UploadTarget = 'asset') => {
setUploadTarget(target);
uploadInputRef.current?.click();
}, []);
const openUploadPicker = useCallback(
(target: UploadTarget) => {
setUploadTarget(target);
uploadInputRef.current?.click();
},
[setUploadTarget],
);
const requestUpload = useCallback(
(target: UploadTarget = 'asset') => {
if (target === 'asset' && !canAccessProtectedDataRef.current) {
openEditorLoginModal();
return;
}
openUploadPicker(target);
},
[openEditorLoginModal, openUploadPicker],
);
const handleUploadInputChange = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {