diff --git a/invokeai/frontend/web/src/common/util/convertImageUrlToBlob.ts b/invokeai/frontend/web/src/common/util/convertImageUrlToBlob.ts index 42fdd466093..44062fa025b 100644 --- a/invokeai/frontend/web/src/common/util/convertImageUrlToBlob.ts +++ b/invokeai/frontend/web/src/common/util/convertImageUrlToBlob.ts @@ -8,7 +8,7 @@ import { $authToken } from 'app/store/nanostores/authToken'; */ export const convertImageUrlToBlob = async (url: string) => - new Promise((resolve) => { + new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); @@ -17,17 +17,23 @@ export const convertImageUrlToBlob = async (url: string) => const context = canvas.getContext('2d'); if (!context) { + reject(new Error('Failed to get canvas context')); return; } context.drawImage(img, 0, 0); - resolve( - new Promise((resolve) => { - canvas.toBlob(function (blob) { - resolve(blob); - }, 'image/png'); - }) - ); + canvas.toBlob((blob) => { + if (blob) { + resolve(blob); + } else { + reject(new Error('Failed to convert image to blob')); + } + }, 'image/png'); }; + + img.onerror = () => { + reject(new Error('Image failed to load. The URL may be invalid or the object may not exist.')); + }; + img.crossOrigin = $authToken.get() ? 'use-credentials' : 'anonymous'; img.src = url; }); diff --git a/invokeai/frontend/web/src/features/stylePresets/components/ActiveStylePreset.tsx b/invokeai/frontend/web/src/features/stylePresets/components/ActiveStylePreset.tsx index d72df6434eb..8a68ce63960 100644 --- a/invokeai/frontend/web/src/features/stylePresets/components/ActiveStylePreset.tsx +++ b/invokeai/frontend/web/src/features/stylePresets/components/ActiveStylePreset.tsx @@ -1,4 +1,4 @@ -import { Badge, Flex, IconButton, Text, Tooltip } from '@invoke-ai/ui-library'; +import { Badge, Flex, IconButton, Spacer, Text, Tooltip } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { negativePromptChanged, positivePromptChanged } from 'features/controlLayers/store/controlLayersSlice'; import { usePresetModifiedPrompts } from 'features/stylePresets/hooks/usePresetModifiedPrompts'; @@ -69,45 +69,40 @@ export const ActiveStylePreset = () => { ); } return ( - - - - - - {activeStylePreset.name} - - - - - - } - /> - - - } - /> - - - } - /> - - + + + + {activeStylePreset.name} + + + + } + /> + + + } + /> + + + } + /> + ); }; diff --git a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetForm.tsx b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetForm.tsx index 674c179edd3..2fd703103e1 100644 --- a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetForm.tsx +++ b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetForm.tsx @@ -30,8 +30,8 @@ export const StylePresetForm = ({ updatingStylePresetId: string | null; formData: StylePresetFormData | null; }) => { - const [createStylePreset] = useCreateStylePresetMutation(); - const [updateStylePreset] = useUpdateStylePresetMutation(); + const [createStylePreset, { isLoading: isCreating }] = useCreateStylePresetMutation(); + const [updateStylePreset, { isLoading: isUpdating }] = useUpdateStylePresetMutation(); const { t } = useTranslation(); const allowPrivateStylePresets = useAppSelector((s) => s.config.allowPrivateStylePresets); @@ -109,7 +109,11 @@ export const StylePresetForm = ({ {allowPrivateStylePresets ? : } - diff --git a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetModal.tsx b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetModal.tsx index cccae93c186..5ae1db7af92 100644 --- a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetModal.tsx +++ b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetForm/StylePresetModal.tsx @@ -48,9 +48,13 @@ export const StylePresetModal = () => { } else { let file = null; if (data.imageUrl) { - const blob = await convertImageUrlToBlob(data.imageUrl); - if (blob) { - file = new File([blob], 'style_preset.png', { type: 'image/png' }); + try { + const blob = await convertImageUrlToBlob(data.imageUrl); + if (blob) { + file = new File([blob], 'style_preset.png', { type: 'image/png' }); + } + } catch (error) { + // do nothing } } setFormData({ diff --git a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetImage.tsx b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetImage.tsx index c32dfcf3a5e..b0a2a38bcf0 100644 --- a/invokeai/frontend/web/src/features/stylePresets/components/StylePresetImage.tsx +++ b/invokeai/frontend/web/src/features/stylePresets/components/StylePresetImage.tsx @@ -21,6 +21,7 @@ const StylePresetImage = ({ presetImageUrl, imageWidth }: { presetImageUrl: stri /> ) } + p={2} > { py={2} px={3} borderRadius="base" - gap={1} + gap={2} role="button" _hover={_hover} transitionProperty="background-color" transitionDuration="normal" + w="full" > - } size="sm" /> ); diff --git a/invokeai/frontend/web/src/services/api/endpoints/stylePresets.ts b/invokeai/frontend/web/src/services/api/endpoints/stylePresets.ts index 2bc945f86e3..44023b59d16 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/stylePresets.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/stylePresets.ts @@ -94,7 +94,7 @@ export const stylePresetsApi = api.injectEndpoints({ }), exportStylePresets: build.query({ query: () => ({ - url: buildStylePresetsUrl('/export'), + url: buildStylePresetsUrl('export'), responseHandler: (response) => response.text(), }), providesTags: ['FetchOnReconnect', { type: 'StylePreset', id: LIST_TAG }],