|
import { logger } from 'app/logging/logger'; |
|
import type { AppDispatch, RootState } from 'app/store/store'; |
|
import { deepClone } from 'common/util/deepClone'; |
|
import { stagingAreaImageStaged } from 'features/controlLayers/store/canvasStagingAreaSlice'; |
|
import { boardIdSelected, galleryViewChanged, imageSelected, offsetChanged } from 'features/gallery/store/gallerySlice'; |
|
import { $nodeExecutionStates, upsertExecutionState } from 'features/nodes/hooks/useExecutionState'; |
|
import { zNodeStatus } from 'features/nodes/types/invocation'; |
|
import { CANVAS_OUTPUT_PREFIX } from 'features/nodes/util/graph/graphBuilderUtils'; |
|
import { boardsApi } from 'services/api/endpoints/boards'; |
|
import { getImageDTOSafe, imagesApi } from 'services/api/endpoints/images'; |
|
import type { ImageDTO, S } from 'services/api/types'; |
|
import { getCategories, getListImagesUrl } from 'services/api/util'; |
|
import { $lastProgressEvent } from 'services/events/stores'; |
|
import type { JsonObject } from 'type-fest'; |
|
|
|
const log = logger('events'); |
|
|
|
const isCanvasOutputNode = (data: S['InvocationCompleteEvent']) => { |
|
return data.invocation_source_id.split(':')[0] === CANVAS_OUTPUT_PREFIX; |
|
}; |
|
|
|
const nodeTypeDenylist = ['load_image', 'image']; |
|
|
|
export const buildOnInvocationComplete = (getState: () => RootState, dispatch: AppDispatch) => { |
|
const addImageToGallery = (data: S['InvocationCompleteEvent'], imageDTO: ImageDTO) => { |
|
if (nodeTypeDenylist.includes(data.invocation.type)) { |
|
log.trace('Skipping node type denylisted'); |
|
return; |
|
} |
|
|
|
if (imageDTO.is_intermediate) { |
|
return; |
|
} |
|
|
|
|
|
dispatch( |
|
boardsApi.util.updateQueryData('getBoardImagesTotal', imageDTO.board_id ?? 'none', (draft) => { |
|
draft.total += 1; |
|
}) |
|
); |
|
|
|
dispatch( |
|
imagesApi.util.invalidateTags([ |
|
{ type: 'Board', id: imageDTO.board_id ?? 'none' }, |
|
{ |
|
type: 'ImageList', |
|
id: getListImagesUrl({ |
|
board_id: imageDTO.board_id ?? 'none', |
|
categories: getCategories(imageDTO), |
|
}), |
|
}, |
|
]) |
|
); |
|
|
|
const { shouldAutoSwitch, selectedBoardId, galleryView, offset } = getState().gallery; |
|
|
|
|
|
if (shouldAutoSwitch) { |
|
|
|
if (imageDTO.board_id && imageDTO.board_id !== selectedBoardId) { |
|
dispatch( |
|
boardIdSelected({ |
|
boardId: imageDTO.board_id, |
|
selectedImageName: imageDTO.image_name, |
|
}) |
|
); |
|
} else if (!imageDTO.board_id && selectedBoardId !== 'none') { |
|
dispatch( |
|
boardIdSelected({ |
|
boardId: 'none', |
|
selectedImageName: imageDTO.image_name, |
|
}) |
|
); |
|
} else { |
|
|
|
dispatch(imageSelected(imageDTO)); |
|
|
|
if (galleryView !== 'images') { |
|
|
|
dispatch(galleryViewChanged('images')); |
|
} else if (offset > 0) { |
|
|
|
dispatch(offsetChanged({ offset: 0 })); |
|
} |
|
} |
|
} |
|
}; |
|
|
|
const getResultImageDTO = (data: S['InvocationCompleteEvent']) => { |
|
const { result } = data; |
|
if (result.type === 'image_output') { |
|
return getImageDTOSafe(result.image.image_name); |
|
} |
|
return null; |
|
}; |
|
|
|
const handleOriginWorkflows = async (data: S['InvocationCompleteEvent']) => { |
|
const { result, invocation_source_id } = data; |
|
|
|
const nes = deepClone($nodeExecutionStates.get()[invocation_source_id]); |
|
if (nes) { |
|
nes.status = zNodeStatus.enum.COMPLETED; |
|
if (nes.progress !== null) { |
|
nes.progress = 1; |
|
} |
|
nes.outputs.push(result); |
|
upsertExecutionState(nes.nodeId, nes); |
|
} |
|
|
|
const imageDTO = await getResultImageDTO(data); |
|
|
|
if (imageDTO && !imageDTO.is_intermediate) { |
|
addImageToGallery(data, imageDTO); |
|
} |
|
}; |
|
|
|
const handleOriginCanvas = async (data: S['InvocationCompleteEvent']) => { |
|
const imageDTO = await getResultImageDTO(data); |
|
|
|
if (!imageDTO) { |
|
return; |
|
} |
|
|
|
if (data.destination === 'canvas') { |
|
|
|
if (isCanvasOutputNode(data)) { |
|
if (data.result.type === 'image_output') { |
|
dispatch(stagingAreaImageStaged({ stagingAreaImage: { imageDTO, offsetX: 0, offsetY: 0 } })); |
|
} |
|
addImageToGallery(data, imageDTO); |
|
} |
|
} else if (!imageDTO.is_intermediate) { |
|
|
|
addImageToGallery(data, imageDTO); |
|
} |
|
}; |
|
|
|
const handleOriginOther = async (data: S['InvocationCompleteEvent']) => { |
|
const imageDTO = await getResultImageDTO(data); |
|
|
|
if (imageDTO && !imageDTO.is_intermediate) { |
|
addImageToGallery(data, imageDTO); |
|
} |
|
}; |
|
|
|
return async (data: S['InvocationCompleteEvent']) => { |
|
log.debug({ data } as JsonObject, `Invocation complete (${data.invocation.type}, ${data.invocation_source_id})`); |
|
|
|
if (data.origin === 'workflows') { |
|
await handleOriginWorkflows(data); |
|
} else if (data.origin === 'canvas') { |
|
await handleOriginCanvas(data); |
|
} else { |
|
await handleOriginOther(data); |
|
} |
|
|
|
$lastProgressEvent.set(null); |
|
}; |
|
}; |
|
|