mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into tiled-upscaling-graph
This commit is contained in:
commit
fdb97c1d02
@ -14,6 +14,10 @@ To use a community workflow, download the the `.json` node graph file and load i
|
|||||||
|
|
||||||
- Community Nodes
|
- Community Nodes
|
||||||
+ [Average Images](#average-images)
|
+ [Average Images](#average-images)
|
||||||
|
+ [Clean Image Artifacts After Cut](#clean-image-artifacts-after-cut)
|
||||||
|
+ [Close Color Mask](#close-color-mask)
|
||||||
|
+ [Clothing Mask](#clothing-mask)
|
||||||
|
+ [Contrast Limited Adaptive Histogram Equalization](#contrast-limited-adaptive-histogram-equalization)
|
||||||
+ [Depth Map from Wavefront OBJ](#depth-map-from-wavefront-obj)
|
+ [Depth Map from Wavefront OBJ](#depth-map-from-wavefront-obj)
|
||||||
+ [Film Grain](#film-grain)
|
+ [Film Grain](#film-grain)
|
||||||
+ [Generative Grammar-Based Prompt Nodes](#generative-grammar-based-prompt-nodes)
|
+ [Generative Grammar-Based Prompt Nodes](#generative-grammar-based-prompt-nodes)
|
||||||
@ -22,16 +26,22 @@ To use a community workflow, download the the `.json` node graph file and load i
|
|||||||
+ [Halftone](#halftone)
|
+ [Halftone](#halftone)
|
||||||
+ [Ideal Size](#ideal-size)
|
+ [Ideal Size](#ideal-size)
|
||||||
+ [Image and Mask Composition Pack](#image-and-mask-composition-pack)
|
+ [Image and Mask Composition Pack](#image-and-mask-composition-pack)
|
||||||
|
+ [Image Dominant Color](#image-dominant-color)
|
||||||
+ [Image to Character Art Image Nodes](#image-to-character-art-image-nodes)
|
+ [Image to Character Art Image Nodes](#image-to-character-art-image-nodes)
|
||||||
+ [Image Picker](#image-picker)
|
+ [Image Picker](#image-picker)
|
||||||
|
+ [Image Resize Plus](#image-resize-plus)
|
||||||
+ [Load Video Frame](#load-video-frame)
|
+ [Load Video Frame](#load-video-frame)
|
||||||
+ [Make 3D](#make-3d)
|
+ [Make 3D](#make-3d)
|
||||||
|
+ [Mask Operations](#mask-operations)
|
||||||
+ [Match Histogram](#match-histogram)
|
+ [Match Histogram](#match-histogram)
|
||||||
|
+ [Negative Image](#negative-image)
|
||||||
+ [Oobabooga](#oobabooga)
|
+ [Oobabooga](#oobabooga)
|
||||||
+ [Prompt Tools](#prompt-tools)
|
+ [Prompt Tools](#prompt-tools)
|
||||||
+ [Remote Image](#remote-image)
|
+ [Remote Image](#remote-image)
|
||||||
|
+ [Remove Background](#remove-background)
|
||||||
+ [Retroize](#retroize)
|
+ [Retroize](#retroize)
|
||||||
+ [Size Stepper Nodes](#size-stepper-nodes)
|
+ [Size Stepper Nodes](#size-stepper-nodes)
|
||||||
|
+ [Simple Skin Detection](#simple-skin-detection)
|
||||||
+ [Text font to Image](#text-font-to-image)
|
+ [Text font to Image](#text-font-to-image)
|
||||||
+ [Thresholding](#thresholding)
|
+ [Thresholding](#thresholding)
|
||||||
+ [Unsharp Mask](#unsharp-mask)
|
+ [Unsharp Mask](#unsharp-mask)
|
||||||
@ -48,6 +58,46 @@ To use a community workflow, download the the `.json` node graph file and load i
|
|||||||
|
|
||||||
**Node Link:** https://github.com/JPPhoto/average-images-node
|
**Node Link:** https://github.com/JPPhoto/average-images-node
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Clean Image Artifacts After Cut
|
||||||
|
|
||||||
|
Description: Removes residual artifacts after an image is separated from its background.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/clean-artifact-after-cut-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/clean-artifact-after-cut-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Close Color Mask
|
||||||
|
|
||||||
|
Description: Generates a mask for images based on a closely matching color, useful for color-based selections.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/close-color-mask-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/close-color-mask-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Clothing Mask
|
||||||
|
|
||||||
|
Description: Employs a U2NET neural network trained for the segmentation of clothing items in images.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/clothing-mask-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/clothing-mask-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Contrast Limited Adaptive Histogram Equalization
|
||||||
|
|
||||||
|
Description: Enhances local image contrast using adaptive histogram equalization with contrast limiting.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/clahe-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/clahe-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Depth Map from Wavefront OBJ
|
### Depth Map from Wavefront OBJ
|
||||||
|
|
||||||
@ -164,6 +214,16 @@ This includes 15 Nodes:
|
|||||||
|
|
||||||
</br><img src="https://raw.githubusercontent.com/dwringer/composition-nodes/main/composition_pack_overview.jpg" width="500" />
|
</br><img src="https://raw.githubusercontent.com/dwringer/composition-nodes/main/composition_pack_overview.jpg" width="500" />
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Image Dominant Color
|
||||||
|
|
||||||
|
Description: Identifies and extracts the dominant color from an image using k-means clustering.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/image-dominant-color-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/image-dominant-color-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Image to Character Art Image Nodes
|
### Image to Character Art Image Nodes
|
||||||
|
|
||||||
@ -185,6 +245,17 @@ This includes 15 Nodes:
|
|||||||
|
|
||||||
**Node Link:** https://github.com/JPPhoto/image-picker-node
|
**Node Link:** https://github.com/JPPhoto/image-picker-node
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Image Resize Plus
|
||||||
|
|
||||||
|
Description: Provides various image resizing options such as fill, stretch, fit, center, and crop.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/image-resize-plus-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/image-resize-plus-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Load Video Frame
|
### Load Video Frame
|
||||||
|
|
||||||
@ -209,6 +280,16 @@ This includes 15 Nodes:
|
|||||||
<img src="https://gitlab.com/srcrr/shift3d/-/raw/main/example-1.png" width="300" />
|
<img src="https://gitlab.com/srcrr/shift3d/-/raw/main/example-1.png" width="300" />
|
||||||
<img src="https://gitlab.com/srcrr/shift3d/-/raw/main/example-2.png" width="300" />
|
<img src="https://gitlab.com/srcrr/shift3d/-/raw/main/example-2.png" width="300" />
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Mask Operations
|
||||||
|
|
||||||
|
Description: Offers logical operations (OR, SUB, AND) for combining and manipulating image masks.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/mask-operations-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/mask-operations-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Match Histogram
|
### Match Histogram
|
||||||
|
|
||||||
@ -226,6 +307,16 @@ See full docs here: https://github.com/skunkworxdark/Prompt-tools-nodes/edit/mai
|
|||||||
|
|
||||||
<img src="https://github.com/skunkworxdark/match_histogram/assets/21961335/ed12f329-a0ef-444a-9bae-129ed60d6097" width="300" />
|
<img src="https://github.com/skunkworxdark/match_histogram/assets/21961335/ed12f329-a0ef-444a-9bae-129ed60d6097" width="300" />
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Negative Image
|
||||||
|
|
||||||
|
Description: Creates a negative version of an image, effective for visual effects and mask inversion.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/negative-image-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/negative-image-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Oobabooga
|
### Oobabooga
|
||||||
|
|
||||||
@ -289,6 +380,15 @@ See full docs here: https://github.com/skunkworxdark/Prompt-tools-nodes/edit/mai
|
|||||||
|
|
||||||
**Node Link:** https://github.com/fieldOfView/InvokeAI-remote_image
|
**Node Link:** https://github.com/fieldOfView/InvokeAI-remote_image
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Remove Background
|
||||||
|
|
||||||
|
Description: An integration of the rembg package to remove backgrounds from images using multiple U2NET models.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/remove-background-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/remove-background-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Retroize
|
### Retroize
|
||||||
@ -301,6 +401,17 @@ See full docs here: https://github.com/skunkworxdark/Prompt-tools-nodes/edit/mai
|
|||||||
|
|
||||||
<img src="https://github.com/Ar7ific1al/InvokeAI_nodes_retroize/assets/2306586/de8b4fa6-324c-4c2d-b36c-297600c73974" width="500" />
|
<img src="https://github.com/Ar7ific1al/InvokeAI_nodes_retroize/assets/2306586/de8b4fa6-324c-4c2d-b36c-297600c73974" width="500" />
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Simple Skin Detection
|
||||||
|
|
||||||
|
Description: Detects skin in images based on predefined color thresholds.
|
||||||
|
|
||||||
|
Node Link: https://github.com/VeyDlin/simple-skin-detection-node
|
||||||
|
|
||||||
|
View:
|
||||||
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/simple-skin-detection-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Size Stepper Nodes
|
### Size Stepper Nodes
|
||||||
|
|
||||||
@ -386,6 +497,7 @@ See full docs here: https://github.com/skunkworxdark/XYGrid_nodes/edit/main/READ
|
|||||||
|
|
||||||
<img src="https://github.com/skunkworxdark/XYGrid_nodes/blob/main/images/collage.png" width="300" />
|
<img src="https://github.com/skunkworxdark/XYGrid_nodes/blob/main/images/collage.png" width="300" />
|
||||||
|
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Example Node Template
|
### Example Node Template
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ sd-1/main/Analog-Diffusion:
|
|||||||
description: An SD-1.5 model trained on diverse analog photographs (2.13 GB)
|
description: An SD-1.5 model trained on diverse analog photographs (2.13 GB)
|
||||||
repo_id: wavymulder/Analog-Diffusion
|
repo_id: wavymulder/Analog-Diffusion
|
||||||
recommended: False
|
recommended: False
|
||||||
sd-1/main/Deliberate:
|
sd-1/main/Deliberate_v5:
|
||||||
description: Versatile model that produces detailed images up to 768px (4.27 GB)
|
description: Versatile model that produces detailed images up to 768px (4.27 GB)
|
||||||
repo_id: XpucT/Deliberate
|
path: https://huggingface.co/XpucT/Deliberate/resolve/main/Deliberate_v5.safetensors
|
||||||
recommended: False
|
recommended: False
|
||||||
sd-1/main/Dungeons-and-Diffusion:
|
sd-1/main/Dungeons-and-Diffusion:
|
||||||
description: Dungeons & Dragons characters (2.13 GB)
|
description: Dungeons & Dragons characters (2.13 GB)
|
||||||
|
@ -99,7 +99,18 @@
|
|||||||
"data": "Daten",
|
"data": "Daten",
|
||||||
"safetensors": "Safetensors",
|
"safetensors": "Safetensors",
|
||||||
"outpaint": "outpaint",
|
"outpaint": "outpaint",
|
||||||
"details": "Details"
|
"details": "Details",
|
||||||
|
"format": "Format",
|
||||||
|
"unknown": "Unbekannt",
|
||||||
|
"folder": "Ordner",
|
||||||
|
"error": "Fehler",
|
||||||
|
"installed": "Installiert",
|
||||||
|
"ai": "KI",
|
||||||
|
"file": "Datei",
|
||||||
|
"somethingWentWrong": "Etwas ist schief gelaufen",
|
||||||
|
"copyError": "$t(gallery.copy) Fehler",
|
||||||
|
"input": "Eingabe",
|
||||||
|
"notInstalled": "Nicht $t(common.installed)"
|
||||||
},
|
},
|
||||||
"gallery": {
|
"gallery": {
|
||||||
"generations": "Erzeugungen",
|
"generations": "Erzeugungen",
|
||||||
@ -696,7 +707,9 @@
|
|||||||
"menu": "Menü",
|
"menu": "Menü",
|
||||||
"loadMore": "Mehr laden",
|
"loadMore": "Mehr laden",
|
||||||
"invokeProgressBar": "Invoke Fortschrittsanzeige",
|
"invokeProgressBar": "Invoke Fortschrittsanzeige",
|
||||||
"mode": "Modus"
|
"mode": "Modus",
|
||||||
|
"resetUI": "$t(accessibility.reset) von UI",
|
||||||
|
"createIssue": "Ticket erstellen"
|
||||||
},
|
},
|
||||||
"boards": {
|
"boards": {
|
||||||
"autoAddBoard": "Automatisches Hinzufügen zum Ordner",
|
"autoAddBoard": "Automatisches Hinzufügen zum Ordner",
|
||||||
@ -718,7 +731,9 @@
|
|||||||
"deleteBoardOnly": "Nur Ordner löschen",
|
"deleteBoardOnly": "Nur Ordner löschen",
|
||||||
"deleteBoard": "Löschen Ordner",
|
"deleteBoard": "Löschen Ordner",
|
||||||
"deleteBoardAndImages": "Löschen Ordner und Bilder",
|
"deleteBoardAndImages": "Löschen Ordner und Bilder",
|
||||||
"deletedBoardsCannotbeRestored": "Gelöschte Ordner könnte nicht wiederhergestellt werden"
|
"deletedBoardsCannotbeRestored": "Gelöschte Ordner könnte nicht wiederhergestellt werden",
|
||||||
|
"movingImagesToBoard_one": "Verschiebe {{count}} Bild zu Ordner",
|
||||||
|
"movingImagesToBoard_other": "Verschiebe {{count}} Bilder in Ordner"
|
||||||
},
|
},
|
||||||
"controlnet": {
|
"controlnet": {
|
||||||
"showAdvanced": "Zeige Erweitert",
|
"showAdvanced": "Zeige Erweitert",
|
||||||
@ -932,7 +947,8 @@
|
|||||||
"embedding": {
|
"embedding": {
|
||||||
"noMatchingEmbedding": "Keine passenden Embeddings",
|
"noMatchingEmbedding": "Keine passenden Embeddings",
|
||||||
"addEmbedding": "Embedding hinzufügen",
|
"addEmbedding": "Embedding hinzufügen",
|
||||||
"incompatibleModel": "Inkompatibles Basismodell:"
|
"incompatibleModel": "Inkompatibles Basismodell:",
|
||||||
|
"noEmbeddingsLoaded": "Kein Embedding geladen"
|
||||||
},
|
},
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"booleanPolymorphicDescription": "Eine Sammlung boolescher Werte.",
|
"booleanPolymorphicDescription": "Eine Sammlung boolescher Werte.",
|
||||||
|
@ -161,6 +161,7 @@
|
|||||||
"txt2img": "Text To Image",
|
"txt2img": "Text To Image",
|
||||||
"unifiedCanvas": "Unified Canvas",
|
"unifiedCanvas": "Unified Canvas",
|
||||||
"unknown": "Unknown",
|
"unknown": "Unknown",
|
||||||
|
"unknownError": "Unknown Error",
|
||||||
"upload": "Upload"
|
"upload": "Upload"
|
||||||
},
|
},
|
||||||
"controlnet": {
|
"controlnet": {
|
||||||
@ -384,7 +385,9 @@
|
|||||||
"deleteSelection": "Delete Selection",
|
"deleteSelection": "Delete Selection",
|
||||||
"downloadSelection": "Download Selection",
|
"downloadSelection": "Download Selection",
|
||||||
"preparingDownload": "Preparing Download",
|
"preparingDownload": "Preparing Download",
|
||||||
"preparingDownloadFailed": "Problem Preparing Download"
|
"preparingDownloadFailed": "Problem Preparing Download",
|
||||||
|
"problemDeletingImages": "Problem Deleting Images",
|
||||||
|
"problemDeletingImagesDesc": "One or more images could not be deleted"
|
||||||
},
|
},
|
||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
"acceptStagingImage": {
|
"acceptStagingImage": {
|
||||||
|
@ -3,7 +3,7 @@ import { logger } from 'app/logging/logger';
|
|||||||
import { parseify } from 'common/util/serialize';
|
import { parseify } from 'common/util/serialize';
|
||||||
import { zPydanticValidationError } from 'features/system/store/zodSchemas';
|
import { zPydanticValidationError } from 'features/system/store/zodSchemas';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { get, truncate, upperFirst } from 'lodash-es';
|
import { truncate, upperFirst } from 'lodash-es';
|
||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
import { TOAST_OPTIONS, theme } from 'theme/theme';
|
import { TOAST_OPTIONS, theme } from 'theme/theme';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
@ -74,22 +74,11 @@ export const addBatchEnqueuedListener = () => {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else if (response.status !== 403) {
|
||||||
let detail = 'Unknown Error';
|
|
||||||
let duration = undefined;
|
|
||||||
if (response.status === 403 && 'body' in response) {
|
|
||||||
detail = get(response, 'body.detail', 'Unknown Error');
|
|
||||||
} else if (response.status === 403 && 'error' in response) {
|
|
||||||
detail = get(response, 'error.detail', 'Unknown Error');
|
|
||||||
} else if (response.status === 403 && 'data' in response) {
|
|
||||||
detail = get(response, 'data.detail', 'Unknown Error');
|
|
||||||
duration = 15000;
|
|
||||||
}
|
|
||||||
toast({
|
toast({
|
||||||
title: t('queue.batchFailedToQueue'),
|
title: t('queue.batchFailedToQueue'),
|
||||||
|
description: t('common.unknownError'),
|
||||||
status: 'error',
|
status: 'error',
|
||||||
description: detail,
|
|
||||||
...(duration ? { duration } : {}),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
logger('queue').error(
|
logger('queue').error(
|
||||||
|
@ -109,20 +109,9 @@ export const addControlNetImageProcessedListener = () => {
|
|||||||
t('queue.graphFailedToQueue')
|
t('queue.graphFailedToQueue')
|
||||||
);
|
);
|
||||||
|
|
||||||
// handle usage-related errors
|
|
||||||
if (error instanceof Object) {
|
if (error instanceof Object) {
|
||||||
if ('data' in error && 'status' in error) {
|
if ('data' in error && 'status' in error) {
|
||||||
if (error.status === 403) {
|
if (error.status === 403) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const detail = (error.data as any)?.detail || 'Unknown Error';
|
|
||||||
dispatch(
|
|
||||||
addToast({
|
|
||||||
title: t('queue.graphFailedToQueue'),
|
|
||||||
status: 'error',
|
|
||||||
description: detail,
|
|
||||||
duration: 15000,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
dispatch(pendingControlImagesCleared());
|
dispatch(pendingControlImagesCleared());
|
||||||
dispatch(controlAdapterImageChanged({ id, controlImage: null }));
|
dispatch(controlAdapterImageChanged({ id, controlImage: null }));
|
||||||
return;
|
return;
|
||||||
|
@ -75,25 +75,13 @@ export const addUpscaleRequestedListener = () => {
|
|||||||
t('queue.graphFailedToQueue')
|
t('queue.graphFailedToQueue')
|
||||||
);
|
);
|
||||||
|
|
||||||
// handle usage-related errors
|
if (
|
||||||
if (error instanceof Object) {
|
error instanceof Object &&
|
||||||
if ('data' in error && 'status' in error) {
|
'status' in error &&
|
||||||
if (error.status === 403) {
|
error.status === 403
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
) {
|
||||||
const detail = (error.data as any)?.detail || 'Unknown Error';
|
|
||||||
dispatch(
|
|
||||||
addToast({
|
|
||||||
title: t('queue.graphFailedToQueue'),
|
|
||||||
status: 'error',
|
|
||||||
description: detail,
|
|
||||||
duration: 15000,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
addToast({
|
addToast({
|
||||||
title: t('queue.graphFailedToQueue'),
|
title: t('queue.graphFailedToQueue'),
|
||||||
@ -101,6 +89,7 @@ export const addUpscaleRequestedListener = () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -33,6 +33,7 @@ import { actionsDenylist } from './middleware/devtools/actionsDenylist';
|
|||||||
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
||||||
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
||||||
import { createStore as createIDBKeyValStore, get, set } from 'idb-keyval';
|
import { createStore as createIDBKeyValStore, get, set } from 'idb-keyval';
|
||||||
|
import { authToastMiddleware } from 'services/api/authToastMiddleware';
|
||||||
|
|
||||||
const allReducers = {
|
const allReducers = {
|
||||||
canvas: canvasReducer,
|
canvas: canvasReducer,
|
||||||
@ -107,6 +108,7 @@ export const createStore = (uniqueStoreKey?: string) =>
|
|||||||
})
|
})
|
||||||
.concat(api.middleware)
|
.concat(api.middleware)
|
||||||
.concat(dynamicMiddlewares)
|
.concat(dynamicMiddlewares)
|
||||||
|
.concat(authToastMiddleware)
|
||||||
.prepend(listenerMiddleware.middleware),
|
.prepend(listenerMiddleware.middleware),
|
||||||
devTools: {
|
devTools: {
|
||||||
actionSanitizer,
|
actionSanitizer,
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
import { isRejectedWithValue } from '@reduxjs/toolkit';
|
||||||
|
import type { MiddlewareAPI, Middleware } from '@reduxjs/toolkit';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
|
||||||
|
export const authToastMiddleware: Middleware =
|
||||||
|
(api: MiddlewareAPI) => (next) => (action) => {
|
||||||
|
if (isRejectedWithValue(action)) {
|
||||||
|
if (action.payload.status === 403) {
|
||||||
|
const { dispatch } = api;
|
||||||
|
const customMessage =
|
||||||
|
action.payload.data.detail !== 'Forbidden'
|
||||||
|
? action.payload.data.detail
|
||||||
|
: undefined;
|
||||||
|
dispatch(
|
||||||
|
addToast({
|
||||||
|
title: t('common.somethingWentWrong'),
|
||||||
|
status: 'error',
|
||||||
|
description: customMessage,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(action);
|
||||||
|
};
|
@ -27,6 +27,8 @@ import {
|
|||||||
imagesSelectors,
|
imagesSelectors,
|
||||||
} from 'services/api/util';
|
} from 'services/api/util';
|
||||||
import { boardsApi } from './boards';
|
import { boardsApi } from './boards';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
|
||||||
export const imagesApi = api.injectEndpoints({
|
export const imagesApi = api.injectEndpoints({
|
||||||
endpoints: (build) => ({
|
endpoints: (build) => ({
|
||||||
@ -208,6 +210,16 @@ export const imagesApi = api.injectEndpoints({
|
|||||||
try {
|
try {
|
||||||
const { data } = await queryFulfilled;
|
const { data } = await queryFulfilled;
|
||||||
|
|
||||||
|
if (data.deleted_images.length < imageDTOs.length) {
|
||||||
|
dispatch(
|
||||||
|
addToast({
|
||||||
|
title: t('gallery.problemDeletingImages'),
|
||||||
|
description: t('gallery.problemDeletingImagesDesc'),
|
||||||
|
status: 'warning',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// convert to an object so we can access the successfully delete image DTOs by name
|
// convert to an object so we can access the successfully delete image DTOs by name
|
||||||
const groupedImageDTOs = keyBy(imageDTOs, 'image_name');
|
const groupedImageDTOs = keyBy(imageDTOs, 'image_name');
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user