feat(ui): improve image upload handling

This commit is contained in:
psychedelicious 2023-05-26 14:19:32 +10:00
parent 17164a37a8
commit 0d5f44b153
7 changed files with 45 additions and 26 deletions

View File

@ -8,7 +8,10 @@ import type { TypedStartListening, TypedAddListener } from '@reduxjs/toolkit';
import type { RootState, AppDispatch } from '../../store';
import { addInitialImageSelectedListener } from './listeners/initialImageSelected';
import { addImageUploadedListener } from './listeners/imageUploaded';
import {
addImageUploadedFulfilledListener,
addImageUploadedRejectedListener,
} from './listeners/imageUploaded';
import { addRequestedImageDeletionListener } from './listeners/imageDeleted';
import { addUserInvokedCanvasListener } from './listeners/userInvokedCanvas';
import { addUserInvokedNodesListener } from './listeners/userInvokedNodes';
@ -47,23 +50,28 @@ export type AppListenerEffect = ListenerEffect<
AppDispatch
>;
addImageUploadedListener();
// Image uploads
addImageUploadedFulfilledListener();
addImageUploadedRejectedListener();
addInitialImageSelectedListener();
addRequestedImageDeletionListener();
// Invoking stuff
addUserInvokedCanvasListener();
addUserInvokedNodesListener();
addUserInvokedTextToImageListener();
addUserInvokedImageToImageListener();
addSessionReadyToInvokeListener();
// Canvas actions
addCanvasSavedToGalleryListener();
addCanvasDownloadedAsImageListener();
addCanvasCopiedToClipboardListener();
addCanvasMergedListener();
// socketio
addGeneratorProgressListener();
addGraphExecutionStateCompleteListener();
addInvocationCompleteListener();

View File

@ -52,7 +52,6 @@ export const addCanvasMergedListener = () => {
dispatch(
imageUploaded({
imageType: 'intermediates',
formData: {
file: new File([blob], filename, { type: 'image/png' }),
},
@ -65,7 +64,7 @@ export const addCanvasMergedListener = () => {
action.meta.arg.formData.file.name === filename
);
const mergedCanvasImage = payload.response;
const mergedCanvasImage = payload;
dispatch(
setMergedCanvas({

View File

@ -29,7 +29,6 @@ export const addCanvasSavedToGalleryListener = () => {
dispatch(
imageUploaded({
imageType: 'results',
formData: {
file: new File([blob], 'mergedCanvas.png', { type: 'image/png' }),
},

View File

@ -7,17 +7,23 @@ import { initialImageSelected } from 'features/parameters/store/actions';
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
import { resultAdded } from 'features/gallery/store/resultsSlice';
import { isResultsImageDTO, isUploadsImageDTO } from 'services/types/guards';
import { log } from 'app/logging/useLogger';
export const addImageUploadedListener = () => {
const moduleLog = log.child({ namespace: 'image' });
export const addImageUploadedFulfilledListener = () => {
startAppListening({
predicate: (action): action is ReturnType<typeof imageUploaded.fulfilled> =>
imageUploaded.fulfilled.match(action) &&
action.payload.response.is_intermediate === false,
action.payload.is_intermediate === false,
effect: (action, { dispatch, getState }) => {
const { response: image } = action.payload;
const image = action.payload;
moduleLog.debug({ arg: '<Blob>', image }, 'Image uploaded');
const state = getState();
// Handle uploads
if (isUploadsImageDTO(image)) {
dispatch(uploadAdded(image));
@ -36,9 +42,26 @@ export const addImageUploadedListener = () => {
}
}
// Handle results
// TODO: Can this ever happen? I don't think so...
if (isResultsImageDTO(image)) {
dispatch(resultAdded(image));
}
},
});
};
export const addImageUploadedRejectedListener = () => {
startAppListening({
actionCreator: imageUploaded.rejected,
effect: (action, { dispatch }) => {
dispatch(
addToast({
title: 'Image Upload Failed',
description: action.error.message,
status: 'error',
})
);
},
});
};

View File

@ -106,19 +106,16 @@ export const addUserInvokedCanvasListener = () => {
);
// Wait for the image to be uploaded
const [{ payload: basePayload }] = await take(
const [{ payload: baseImageDTO }] = await take(
(action): action is ReturnType<typeof imageUploaded.fulfilled> =>
imageUploaded.fulfilled.match(action) &&
action.meta.arg.formData.file.name === baseFilename
);
// Update the base node with the image name and type
const { image_name: baseName, image_type: baseType } =
basePayload.response;
baseNode.image = {
image_name: baseName,
image_type: baseType,
image_name: baseImageDTO.image_name,
image_type: baseImageDTO.image_type,
};
}
@ -135,19 +132,16 @@ export const addUserInvokedCanvasListener = () => {
);
// Wait for the mask to be uploaded
const [{ payload: maskPayload }] = await take(
const [{ payload: maskImageDTO }] = await take(
(action): action is ReturnType<typeof imageUploaded.fulfilled> =>
imageUploaded.fulfilled.match(action) &&
action.meta.arg.formData.file.name === maskFilename
);
// Update the base node with the image name and type
const { image_name: maskName, image_type: maskType } =
maskPayload.response;
baseNode.mask = {
image_name: maskName,
image_type: maskType,
image_name: maskImageDTO.image_name,
image_type: maskImageDTO.image_type,
};
}

View File

@ -68,7 +68,6 @@ const ImageUploader = (props: ImageUploaderProps) => {
async (file: File) => {
dispatch(
imageUploaded({
imageType: 'uploads',
formData: { file },
activeTabName,
})

View File

@ -53,11 +53,8 @@ export const imageUploaded = createAppAsyncThunk(
// strip out `activeTabName` from arg - the route does not need it
const { activeTabName, ...rest } = arg;
const response = await ImagesService.uploadImage(rest);
const { location } = getHeaders(response);
imagesLog.debug({ arg: '<Blob>', response, location }, 'Image uploaded');
return { response, location };
return response;
}
);