Show toast on upload error (#2959)
A little toast for when image uploads fail. Solves #2944 ![Kapture 2024-02-27 at 09 27 12](https://github.com/tldraw/tldraw/assets/1242537/9e285622-8015-41fa-bc3d-92dccfaa7ba9) ### Change Type - [x] `patch` — Bug fix ### Release Notes - Adds a quick toast to show when image uploads fail.
This commit is contained in:
parent
2a8ae6188e
commit
4639436aad
7 changed files with 45 additions and 12 deletions
|
@ -107,6 +107,8 @@
|
||||||
"action.zoom-to-100": "Zoom to 100%",
|
"action.zoom-to-100": "Zoom to 100%",
|
||||||
"action.zoom-to-fit": "Zoom to fit",
|
"action.zoom-to-fit": "Zoom to fit",
|
||||||
"action.zoom-to-selection": "Zoom to selection",
|
"action.zoom-to-selection": "Zoom to selection",
|
||||||
|
"assets.files.upload-failed": "Upload failed",
|
||||||
|
"assets.url.failed": "Couldn't load URL preview",
|
||||||
"color-style.black": "Black",
|
"color-style.black": "Black",
|
||||||
"color-style.blue": "Blue",
|
"color-style.blue": "Blue",
|
||||||
"color-style.green": "Green",
|
"color-style.green": "Green",
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -33,7 +33,9 @@ import { registerDefaultSideEffects } from './defaultSideEffects'
|
||||||
import { defaultTools } from './defaultTools'
|
import { defaultTools } from './defaultTools'
|
||||||
import { TldrawUi, TldrawUiProps } from './ui/TldrawUi'
|
import { TldrawUi, TldrawUiProps } from './ui/TldrawUi'
|
||||||
import { TLUiComponents, useTldrawUiComponents } from './ui/context/components'
|
import { TLUiComponents, useTldrawUiComponents } from './ui/context/components'
|
||||||
|
import { useToasts } from './ui/context/toasts'
|
||||||
import { usePreloadAssets } from './ui/hooks/usePreloadAssets'
|
import { usePreloadAssets } from './ui/hooks/usePreloadAssets'
|
||||||
|
import { useTranslation } from './ui/hooks/useTranslation/useTranslation'
|
||||||
import { useDefaultEditorAssetsWithOverrides } from './utils/static-assets/assetUrls'
|
import { useDefaultEditorAssetsWithOverrides } from './utils/static-assets/assetUrls'
|
||||||
|
|
||||||
/**@public */
|
/**@public */
|
||||||
|
@ -158,6 +160,8 @@ function InsideOfEditorAndUiContext({
|
||||||
onMount,
|
onMount,
|
||||||
}: Partial<TLExternalContentProps & { onMount: TLOnMountHandler }>) {
|
}: Partial<TLExternalContentProps & { onMount: TLOnMountHandler }>) {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
|
const toasts = useToasts()
|
||||||
|
const msg = useTranslation()
|
||||||
|
|
||||||
const onMountEvent = useEvent((editor: Editor) => {
|
const onMountEvent = useEvent((editor: Editor) => {
|
||||||
const unsubs: (void | (() => void) | undefined)[] = []
|
const unsubs: (void | (() => void) | undefined)[] = []
|
||||||
|
@ -165,12 +169,19 @@ function InsideOfEditorAndUiContext({
|
||||||
unsubs.push(...registerDefaultSideEffects(editor))
|
unsubs.push(...registerDefaultSideEffects(editor))
|
||||||
|
|
||||||
// for content handling, first we register the default handlers...
|
// for content handling, first we register the default handlers...
|
||||||
registerDefaultExternalContentHandlers(editor, {
|
registerDefaultExternalContentHandlers(
|
||||||
maxImageDimension,
|
editor,
|
||||||
maxAssetSize,
|
{
|
||||||
acceptedImageMimeTypes,
|
maxImageDimension,
|
||||||
acceptedVideoMimeTypes,
|
maxAssetSize,
|
||||||
})
|
acceptedImageMimeTypes,
|
||||||
|
acceptedVideoMimeTypes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toasts,
|
||||||
|
msg,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// ...then we run the onMount prop, which may override the above
|
// ...then we run the onMount prop, which may override the above
|
||||||
unsubs.push(onMount?.(editor))
|
unsubs.push(onMount?.(editor))
|
||||||
|
|
|
@ -19,6 +19,8 @@ import {
|
||||||
getHashForString,
|
getHashForString,
|
||||||
} from '@tldraw/editor'
|
} from '@tldraw/editor'
|
||||||
import { FONT_FAMILIES, FONT_SIZES, TEXT_PROPS } from './shapes/shared/default-shape-constants'
|
import { FONT_FAMILIES, FONT_SIZES, TEXT_PROPS } from './shapes/shared/default-shape-constants'
|
||||||
|
import { TLUiToastsContextType } from './ui/context/toasts'
|
||||||
|
import { useTranslation } from './ui/hooks/useTranslation/useTranslation'
|
||||||
import { containBoxSize, downsizeImage, isGifAnimated } from './utils/assets/assets'
|
import { containBoxSize, downsizeImage, isGifAnimated } from './utils/assets/assets'
|
||||||
import { getEmbedInfo } from './utils/embeds/embeds'
|
import { getEmbedInfo } from './utils/embeds/embeds'
|
||||||
import { cleanupText, isRightToLeftLanguage, truncateStringWithEllipsis } from './utils/text/text'
|
import { cleanupText, isRightToLeftLanguage, truncateStringWithEllipsis } from './utils/text/text'
|
||||||
|
@ -42,7 +44,8 @@ export function registerDefaultExternalContentHandlers(
|
||||||
maxAssetSize,
|
maxAssetSize,
|
||||||
acceptedImageMimeTypes,
|
acceptedImageMimeTypes,
|
||||||
acceptedVideoMimeTypes,
|
acceptedVideoMimeTypes,
|
||||||
}: TLExternalContentProps
|
}: TLExternalContentProps,
|
||||||
|
{ toasts, msg }: { toasts: TLUiToastsContextType; msg: ReturnType<typeof useTranslation> }
|
||||||
) {
|
) {
|
||||||
// files -> asset
|
// files -> asset
|
||||||
editor.registerExternalAssetHandler('file', async ({ file: _file }) => {
|
editor.registerExternalAssetHandler('file', async ({ file: _file }) => {
|
||||||
|
@ -122,6 +125,9 @@ export function registerDefaultExternalContentHandlers(
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
toasts.addToast({
|
||||||
|
title: msg('assets.url.failed'),
|
||||||
|
})
|
||||||
meta = { image: '', title: truncateStringWithEllipsis(url, 32), description: '' }
|
meta = { image: '', title: truncateStringWithEllipsis(url, 32), description: '' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +247,9 @@ export function registerDefaultExternalContentHandlers(
|
||||||
|
|
||||||
assets[i] = asset
|
assets[i] = asset
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
toasts.addToast({
|
||||||
|
title: msg('assets.files.upload-failed'),
|
||||||
|
})
|
||||||
console.error(error)
|
console.error(error)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -352,9 +361,16 @@ export function registerDefaultExternalContentHandlers(
|
||||||
let shouldAlsoCreateAsset = false
|
let shouldAlsoCreateAsset = false
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
shouldAlsoCreateAsset = true
|
shouldAlsoCreateAsset = true
|
||||||
const bookmarkAsset = await editor.getAssetForExternalContent({ type: 'url', url })
|
try {
|
||||||
if (!bookmarkAsset) throw Error('Could not create an asset')
|
const bookmarkAsset = await editor.getAssetForExternalContent({ type: 'url', url })
|
||||||
asset = bookmarkAsset
|
if (!bookmarkAsset) throw Error('Could not create an asset')
|
||||||
|
asset = bookmarkAsset
|
||||||
|
} catch (e) {
|
||||||
|
toasts.addToast({
|
||||||
|
title: msg('assets.url.failed'),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.batch(() => {
|
editor.batch(() => {
|
||||||
|
|
|
@ -111,6 +111,8 @@ export type TLUiTranslationKey =
|
||||||
| 'action.zoom-to-100'
|
| 'action.zoom-to-100'
|
||||||
| 'action.zoom-to-fit'
|
| 'action.zoom-to-fit'
|
||||||
| 'action.zoom-to-selection'
|
| 'action.zoom-to-selection'
|
||||||
|
| 'assets.files.upload-failed'
|
||||||
|
| 'assets.url.failed'
|
||||||
| 'color-style.black'
|
| 'color-style.black'
|
||||||
| 'color-style.blue'
|
| 'color-style.blue'
|
||||||
| 'color-style.green'
|
| 'color-style.green'
|
||||||
|
|
|
@ -111,6 +111,8 @@ export const DEFAULT_TRANSLATION = {
|
||||||
'action.zoom-to-100': 'Zoom to 100%',
|
'action.zoom-to-100': 'Zoom to 100%',
|
||||||
'action.zoom-to-fit': 'Zoom to fit',
|
'action.zoom-to-fit': 'Zoom to fit',
|
||||||
'action.zoom-to-selection': 'Zoom to selection',
|
'action.zoom-to-selection': 'Zoom to selection',
|
||||||
|
'assets.files.upload-failed': 'Upload failed',
|
||||||
|
'assets.url.failed': "Couldn't load URL preview",
|
||||||
'color-style.black': 'Black',
|
'color-style.black': 'Black',
|
||||||
'color-style.blue': 'Blue',
|
'color-style.blue': 'Blue',
|
||||||
'color-style.green': 'Green',
|
'color-style.green': 'Green',
|
||||||
|
|
Loading…
Reference in a new issue