@strapi/upload 5.52.0 → 5.52.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/future/components/TruncatedText.js +76 -0
- package/dist/admin/future/components/TruncatedText.js.map +1 -0
- package/dist/admin/future/components/TruncatedText.mjs +74 -0
- package/dist/admin/future/components/TruncatedText.mjs.map +1 -0
- package/dist/admin/future/components/UploadProgressDialog.js +36 -1
- package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
- package/dist/admin/future/components/UploadProgressDialog.mjs +37 -2
- package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
- package/dist/admin/future/hooks/useApiErrorMessage.js +61 -0
- package/dist/admin/future/hooks/useApiErrorMessage.js.map +1 -0
- package/dist/admin/future/hooks/useApiErrorMessage.mjs +39 -0
- package/dist/admin/future/hooks/useApiErrorMessage.mjs.map +1 -0
- package/dist/admin/future/hooks/useTracking.js +57 -0
- package/dist/admin/future/hooks/useTracking.js.map +1 -0
- package/dist/admin/future/hooks/useTracking.mjs +53 -0
- package/dist/admin/future/hooks/useTracking.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js +31 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +31 -0
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +13 -11
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +13 -11
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +62 -51
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +62 -51
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +3 -4
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +4 -5
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +11 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +11 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +6 -4
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +6 -4
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +10 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +10 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js +3 -2
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs +3 -2
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +4 -2
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +4 -2
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.js +18 -2
- package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +18 -2
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js +9 -7
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs +9 -7
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js +12 -0
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs +12 -0
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +21 -38
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +23 -40
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.js +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +5 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +6 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useIsAssetDetailsOpen.js +30 -0
- package/dist/admin/future/pages/Assets/hooks/useIsAssetDetailsOpen.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useIsAssetDetailsOpen.mjs +26 -0
- package/dist/admin/future/pages/Assets/hooks/useIsAssetDetailsOpen.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/selection.js +17 -0
- package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs +17 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -1
- package/dist/admin/future/services/api.js +123 -19
- package/dist/admin/future/services/api.js.map +1 -1
- package/dist/admin/future/services/api.mjs +125 -21
- package/dist/admin/future/services/api.mjs.map +1 -1
- package/dist/admin/future/services/assets.js +11 -23
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +11 -23
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/future/services/uploadFileViaXHR.js +9 -3
- package/dist/admin/future/services/uploadFileViaXHR.js.map +1 -1
- package/dist/admin/future/services/uploadFileViaXHR.mjs +9 -3
- package/dist/admin/future/services/uploadFileViaXHR.mjs.map +1 -1
- package/dist/admin/future/store/uploadProgress.js +44 -5
- package/dist/admin/future/store/uploadProgress.js.map +1 -1
- package/dist/admin/future/store/uploadProgress.mjs +43 -6
- package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
- package/dist/admin/future/utils/getApiErrorMessage.js +20 -0
- package/dist/admin/future/utils/getApiErrorMessage.js.map +1 -0
- package/dist/admin/future/utils/getApiErrorMessage.mjs +18 -0
- package/dist/admin/future/utils/getApiErrorMessage.mjs.map +1 -0
- package/dist/admin/hooks/useAIMetadataJob.js +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.js +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
- package/dist/admin/src/future/components/TruncatedText.d.ts +32 -0
- package/dist/admin/src/future/hooks/useApiErrorMessage.d.ts +17 -0
- package/dist/admin/src/future/hooks/useTracking.d.ts +29 -0
- package/dist/admin/src/future/pages/Assets/components/AssetActionsMenu.d.ts +5 -3
- package/dist/admin/src/future/pages/Assets/components/FolderActionsMenu.d.ts +5 -4
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +2 -0
- package/dist/admin/src/future/pages/Assets/hooks/useIsAssetDetailsOpen.d.ts +18 -0
- package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +10 -0
- package/dist/admin/src/future/services/api.d.ts +6 -7
- package/dist/admin/src/future/services/uploadFileViaXHR.d.ts +6 -1
- package/dist/admin/src/future/store/uploadProgress.d.ts +16 -1
- package/dist/admin/src/future/utils/getApiErrorMessage.d.ts +1 -0
- package/dist/admin/translations/ca.json.js +1 -1
- package/dist/admin/translations/ca.json.mjs +1 -1
- package/dist/admin/translations/de.json.js +1 -1
- package/dist/admin/translations/de.json.mjs +1 -1
- package/dist/admin/translations/en.json.js +2 -1
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +2 -1
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/es.json.js +1 -1
- package/dist/admin/translations/es.json.mjs +1 -1
- package/dist/admin/translations/fr.json.js +1 -1
- package/dist/admin/translations/fr.json.mjs +1 -1
- package/dist/admin/translations/ja.json.js +1 -1
- package/dist/admin/translations/ja.json.mjs +1 -1
- package/dist/admin/translations/ko.json.js +1 -1
- package/dist/admin/translations/ko.json.mjs +1 -1
- package/dist/admin/translations/nl.json.js +1 -1
- package/dist/admin/translations/nl.json.mjs +1 -1
- package/dist/admin/translations/pl.json.js +1 -1
- package/dist/admin/translations/pl.json.mjs +1 -1
- package/dist/admin/translations/pt-BR.json.js +1 -1
- package/dist/admin/translations/pt-BR.json.mjs +1 -1
- package/dist/admin/translations/ru.json.js +1 -1
- package/dist/admin/translations/ru.json.mjs +1 -1
- package/dist/admin/translations/sk.json.js +1 -1
- package/dist/admin/translations/sk.json.mjs +1 -1
- package/dist/admin/translations/tr.json.js +1 -1
- package/dist/admin/translations/tr.json.mjs +1 -1
- package/dist/admin/translations/uk.json.js +1 -1
- package/dist/admin/translations/uk.json.mjs +1 -1
- package/dist/admin/translations/zh-Hans.json.js +1 -1
- package/dist/admin/translations/zh-Hans.json.mjs +1 -1
- package/dist/admin/translations/zh.json.js +1 -1
- package/dist/admin/translations/zh.json.mjs +1 -1
- package/dist/server/controllers/admin-file.js +27 -9
- package/dist/server/controllers/admin-file.js.map +1 -1
- package/dist/server/controllers/admin-file.mjs +27 -9
- package/dist/server/controllers/admin-file.mjs.map +1 -1
- package/dist/server/controllers/admin-upload.js +24 -8
- package/dist/server/controllers/admin-upload.js.map +1 -1
- package/dist/server/controllers/admin-upload.mjs +24 -8
- package/dist/server/controllers/admin-upload.mjs.map +1 -1
- package/dist/server/routes/admin.js +41 -21
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/admin.mjs +41 -21
- package/dist/server/routes/admin.mjs.map +1 -1
- package/dist/server/services/ai-metadata.js +25 -5
- package/dist/server/services/ai-metadata.js.map +1 -1
- package/dist/server/services/ai-metadata.mjs +1 -1
- package/dist/server/services/ai-metadata.mjs.map +1 -1
- package/dist/server/services/upload.js +4 -0
- package/dist/server/services/upload.js.map +1 -1
- package/dist/server/services/upload.mjs +4 -0
- package/dist/server/services/upload.mjs.map +1 -1
- package/dist/server/src/controllers/admin-file.d.ts +29 -8
- package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-upload.d.ts +20 -4
- package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +4 -4
- package/dist/server/src/index.d.ts +4 -4
- package/dist/server/src/routes/admin.d.ts.map +1 -1
- package/dist/server/src/services/ai-metadata.d.ts +2 -2
- package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
- package/dist/server/src/services/upload.d.ts.map +1 -1
- package/dist/shared/contracts/ai-metadata-jobs.d.ts +10 -32
- package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -1
- package/dist/shared/contracts/files.d.ts +10 -10
- package/dist/shared/contracts/files.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/admin/future/utils/getBulkMoveErrorMessage.js +0 -23
- package/dist/admin/future/utils/getBulkMoveErrorMessage.js.map +0 -1
- package/dist/admin/future/utils/getBulkMoveErrorMessage.mjs +0 -21
- package/dist/admin/future/utils/getBulkMoveErrorMessage.mjs.map +0 -1
- package/dist/admin/src/future/utils/getBulkMoveErrorMessage.d.ts +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UploadProgressDialog.mjs","sources":["../../../../admin/src/future/components/UploadProgressDialog.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Flex, IconButton, TextButton, Typography } from '@strapi/design-system';\nimport {\n ArrowsCounterClockwise,\n Check,\n CheckCircle,\n ChevronDown,\n Cross,\n CrossCircle,\n Information,\n MinusCircle,\n Sparkle,\n Upload,\n WarningCircle,\n} from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { keyframes, styled } from 'styled-components';\n\nimport { abortUpload, useRetryCancelledFilesMutation } from '../services/api';\nimport { useTypedDispatch, useTypedSelector } from '../store/hooks';\nimport {\n closeUploadProgress,\n toggleMinimize,\n cancelUpload,\n selectAggregateProgress,\n selectMetadataProgress,\n selectIsGeneratingMetadata,\n selectMetadataOutcome,\n} from '../store/uploadProgress';\nimport { getTranslationKey } from '../utils/translations';\n\nimport { Drawer } from './Drawer';\n\nimport type { FileMetadataStatus, FileProgress, FileProgressStatus } from '../store/uploadProgress';\nimport type { MessageDescriptor } from 'react-intl';\n\n/* -------------------------------------------------------------------------------------------------\n * DialogHeader\n * -----------------------------------------------------------------------------------------------*/\n\nconst HeaderStatusMessage = ({\n title,\n subtitle,\n metadataSubtitle,\n}: {\n title: string;\n subtitle?: string;\n metadataSubtitle?: string;\n}) => {\n return (\n <Flex direction=\"column\" alignItems=\"flex-start\" paddingLeft={2}>\n <Drawer.Title>\n <Typography variant=\"omega\">{title}</Typography>\n </Drawer.Title>\n <Drawer.Description>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {subtitle}\n </Typography>\n </Drawer.Description>\n {metadataSubtitle && (\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {metadataSubtitle}\n </Typography>\n )}\n </Flex>\n );\n};\n\nconst HeaderStatusIcon = styled(Flex)`\n padding: ${({ theme }) => theme.spaces[3]};\n border-radius: ${({ theme }) => `${theme.borderRadius} 0 0 ${theme.borderRadius}`};\n\n > svg {\n height: 24px;\n width: 24px;\n }\n`;\n\nconst HeaderStatusWrapper = styled(Flex)`\n align-items: center;\n`;\n\ntype HeaderStatusProps = {\n status: 'uploading' | 'success' | 'error' | 'canceled';\n progress?: number;\n totalFiles: number;\n successfulCount: number;\n errorCount: number;\n /**\n * Count-based metadata progress, or `null` when no row entered the metadata phase.\n * Shown as an extra subtitle while generation is still in flight.\n */\n metadataProgress: number | null;\n /** Whether any row is still generating — drives whether the subtitle shows at all. */\n isGeneratingMetadata: boolean;\n /**\n * Terminal per-outcome counts, or `null` while the phase is unfinished or was never\n * entered. Replaces the in-flight subtitle once generation settles.\n */\n metadataOutcome: { generated: number; skipped: number; failed: number } | null;\n};\n\nconst HeaderStatus = ({\n status,\n progress,\n totalFiles,\n successfulCount,\n errorCount,\n metadataProgress,\n isGeneratingMetadata,\n metadataOutcome,\n}: HeaderStatusProps) => {\n const { formatMessage } = useIntl();\n\n // Completion is upload-driven, so the terminal header can appear while metadata is\n // still generating — the subtitle keeps ticking underneath until it settles.\n //\n // Gated on work actually being in flight rather than on `progress < 100`: in a\n // sequential batch the percentage touches 100% between files, which would blink the\n // subtitle out and back in on every upload.\n //\n // Once the phase settles the line is not dropped but replaced with the outcome, so the\n // header keeps confirming what happened instead of silently losing the message.\n const metadataSubtitle = (() => {\n if (metadataProgress !== null && isGeneratingMetadata) {\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.generatingMetadata.withCount'),\n defaultMessage: 'Generating metadata with AI ({percentage}%)',\n },\n { percentage: metadataProgress }\n );\n }\n\n if (metadataOutcome === null) {\n return undefined;\n }\n\n // Only `generated` rows had metadata written, so only they can be reported as a\n // success. With none, there is nothing to confirm — an all-skipped batch of\n // non-images would otherwise read as \"generated on 0 files\". Per-row sublines\n // already spell out skipped and failed outcomes.\n if (metadataOutcome.generated === 0) {\n return undefined;\n }\n\n if (metadataOutcome.failed > 0) {\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.metadataGenerated.withFailures'),\n defaultMessage: '{generatedCount} generated, {failedCount} failed',\n },\n { generatedCount: metadataOutcome.generated, failedCount: metadataOutcome.failed }\n );\n }\n\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.metadataGenerated.withCount'),\n defaultMessage:\n '{count, plural, one {Metadata successfully generated on # file} other {Metadata successfully generated on # files}}',\n },\n { count: metadataOutcome.generated }\n );\n })();\n\n if (status === 'error') {\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"danger200\">\n <Cross fill=\"danger700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.failed'),\n defaultMessage: 'Upload failed',\n })}\n subtitle={formatMessage({\n id: getTranslationKey('upload.progress.failed.subtitle'),\n defaultMessage: 'Please try to upload files again',\n })}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'success') {\n const subtitle =\n errorCount > 0\n ? formatMessage(\n {\n id: getTranslationKey('upload.progress.success.subtitle.withErrors'),\n defaultMessage: '{successCount} uploaded, {errorCount} failed',\n },\n { successCount: successfulCount, errorCount }\n )\n : formatMessage(\n {\n id: getTranslationKey('upload.progress.success.subtitle'),\n defaultMessage: '{count} files uploaded successfully',\n },\n { count: successfulCount }\n );\n\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"success200\">\n <Check fill=\"success700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.success'),\n defaultMessage: 'Upload successful!',\n })}\n subtitle={subtitle}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'canceled') {\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"neutral200\">\n <MinusCircle fill=\"neutral700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.canceled'),\n defaultMessage: 'Upload canceled',\n })}\n subtitle={formatMessage({\n id: getTranslationKey('upload.progress.canceled.subtitle'),\n defaultMessage: 'Some files were not uploaded',\n })}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'uploading') {\n const progressPercentage = progress ? Math.round(progress) : 0;\n\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"primary200\">\n <Upload fill=\"primary700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage(\n {\n id: getTranslationKey('upload.progress.uploading.withCount'),\n defaultMessage: 'Uploading {total} items ({percentage}%)',\n },\n {\n total: totalFiles,\n percentage: progressPercentage,\n }\n )}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n return null;\n};\n\nconst HeaderIconButton = styled(IconButton)`\n &:hover {\n background: transparent;\n }\n`;\n\nconst ChevronWrapper = styled.span<{ $isMinimized: boolean }>`\n display: flex;\n transition: transform 0.5s ease-in-out;\n transform: ${({ $isMinimized }) => ($isMinimized ? 'rotate(180deg)' : 'rotate(0deg)')};\n`;\n\nconst HEADER_COLOR_MAP = {\n uploading: { background: 'primary100' },\n canceled: { background: 'neutral100' },\n success: { background: 'success100' },\n error: { background: 'danger100' },\n} as const;\n\nconst DialogHeader = ({ handleClose }: { handleClose: () => void }) => {\n const { formatMessage } = useIntl();\n\n const { isMinimized, files, uploadId, totalFiles } = useTypedSelector(\n (state) => state.uploadProgress\n );\n const progress = useTypedSelector(selectAggregateProgress);\n const metadataProgress = useTypedSelector(selectMetadataProgress);\n const isGeneratingMetadata = useTypedSelector(selectIsGeneratingMetadata);\n const metadataOutcome = useTypedSelector(selectMetadataOutcome);\n const dispatch = useTypedDispatch();\n const [retryCancelledFiles] = useRetryCancelledFilesMutation();\n\n // The batch is complete once every file has reached a terminal state. Byte-weighted\n // progress can't be used here because errored/cancelled rows never reach 100%.\n const isComplete =\n files.length > 0 &&\n files.every((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled');\n const isAllUploaded = isComplete;\n const isAllErrored = isComplete && files.every((f) => f.status === 'error');\n const hasCancelledFiles = files.some((f) => f.status === 'cancelled');\n const successfulCount = files.filter((f) => f.status === 'complete').length;\n const errorCount = files.filter((f) => f.status === 'error').length;\n // Success includes partial success (some files succeeded, even if some failed)\n const isSuccess = isComplete && successfulCount > 0 && !hasCancelledFiles;\n const status = ((): HeaderStatusProps['status'] => {\n if (isAllErrored) return 'error';\n if (isSuccess) return 'success';\n if (hasCancelledFiles) return 'canceled';\n\n return 'uploading';\n })();\n\n const handleCancel = () => {\n abortUpload(uploadId);\n dispatch(cancelUpload());\n };\n\n const handleRetry = async () => {\n try {\n await retryCancelledFiles().unwrap();\n } catch {\n // Error is already dispatched to store from the API queryFn\n }\n };\n\n const handleToggleMinimize = () => {\n dispatch(toggleMinimize());\n };\n\n return (\n <Flex\n background={HEADER_COLOR_MAP[status].background}\n justifyContent=\"space-between\"\n margin={1}\n hasRadius\n >\n <HeaderStatus\n status={status}\n progress={progress}\n totalFiles={totalFiles}\n successfulCount={successfulCount}\n errorCount={errorCount}\n metadataProgress={metadataProgress}\n isGeneratingMetadata={isGeneratingMetadata}\n metadataOutcome={metadataOutcome}\n />\n <Flex gap={1}>\n {!isAllUploaded && (\n <TextButton onClick={handleCancel} fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('upload.progress.cancel'),\n defaultMessage: 'Cancel all',\n })}\n </TextButton>\n )}\n {hasCancelledFiles && (\n <TextButton onClick={handleRetry} fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('upload.progress.retry'),\n defaultMessage: 'Retry',\n })}\n </TextButton>\n )}\n <HeaderIconButton\n onClick={handleToggleMinimize}\n label={formatMessage({\n id: getTranslationKey(\n isMinimized ? 'upload.progress.maximize' : 'upload.progress.minimize'\n ),\n defaultMessage: isMinimized ? 'Maximize' : 'Minimize',\n })}\n variant=\"ghost\"\n >\n <ChevronWrapper $isMinimized={isMinimized}>\n <ChevronDown />\n </ChevronWrapper>\n </HeaderIconButton>\n {isComplete && (\n <Drawer.CloseButton\n onClose={handleClose}\n label={formatMessage({\n id: getTranslationKey('upload.progress.close'),\n defaultMessage: 'Close',\n })}\n />\n )}\n </Flex>\n </Flex>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * UploadProgressDialog\n * -----------------------------------------------------------------------------------------------*/\n\nconst ProgressTrack = styled.div`\n width: 100%;\n height: ${({ theme }) => theme.spaces[1]};\n background-color: ${({ theme }) => theme.colors.neutral200};\n border-radius: 4px;\n overflow: hidden;\n`;\n\nconst ProgressIndicator = styled.div<{ $percent: number }>`\n height: 100%;\n width: ${({ $percent }) => $percent}%;\n background-color: ${({ theme }) => theme.colors.primary700};\n border-radius: 4px;\n transition: width 0.15s linear;\n`;\n\nconst DeterminateBar = ({ percent }: { percent: number }) => {\n const clamped = Math.min(100, Math.max(0, Math.round(percent)));\n return (\n <ProgressTrack role=\"progressbar\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={clamped}>\n <ProgressIndicator $percent={clamped} />\n </ProgressTrack>\n );\n};\n\nconst INDETERMINATE_INDICATOR_WIDTH = 40;\n\n/**\n * `translateX` percentages resolve against the *indicator's* own width, not the track's.\n * So -100% is exactly \"fully off the left edge\" regardless of the width above, and the\n * end offset converts a full track width into those same own-width units. Both ends sit\n * flush off-track, which keeps entry and exit symmetric — a smaller start offset would\n * make the bar pop in already partly visible.\n */\nconst indeterminateSlide = keyframes`\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(${(100 / INDETERMINATE_INDICATOR_WIDTH) * 100}%);\n }\n`;\n\nconst IndeterminateIndicator = styled.div`\n height: 100%;\n width: ${INDETERMINATE_INDICATOR_WIDTH}%;\n background-color: ${({ theme }) => theme.colors.primary700};\n border-radius: 4px;\n /* Linear, not an eased curve: the DS easings decelerate to a stop, which on a loop\n reads as a stall at the wrap point. Constant speed is what makes it read as a sweep. */\n animation: ${indeterminateSlide} 1.2s linear infinite;\n\n /* A perpetually moving bar is a vestibular trigger; fall back to a static track fill. */\n @media (prefers-reduced-motion: reduce) {\n animation: none;\n width: 100%;\n opacity: 0.5;\n }\n`;\n\n/**\n * Progress bar for work whose completion fraction is genuinely unknowable, rather\n * than merely unknown-yet: the AI metadata endpoint answers in one go, and the URL\n * flow can't report bytes until the server has fetched the file and knows its size.\n *\n * Deliberately omits `aria-valuenow` — that absence is precisely how ARIA conveys\n * an indeterminate progressbar, so assistive tech announces \"busy\" instead of \"0%\".\n */\nconst IndeterminateBar = () => {\n return (\n <ProgressTrack role=\"progressbar\" aria-valuemin={0} aria-valuemax={100}>\n <IndeterminateIndicator />\n </ProgressTrack>\n );\n};\n\nconst FileRow = ({\n icon,\n fileName,\n children,\n}: {\n icon: React.ReactNode;\n fileName: string;\n children: React.ReactNode;\n}) => {\n return (\n <Flex direction=\"column\" alignItems=\"stretch\" justifyContent=\"center\" gap={1} width=\"100%\">\n <Flex gap={2}>\n {icon}\n <Typography variant=\"omega\" fontWeight=\"semiBold\" ellipsis>\n {fileName}\n </Typography>\n </Flex>\n {children}\n </Flex>\n );\n};\n\n/**\n * Icon + subline for a successfully uploaded row, keyed by its metadata phase.\n * `'none'` covers rows that never entered the phase — AI metadata disabled — and\n * renders exactly as before this feature existed. Non-images do enter the phase and\n * land on `skipped`.\n *\n * `skipped` uses a neutral `Information` icon, deliberately distinct from\n * generated/failed/cancelled — skipping is an expected outcome for a non-image, not a\n * problem to flag.\n */\nconst COMPLETED_ROW_PRESENTATION: Record<\n FileMetadataStatus | 'none',\n { icon: React.ReactNode; message: MessageDescriptor }\n> = {\n none: {\n icon: <CheckCircle fill=\"success500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.uploaded'),\n defaultMessage: 'Uploaded',\n },\n },\n generating: {\n icon: <Sparkle fill=\"primary600\" />,\n message: {\n id: getTranslationKey('upload.progress.file.generatingMetadata'),\n defaultMessage: 'Uploaded • Generating metadata…',\n },\n },\n generated: {\n icon: <CheckCircle fill=\"success500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataGenerated'),\n defaultMessage: 'Uploaded • Metadata generated',\n },\n },\n skipped: {\n icon: <Information fill=\"neutral500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataSkipped'),\n defaultMessage: 'Upload complete • Metadata generation skipped',\n },\n },\n failed: {\n icon: <WarningCircle fill=\"warning500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataFailed'),\n defaultMessage: 'Upload complete • Metadata generation failed',\n },\n },\n};\n\nconst FileRowRenderer = ({ file }: { file: FileProgress }) => {\n const { formatMessage } = useIntl();\n const isError = file.status === 'error';\n const isCurrentFile = file.status === 'uploading';\n const isCompleted = file.status === 'complete';\n const isCancelled = file.status === 'cancelled';\n\n if (isCurrentFile) {\n // Determinate only once bytes are actually being reported — a known `size` is not\n // enough. The two upload flows differ here:\n // - the direct-file flow streams real byte counts from XHR, so `uploadedBytes`\n // climbs and a determinate bar is meaningful;\n // - the URL flow learns the size from the `file:uploading` SSE event but receives\n // no incremental counts at all (the next event is `file:complete`), so\n // `uploadedBytes` stays 0 for the whole transfer.\n // Keying off `size` alone froze URL rows at a determinate 0% for the entire upload;\n // keying off reported bytes keeps them animating until there is a fraction to show.\n const hasReportedProgress = file.size > 0 && file.uploadedBytes > 0;\n\n return (\n <FileRow icon={<ArrowsCounterClockwise fill=\"secondary600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.uploading'),\n defaultMessage: 'Uploading...',\n })}\n </Typography>\n {hasReportedProgress ? (\n <DeterminateBar percent={(file.uploadedBytes / file.size) * 100} />\n ) : (\n <IndeterminateBar />\n )}\n </FileRow>\n );\n }\n\n if (isError) {\n return (\n <FileRow icon={<CrossCircle fill=\"danger500\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {file.error}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCancelled) {\n return (\n <FileRow icon={<MinusCircle fill=\"neutral600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.canceled'),\n defaultMessage: 'Canceled',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCompleted) {\n // The upload succeeded; the metadata phase (if any) drives both the icon and the\n // subline from here on — a metadata failure shows a warning, not an upload error.\n const { icon, message } = COMPLETED_ROW_PRESENTATION[file.metadataStatus ?? 'none'];\n\n return (\n <FileRow icon={icon} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage(message)}\n </Typography>\n {/* Generation has no intermediate progress to report, so the bar stays indeterminate. */}\n {file.metadataStatus === 'generating' && <IndeterminateBar />}\n </FileRow>\n );\n }\n\n return null;\n};\n\nconst CompletedFilesList = styled(Flex)`\n flex-direction: column;\n gap: ${({ theme }) => theme.spaces[2]};\n width: 100%;\n`;\n\nexport const UploadProgressDialog = () => {\n const dispatch = useTypedDispatch();\n const { isVisible, isMinimized, files } = useTypedSelector((state) => state.uploadProgress);\n\n // With concurrent uploads several files are `uploading` at once — render every\n // in-flight row, not just the first (a `find` here dated to the strictly\n // sequential era and hid all but the lowest-index worker's row).\n const uploadingFiles = files.filter((f) => f.status === 'uploading');\n const completedFiles = files\n .filter((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled')\n .sort((a, b) => {\n // Sort priority: error > cancelled > complete\n const priority: Record<FileProgressStatus, number> = {\n error: 0,\n cancelled: 1,\n complete: 2,\n uploading: 3,\n pending: 4,\n };\n return priority[a.status] - priority[b.status];\n });\n\n const handleClose = () => {\n dispatch(closeUploadProgress());\n };\n\n return (\n <Drawer.Root isVisible={isVisible} onClose={handleClose}>\n <Drawer.Body animationDirection=\"up\" width=\"41.6rem\" maxHeight=\"34.2rem\">\n <DialogHeader handleClose={handleClose} />\n <Drawer.ScrollableContent isContentExpanded={!isMinimized}>\n <Flex\n direction=\"column\"\n alignItems=\"stretch\"\n gap={4}\n paddingTop={4}\n paddingBottom={4}\n paddingLeft={4}\n paddingRight={4}\n >\n {uploadingFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n\n {completedFiles.length > 0 && (\n <CompletedFilesList>\n {completedFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n </CompletedFilesList>\n )}\n </Flex>\n </Drawer.ScrollableContent>\n </Drawer.Body>\n </Drawer.Root>\n );\n};\n"],"names":["HeaderStatusMessage","title","subtitle","metadataSubtitle","_jsxs","Flex","direction","alignItems","paddingLeft","_jsx","Drawer","Title","Typography","variant","Description","textColor","HeaderStatusIcon","styled","theme","spaces","borderRadius","HeaderStatusWrapper","HeaderStatus","status","progress","totalFiles","successfulCount","errorCount","metadataProgress","isGeneratingMetadata","metadataOutcome","formatMessage","useIntl","id","getTranslationKey","defaultMessage","percentage","undefined","generated","failed","generatedCount","failedCount","count","background","Cross","fill","successCount","Check","MinusCircle","progressPercentage","Math","round","Upload","total","HeaderIconButton","IconButton","ChevronWrapper","span","$isMinimized","HEADER_COLOR_MAP","uploading","canceled","success","error","DialogHeader","handleClose","isMinimized","files","uploadId","useTypedSelector","state","uploadProgress","selectAggregateProgress","selectMetadataProgress","selectIsGeneratingMetadata","selectMetadataOutcome","dispatch","useTypedDispatch","retryCancelledFiles","useRetryCancelledFilesMutation","isComplete","length","every","f","isAllUploaded","isAllErrored","hasCancelledFiles","some","filter","isSuccess","handleCancel","abortUpload","cancelUpload","handleRetry","unwrap","handleToggleMinimize","toggleMinimize","justifyContent","margin","hasRadius","gap","TextButton","onClick","fontWeight","label","ChevronDown","CloseButton","onClose","ProgressTrack","div","colors","neutral200","ProgressIndicator","$percent","primary700","DeterminateBar","percent","clamped","min","max","role","aria-valuemin","aria-valuemax","aria-valuenow","INDETERMINATE_INDICATOR_WIDTH","indeterminateSlide","keyframes","IndeterminateIndicator","IndeterminateBar","FileRow","icon","fileName","children","width","ellipsis","COMPLETED_ROW_PRESENTATION","none","CheckCircle","message","generating","Sparkle","skipped","Information","WarningCircle","FileRowRenderer","file","isError","isCurrentFile","isCompleted","isCancelled","hasReportedProgress","size","uploadedBytes","ArrowsCounterClockwise","name","CrossCircle","metadataStatus","CompletedFilesList","UploadProgressDialog","isVisible","uploadingFiles","completedFiles","sort","a","b","priority","cancelled","complete","pending","closeUploadProgress","Root","Body","animationDirection","maxHeight","ScrollableContent","isContentExpanded","paddingTop","paddingBottom","paddingRight","map","index"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UploadProgressDialog.mjs","sources":["../../../../admin/src/future/components/UploadProgressDialog.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Flex, IconButton, TextButton, Typography } from '@strapi/design-system';\nimport {\n ArrowsCounterClockwise,\n Check,\n CheckCircle,\n ChevronDown,\n Clock,\n Cross,\n CrossCircle,\n Information,\n MinusCircle,\n Sparkle,\n Upload,\n WarningCircle,\n} from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { keyframes, styled } from 'styled-components';\n\nimport { abortUpload, useRetryCancelledFilesMutation } from '../services/api';\nimport { useTypedDispatch, useTypedSelector } from '../store/hooks';\nimport {\n closeUploadProgress,\n toggleMinimize,\n cancelUpload,\n selectAggregateProgress,\n selectMetadataProgress,\n selectIsGeneratingMetadata,\n selectMetadataOutcome,\n} from '../store/uploadProgress';\nimport { getTranslationKey } from '../utils/translations';\n\nimport { Drawer } from './Drawer';\n\nimport type { FileMetadataStatus, FileProgress, FileProgressStatus } from '../store/uploadProgress';\nimport type { MessageDescriptor } from 'react-intl';\n\n/* -------------------------------------------------------------------------------------------------\n * DialogHeader\n * -----------------------------------------------------------------------------------------------*/\n\nconst HeaderStatusMessage = ({\n title,\n subtitle,\n metadataSubtitle,\n}: {\n title: string;\n subtitle?: string;\n metadataSubtitle?: string;\n}) => {\n return (\n <Flex direction=\"column\" alignItems=\"flex-start\" paddingLeft={2}>\n <Drawer.Title>\n <Typography variant=\"omega\">{title}</Typography>\n </Drawer.Title>\n <Drawer.Description>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {subtitle}\n </Typography>\n </Drawer.Description>\n {metadataSubtitle && (\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {metadataSubtitle}\n </Typography>\n )}\n </Flex>\n );\n};\n\nconst HeaderStatusIcon = styled(Flex)`\n padding: ${({ theme }) => theme.spaces[3]};\n border-radius: ${({ theme }) => `${theme.borderRadius} 0 0 ${theme.borderRadius}`};\n\n > svg {\n height: 24px;\n width: 24px;\n }\n`;\n\nconst HeaderStatusWrapper = styled(Flex)`\n align-items: center;\n`;\n\ntype HeaderStatusProps = {\n status: 'uploading' | 'success' | 'error' | 'canceled';\n progress?: number;\n totalFiles: number;\n successfulCount: number;\n errorCount: number;\n /**\n * Count-based metadata progress, or `null` when no row entered the metadata phase.\n * Shown as an extra subtitle while generation is still in flight.\n */\n metadataProgress: number | null;\n /** Whether any row is still generating — drives whether the subtitle shows at all. */\n isGeneratingMetadata: boolean;\n /**\n * Terminal per-outcome counts, or `null` while the phase is unfinished or was never\n * entered. Replaces the in-flight subtitle once generation settles.\n */\n metadataOutcome: { generated: number; skipped: number; failed: number } | null;\n};\n\nconst HeaderStatus = ({\n status,\n progress,\n totalFiles,\n successfulCount,\n errorCount,\n metadataProgress,\n isGeneratingMetadata,\n metadataOutcome,\n}: HeaderStatusProps) => {\n const { formatMessage } = useIntl();\n\n // Completion is upload-driven, so the terminal header can appear while metadata is\n // still generating — the subtitle keeps ticking underneath until it settles.\n //\n // Gated on work actually being in flight rather than on `progress < 100`: in a\n // sequential batch the percentage touches 100% between files, which would blink the\n // subtitle out and back in on every upload.\n //\n // Once the phase settles the line is not dropped but replaced with the outcome, so the\n // header keeps confirming what happened instead of silently losing the message.\n const metadataSubtitle = (() => {\n if (metadataProgress !== null && isGeneratingMetadata) {\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.generatingMetadata.withCount'),\n defaultMessage: 'Generating metadata with AI ({percentage}%)',\n },\n { percentage: metadataProgress }\n );\n }\n\n if (metadataOutcome === null) {\n return undefined;\n }\n\n // Only `generated` rows had metadata written, so only they can be reported as a\n // success. With none, there is nothing to confirm — an all-skipped batch of\n // non-images would otherwise read as \"generated on 0 files\". Per-row sublines\n // already spell out skipped and failed outcomes.\n if (metadataOutcome.generated === 0) {\n return undefined;\n }\n\n if (metadataOutcome.failed > 0) {\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.metadataGenerated.withFailures'),\n defaultMessage: '{generatedCount} generated, {failedCount} failed',\n },\n { generatedCount: metadataOutcome.generated, failedCount: metadataOutcome.failed }\n );\n }\n\n return formatMessage(\n {\n id: getTranslationKey('upload.progress.metadataGenerated.withCount'),\n defaultMessage:\n '{count, plural, one {Metadata successfully generated on # file} other {Metadata successfully generated on # files}}',\n },\n { count: metadataOutcome.generated }\n );\n })();\n\n if (status === 'error') {\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"danger200\">\n <Cross fill=\"danger700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.failed'),\n defaultMessage: 'Upload failed',\n })}\n subtitle={formatMessage({\n id: getTranslationKey('upload.progress.failed.subtitle'),\n defaultMessage: 'Please try to upload files again',\n })}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'success') {\n const subtitle =\n errorCount > 0\n ? formatMessage(\n {\n id: getTranslationKey('upload.progress.success.subtitle.withErrors'),\n defaultMessage: '{successCount} uploaded, {errorCount} failed',\n },\n { successCount: successfulCount, errorCount }\n )\n : formatMessage(\n {\n id: getTranslationKey('upload.progress.success.subtitle'),\n defaultMessage: '{count} files uploaded successfully',\n },\n { count: successfulCount }\n );\n\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"success200\">\n <Check fill=\"success700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.success'),\n defaultMessage: 'Upload successful!',\n })}\n subtitle={subtitle}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'canceled') {\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"neutral200\">\n <MinusCircle fill=\"neutral700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage({\n id: getTranslationKey('upload.progress.canceled'),\n defaultMessage: 'Upload canceled',\n })}\n subtitle={formatMessage({\n id: getTranslationKey('upload.progress.canceled.subtitle'),\n defaultMessage: 'Some files were not uploaded',\n })}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n if (status === 'uploading') {\n const progressPercentage = progress ? Math.round(progress) : 0;\n\n return (\n <HeaderStatusWrapper>\n <HeaderStatusIcon background=\"primary200\">\n <Upload fill=\"primary700\" />\n </HeaderStatusIcon>\n <HeaderStatusMessage\n title={formatMessage(\n {\n id: getTranslationKey('upload.progress.uploading.withCount'),\n defaultMessage: 'Uploading {total} items ({percentage}%)',\n },\n {\n total: totalFiles,\n percentage: progressPercentage,\n }\n )}\n metadataSubtitle={metadataSubtitle}\n />\n </HeaderStatusWrapper>\n );\n }\n\n return null;\n};\n\nconst HeaderIconButton = styled(IconButton)`\n &:hover {\n background: transparent;\n }\n`;\n\nconst ChevronWrapper = styled.span<{ $isMinimized: boolean }>`\n display: flex;\n transition: transform 0.5s ease-in-out;\n transform: ${({ $isMinimized }) => ($isMinimized ? 'rotate(180deg)' : 'rotate(0deg)')};\n`;\n\nconst HEADER_COLOR_MAP = {\n uploading: { background: 'primary100' },\n canceled: { background: 'neutral100' },\n success: { background: 'success100' },\n error: { background: 'danger100' },\n} as const;\n\nconst DialogHeader = ({ handleClose }: { handleClose: () => void }) => {\n const { formatMessage } = useIntl();\n\n const { isMinimized, files, uploadId, totalFiles } = useTypedSelector(\n (state) => state.uploadProgress\n );\n const progress = useTypedSelector(selectAggregateProgress);\n const metadataProgress = useTypedSelector(selectMetadataProgress);\n const isGeneratingMetadata = useTypedSelector(selectIsGeneratingMetadata);\n const metadataOutcome = useTypedSelector(selectMetadataOutcome);\n const dispatch = useTypedDispatch();\n const [retryCancelledFiles] = useRetryCancelledFilesMutation();\n\n // The batch is complete once every file has reached a terminal state. Byte-weighted\n // progress can't be used here because errored/cancelled rows never reach 100%.\n const isComplete =\n files.length > 0 &&\n files.every((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled');\n const isAllUploaded = isComplete;\n const isAllErrored = isComplete && files.every((f) => f.status === 'error');\n const hasCancelledFiles = files.some((f) => f.status === 'cancelled');\n const successfulCount = files.filter((f) => f.status === 'complete').length;\n const errorCount = files.filter((f) => f.status === 'error').length;\n // Success includes partial success (some files succeeded, even if some failed)\n const isSuccess = isComplete && successfulCount > 0 && !hasCancelledFiles;\n const status = ((): HeaderStatusProps['status'] => {\n if (isAllErrored) return 'error';\n if (isSuccess) return 'success';\n if (hasCancelledFiles) return 'canceled';\n\n return 'uploading';\n })();\n\n const handleCancel = () => {\n abortUpload(uploadId);\n dispatch(cancelUpload());\n };\n\n const handleRetry = async () => {\n try {\n await retryCancelledFiles().unwrap();\n } catch {\n // Error is already dispatched to store from the API queryFn\n }\n };\n\n const handleToggleMinimize = () => {\n dispatch(toggleMinimize());\n };\n\n return (\n <Flex\n background={HEADER_COLOR_MAP[status].background}\n justifyContent=\"space-between\"\n margin={1}\n hasRadius\n >\n <HeaderStatus\n status={status}\n progress={progress}\n totalFiles={totalFiles}\n successfulCount={successfulCount}\n errorCount={errorCount}\n metadataProgress={metadataProgress}\n isGeneratingMetadata={isGeneratingMetadata}\n metadataOutcome={metadataOutcome}\n />\n <Flex gap={1}>\n {!isAllUploaded && (\n <TextButton onClick={handleCancel} fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('upload.progress.cancel'),\n defaultMessage: 'Cancel all',\n })}\n </TextButton>\n )}\n {hasCancelledFiles && (\n <TextButton onClick={handleRetry} fontWeight=\"bold\">\n {formatMessage({\n id: getTranslationKey('upload.progress.retry'),\n defaultMessage: 'Retry',\n })}\n </TextButton>\n )}\n <HeaderIconButton\n onClick={handleToggleMinimize}\n label={formatMessage({\n id: getTranslationKey(\n isMinimized ? 'upload.progress.maximize' : 'upload.progress.minimize'\n ),\n defaultMessage: isMinimized ? 'Maximize' : 'Minimize',\n })}\n variant=\"ghost\"\n >\n <ChevronWrapper $isMinimized={isMinimized}>\n <ChevronDown />\n </ChevronWrapper>\n </HeaderIconButton>\n {isComplete && (\n <Drawer.CloseButton\n onClose={handleClose}\n label={formatMessage({\n id: getTranslationKey('upload.progress.close'),\n defaultMessage: 'Close',\n })}\n />\n )}\n </Flex>\n </Flex>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * UploadProgressDialog\n * -----------------------------------------------------------------------------------------------*/\n\nconst ProgressTrack = styled.div`\n width: 100%;\n height: ${({ theme }) => theme.spaces[1]};\n background-color: ${({ theme }) => theme.colors.neutral200};\n border-radius: 4px;\n overflow: hidden;\n`;\n\nconst ProgressIndicator = styled.div<{ $percent: number }>`\n height: 100%;\n width: ${({ $percent }) => $percent}%;\n background-color: ${({ theme }) => theme.colors.primary700};\n border-radius: 4px;\n transition: width 0.15s linear;\n`;\n\nconst DeterminateBar = ({ percent }: { percent: number }) => {\n const clamped = Math.min(100, Math.max(0, Math.round(percent)));\n return (\n <ProgressTrack role=\"progressbar\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={clamped}>\n <ProgressIndicator $percent={clamped} />\n </ProgressTrack>\n );\n};\n\nconst INDETERMINATE_INDICATOR_WIDTH = 40;\n\n/**\n * `translateX` percentages resolve against the *indicator's* own width, not the track's.\n * So -100% is exactly \"fully off the left edge\" regardless of the width above, and the\n * end offset converts a full track width into those same own-width units. Both ends sit\n * flush off-track, which keeps entry and exit symmetric — a smaller start offset would\n * make the bar pop in already partly visible.\n */\nconst indeterminateSlide = keyframes`\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(${(100 / INDETERMINATE_INDICATOR_WIDTH) * 100}%);\n }\n`;\n\nconst IndeterminateIndicator = styled.div`\n height: 100%;\n width: ${INDETERMINATE_INDICATOR_WIDTH}%;\n background-color: ${({ theme }) => theme.colors.primary700};\n border-radius: 4px;\n /* Linear, not an eased curve: the DS easings decelerate to a stop, which on a loop\n reads as a stall at the wrap point. Constant speed is what makes it read as a sweep. */\n animation: ${indeterminateSlide} 1.2s linear infinite;\n\n /* A perpetually moving bar is a vestibular trigger; fall back to a static track fill. */\n @media (prefers-reduced-motion: reduce) {\n animation: none;\n width: 100%;\n opacity: 0.5;\n }\n`;\n\n/**\n * Progress bar for work whose completion fraction is genuinely unknowable, rather\n * than merely unknown-yet: the AI metadata endpoint answers in one go, and the URL\n * flow can't report bytes until the server has fetched the file and knows its size.\n *\n * Deliberately omits `aria-valuenow` — that absence is precisely how ARIA conveys\n * an indeterminate progressbar, so assistive tech announces \"busy\" instead of \"0%\".\n */\nconst IndeterminateBar = () => {\n return (\n <ProgressTrack role=\"progressbar\" aria-valuemin={0} aria-valuemax={100}>\n <IndeterminateIndicator />\n </ProgressTrack>\n );\n};\n\nconst FileRow = ({\n icon,\n fileName,\n children,\n}: {\n icon: React.ReactNode;\n fileName: string;\n children: React.ReactNode;\n}) => {\n return (\n <Flex direction=\"column\" alignItems=\"stretch\" justifyContent=\"center\" gap={1} width=\"100%\">\n <Flex gap={2}>\n {icon}\n <Typography variant=\"omega\" fontWeight=\"semiBold\" ellipsis>\n {fileName}\n </Typography>\n </Flex>\n {children}\n </Flex>\n );\n};\n\n/**\n * Icon + subline for a successfully uploaded row, keyed by its metadata phase.\n * `'none'` covers rows that never entered the phase — AI metadata disabled — and\n * renders exactly as before this feature existed. Non-images do enter the phase and\n * land on `skipped`.\n *\n * `skipped` uses a neutral `Information` icon, deliberately distinct from\n * generated/failed/cancelled — skipping is an expected outcome for a non-image, not a\n * problem to flag.\n */\nconst COMPLETED_ROW_PRESENTATION: Record<\n FileMetadataStatus | 'none',\n { icon: React.ReactNode; message: MessageDescriptor }\n> = {\n none: {\n icon: <CheckCircle fill=\"success500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.uploaded'),\n defaultMessage: 'Uploaded',\n },\n },\n generating: {\n icon: <Sparkle fill=\"primary600\" />,\n message: {\n id: getTranslationKey('upload.progress.file.generatingMetadata'),\n defaultMessage: 'Uploaded • Generating metadata…',\n },\n },\n generated: {\n icon: <CheckCircle fill=\"success500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataGenerated'),\n defaultMessage: 'Uploaded • Metadata generated',\n },\n },\n skipped: {\n icon: <Information fill=\"neutral500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataSkipped'),\n defaultMessage: 'Upload complete • Metadata generation skipped',\n },\n },\n failed: {\n icon: <WarningCircle fill=\"warning500\" />,\n message: {\n id: getTranslationKey('upload.progress.file.metadataFailed'),\n defaultMessage: 'Upload complete • Metadata generation failed',\n },\n },\n};\n\nconst FileRowRenderer = ({ file }: { file: FileProgress }) => {\n const { formatMessage } = useIntl();\n const isError = file.status === 'error';\n const isCurrentFile = file.status === 'uploading';\n const isCompleted = file.status === 'complete';\n const isCancelled = file.status === 'cancelled';\n const isQueued = file.status === 'pending';\n\n if (isQueued) {\n // No bar: there is nothing to report yet, and an indeterminate bar would read\n // as \"in progress\" on a file the pool has not picked up.\n return (\n <FileRow icon={<Clock fill=\"neutral600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.queued'),\n defaultMessage: 'Queued',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCurrentFile) {\n // Determinate only once bytes are actually being reported — a known `size` is not\n // enough. The two upload flows differ here:\n // - the direct-file flow streams real byte counts from XHR, so `uploadedBytes`\n // climbs and a determinate bar is meaningful;\n // - the URL flow learns the size from the `file:uploading` SSE event but receives\n // no incremental counts at all (the next event is `file:complete`), so\n // `uploadedBytes` stays 0 for the whole transfer.\n // Keying off `size` alone froze URL rows at a determinate 0% for the entire upload;\n // keying off reported bytes keeps them animating until there is a fraction to show.\n const hasReportedProgress = file.size > 0 && file.uploadedBytes > 0;\n\n return (\n <FileRow icon={<ArrowsCounterClockwise fill=\"secondary600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.uploading'),\n defaultMessage: 'Uploading...',\n })}\n </Typography>\n {hasReportedProgress ? (\n <DeterminateBar percent={(file.uploadedBytes / file.size) * 100} />\n ) : (\n <IndeterminateBar />\n )}\n </FileRow>\n );\n }\n\n if (isError) {\n return (\n <FileRow icon={<CrossCircle fill=\"danger500\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {file.error\n ? /**\n * The server may return a machine-readable code (e.g. `FileTooBig` from the\n * body middleware) or an already human-readable sentence (e.g. the upload\n * plugin's size-limit message). Translate the former, fall back to the latter.\n */\n formatMessage({\n id: getTranslationKey(`apiError.${file.error}`),\n defaultMessage: file.error,\n })\n : formatMessage({\n id: getTranslationKey('upload.generic-error'),\n defaultMessage: 'An error occurred while uploading the file.',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCancelled) {\n return (\n <FileRow icon={<MinusCircle fill=\"neutral600\" />} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('upload.progress.file.canceled'),\n defaultMessage: 'Canceled',\n })}\n </Typography>\n </FileRow>\n );\n }\n\n if (isCompleted) {\n // The upload succeeded; the metadata phase (if any) drives both the icon and the\n // subline from here on — a metadata failure shows a warning, not an upload error.\n const { icon, message } = COMPLETED_ROW_PRESENTATION[file.metadataStatus ?? 'none'];\n\n return (\n <FileRow icon={icon} fileName={file.name}>\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage(message)}\n </Typography>\n {/* Generation has no intermediate progress to report, so the bar stays indeterminate. */}\n {file.metadataStatus === 'generating' && <IndeterminateBar />}\n </FileRow>\n );\n }\n\n return null;\n};\n\nconst CompletedFilesList = styled(Flex)`\n flex-direction: column;\n gap: ${({ theme }) => theme.spaces[2]};\n width: 100%;\n`;\n\nexport const UploadProgressDialog = () => {\n const dispatch = useTypedDispatch();\n const { isVisible, isMinimized, files } = useTypedSelector((state) => state.uploadProgress);\n\n // With concurrent uploads several files are `uploading` at once — render every\n // in-flight row, not just the first (a `find` here dated to the strictly\n // sequential era and hid all but the lowest-index worker's row).\n const uploadingFiles = files.filter((f) => f.status === 'uploading');\n // Everything the pool has not reached yet. Listed in queue order, which is the\n // order `files` is already in, so a row's position tells the user where it sits.\n const queuedFiles = files.filter((f) => f.status === 'pending');\n const completedFiles = files\n .filter((f) => f.status === 'complete' || f.status === 'error' || f.status === 'cancelled')\n .sort((a, b) => {\n // Sort priority: error > cancelled > complete\n const priority: Record<FileProgressStatus, number> = {\n error: 0,\n cancelled: 1,\n complete: 2,\n uploading: 3,\n pending: 4,\n };\n return priority[a.status] - priority[b.status];\n });\n\n const handleClose = () => {\n dispatch(closeUploadProgress());\n };\n\n return (\n <Drawer.Root isVisible={isVisible} onClose={handleClose}>\n <Drawer.Body animationDirection=\"up\" width=\"41.6rem\" maxHeight=\"34.2rem\">\n <DialogHeader handleClose={handleClose} />\n <Drawer.ScrollableContent isContentExpanded={!isMinimized}>\n <Flex\n direction=\"column\"\n alignItems=\"stretch\"\n gap={4}\n paddingTop={4}\n paddingBottom={4}\n paddingLeft={4}\n paddingRight={4}\n >\n {uploadingFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n\n {queuedFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n\n {completedFiles.length > 0 && (\n <CompletedFilesList>\n {completedFiles.map((file) => (\n <FileRowRenderer key={file.index} file={file} />\n ))}\n </CompletedFilesList>\n )}\n </Flex>\n </Drawer.ScrollableContent>\n </Drawer.Body>\n </Drawer.Root>\n );\n};\n"],"names":["HeaderStatusMessage","title","subtitle","metadataSubtitle","_jsxs","Flex","direction","alignItems","paddingLeft","_jsx","Drawer","Title","Typography","variant","Description","textColor","HeaderStatusIcon","styled","theme","spaces","borderRadius","HeaderStatusWrapper","HeaderStatus","status","progress","totalFiles","successfulCount","errorCount","metadataProgress","isGeneratingMetadata","metadataOutcome","formatMessage","useIntl","id","getTranslationKey","defaultMessage","percentage","undefined","generated","failed","generatedCount","failedCount","count","background","Cross","fill","successCount","Check","MinusCircle","progressPercentage","Math","round","Upload","total","HeaderIconButton","IconButton","ChevronWrapper","span","$isMinimized","HEADER_COLOR_MAP","uploading","canceled","success","error","DialogHeader","handleClose","isMinimized","files","uploadId","useTypedSelector","state","uploadProgress","selectAggregateProgress","selectMetadataProgress","selectIsGeneratingMetadata","selectMetadataOutcome","dispatch","useTypedDispatch","retryCancelledFiles","useRetryCancelledFilesMutation","isComplete","length","every","f","isAllUploaded","isAllErrored","hasCancelledFiles","some","filter","isSuccess","handleCancel","abortUpload","cancelUpload","handleRetry","unwrap","handleToggleMinimize","toggleMinimize","justifyContent","margin","hasRadius","gap","TextButton","onClick","fontWeight","label","ChevronDown","CloseButton","onClose","ProgressTrack","div","colors","neutral200","ProgressIndicator","$percent","primary700","DeterminateBar","percent","clamped","min","max","role","aria-valuemin","aria-valuemax","aria-valuenow","INDETERMINATE_INDICATOR_WIDTH","indeterminateSlide","keyframes","IndeterminateIndicator","IndeterminateBar","FileRow","icon","fileName","children","width","ellipsis","COMPLETED_ROW_PRESENTATION","none","CheckCircle","message","generating","Sparkle","skipped","Information","WarningCircle","FileRowRenderer","file","isError","isCurrentFile","isCompleted","isCancelled","isQueued","Clock","name","hasReportedProgress","size","uploadedBytes","ArrowsCounterClockwise","CrossCircle","metadataStatus","CompletedFilesList","UploadProgressDialog","isVisible","uploadingFiles","queuedFiles","completedFiles","sort","a","b","priority","cancelled","complete","pending","closeUploadProgress","Root","Body","animationDirection","maxHeight","ScrollableContent","isContentExpanded","paddingTop","paddingBottom","paddingRight","map","index"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var reactIntl = require('react-intl');
|
|
5
|
+
var getApiErrorMessage = require('../utils/getApiErrorMessage.js');
|
|
6
|
+
var translations = require('../utils/translations.js');
|
|
7
|
+
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Turns an API error into something displayable, falling back to the caller's
|
|
30
|
+
* own localized copy when the error carries nothing usable.
|
|
31
|
+
*
|
|
32
|
+
* The server sends either a bare code (`body.ts`'s `FileTooBig`) or a ready-made
|
|
33
|
+
* sentence, and the same button can produce either. A code with a
|
|
34
|
+
* `upload.apiError.*` entry resolves to it; anything else is returned untouched.
|
|
35
|
+
*
|
|
36
|
+
* Checking `messages` rather than passing the text as `defaultMessage` keeps
|
|
37
|
+
* untrusted server text away from the ICU parser, where a stray `{` (a
|
|
38
|
+
* validation message echoing a field name) fails to parse — silent in
|
|
39
|
+
* production, but a throw under Jest, which patches `console.error`.
|
|
40
|
+
*
|
|
41
|
+
* Memoized because consumers hold the result in their own `useCallback`
|
|
42
|
+
* dependency arrays.
|
|
43
|
+
*/ const useApiErrorMessage = ()=>{
|
|
44
|
+
const { formatMessage, messages } = reactIntl.useIntl();
|
|
45
|
+
return React__namespace.useCallback((error, fallback)=>{
|
|
46
|
+
const message = getApiErrorMessage.getApiErrorMessage(error);
|
|
47
|
+
if (!message) {
|
|
48
|
+
return fallback;
|
|
49
|
+
}
|
|
50
|
+
const id = translations.getTranslationKey(`apiError.${message}`);
|
|
51
|
+
return messages[id] ? formatMessage({
|
|
52
|
+
id
|
|
53
|
+
}) : message;
|
|
54
|
+
}, [
|
|
55
|
+
formatMessage,
|
|
56
|
+
messages
|
|
57
|
+
]);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
exports.useApiErrorMessage = useApiErrorMessage;
|
|
61
|
+
//# sourceMappingURL=useApiErrorMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useApiErrorMessage.js","sources":["../../../../admin/src/future/hooks/useApiErrorMessage.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useIntl } from 'react-intl';\n\nimport { getApiErrorMessage } from '../utils/getApiErrorMessage';\nimport { getTranslationKey } from '../utils/translations';\n\n/**\n * Turns an API error into something displayable, falling back to the caller's\n * own localized copy when the error carries nothing usable.\n *\n * The server sends either a bare code (`body.ts`'s `FileTooBig`) or a ready-made\n * sentence, and the same button can produce either. A code with a\n * `upload.apiError.*` entry resolves to it; anything else is returned untouched.\n *\n * Checking `messages` rather than passing the text as `defaultMessage` keeps\n * untrusted server text away from the ICU parser, where a stray `{` (a\n * validation message echoing a field name) fails to parse — silent in\n * production, but a throw under Jest, which patches `console.error`.\n *\n * Memoized because consumers hold the result in their own `useCallback`\n * dependency arrays.\n */\nexport const useApiErrorMessage = () => {\n const { formatMessage, messages } = useIntl();\n\n return React.useCallback(\n (error: unknown, fallback: string) => {\n const message = getApiErrorMessage(error);\n\n if (!message) {\n return fallback;\n }\n\n const id = getTranslationKey(`apiError.${message}`);\n\n return messages[id] ? formatMessage({ id }) : message;\n },\n [formatMessage, messages]\n );\n};\n"],"names":["useApiErrorMessage","formatMessage","messages","useIntl","React","useCallback","error","fallback","message","getApiErrorMessage","id","getTranslationKey"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA;;;;;;;;;;;;;;;UAgBaA,kBAAAA,GAAqB,IAAA;AAChC,IAAA,MAAM,EAAEC,aAAa,EAAEC,QAAQ,EAAE,GAAGC,iBAAAA,EAAAA;AAEpC,IAAA,OAAOC,gBAAAA,CAAMC,WAAW,CACtB,CAACC,KAAAA,EAAgBC,QAAAA,GAAAA;AACf,QAAA,MAAMC,UAAUC,qCAAAA,CAAmBH,KAAAA,CAAAA;AAEnC,QAAA,IAAI,CAACE,OAAAA,EAAS;YACZ,OAAOD,QAAAA;AACT,QAAA;AAEA,QAAA,MAAMG,EAAAA,GAAKC,8BAAAA,CAAkB,CAAC,SAAS,EAAEH,OAAAA,CAAAA,CAAS,CAAA;AAElD,QAAA,OAAON,QAAQ,CAACQ,EAAAA,CAAG,GAAGT,aAAAA,CAAc;AAAES,YAAAA;SAAG,CAAA,GAAKF,OAAAA;IAChD,CAAA,EACA;AAACP,QAAAA,aAAAA;AAAeC,QAAAA;AAAS,KAAA,CAAA;AAE7B;;;;"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import { getApiErrorMessage } from '../utils/getApiErrorMessage.mjs';
|
|
4
|
+
import { getTranslationKey } from '../utils/translations.mjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Turns an API error into something displayable, falling back to the caller's
|
|
8
|
+
* own localized copy when the error carries nothing usable.
|
|
9
|
+
*
|
|
10
|
+
* The server sends either a bare code (`body.ts`'s `FileTooBig`) or a ready-made
|
|
11
|
+
* sentence, and the same button can produce either. A code with a
|
|
12
|
+
* `upload.apiError.*` entry resolves to it; anything else is returned untouched.
|
|
13
|
+
*
|
|
14
|
+
* Checking `messages` rather than passing the text as `defaultMessage` keeps
|
|
15
|
+
* untrusted server text away from the ICU parser, where a stray `{` (a
|
|
16
|
+
* validation message echoing a field name) fails to parse — silent in
|
|
17
|
+
* production, but a throw under Jest, which patches `console.error`.
|
|
18
|
+
*
|
|
19
|
+
* Memoized because consumers hold the result in their own `useCallback`
|
|
20
|
+
* dependency arrays.
|
|
21
|
+
*/ const useApiErrorMessage = ()=>{
|
|
22
|
+
const { formatMessage, messages } = useIntl();
|
|
23
|
+
return React.useCallback((error, fallback)=>{
|
|
24
|
+
const message = getApiErrorMessage(error);
|
|
25
|
+
if (!message) {
|
|
26
|
+
return fallback;
|
|
27
|
+
}
|
|
28
|
+
const id = getTranslationKey(`apiError.${message}`);
|
|
29
|
+
return messages[id] ? formatMessage({
|
|
30
|
+
id
|
|
31
|
+
}) : message;
|
|
32
|
+
}, [
|
|
33
|
+
formatMessage,
|
|
34
|
+
messages
|
|
35
|
+
]);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export { useApiErrorMessage };
|
|
39
|
+
//# sourceMappingURL=useApiErrorMessage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useApiErrorMessage.mjs","sources":["../../../../admin/src/future/hooks/useApiErrorMessage.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useIntl } from 'react-intl';\n\nimport { getApiErrorMessage } from '../utils/getApiErrorMessage';\nimport { getTranslationKey } from '../utils/translations';\n\n/**\n * Turns an API error into something displayable, falling back to the caller's\n * own localized copy when the error carries nothing usable.\n *\n * The server sends either a bare code (`body.ts`'s `FileTooBig`) or a ready-made\n * sentence, and the same button can produce either. A code with a\n * `upload.apiError.*` entry resolves to it; anything else is returned untouched.\n *\n * Checking `messages` rather than passing the text as `defaultMessage` keeps\n * untrusted server text away from the ICU parser, where a stray `{` (a\n * validation message echoing a field name) fails to parse — silent in\n * production, but a throw under Jest, which patches `console.error`.\n *\n * Memoized because consumers hold the result in their own `useCallback`\n * dependency arrays.\n */\nexport const useApiErrorMessage = () => {\n const { formatMessage, messages } = useIntl();\n\n return React.useCallback(\n (error: unknown, fallback: string) => {\n const message = getApiErrorMessage(error);\n\n if (!message) {\n return fallback;\n }\n\n const id = getTranslationKey(`apiError.${message}`);\n\n return messages[id] ? formatMessage({ id }) : message;\n },\n [formatMessage, messages]\n );\n};\n"],"names":["useApiErrorMessage","formatMessage","messages","useIntl","React","useCallback","error","fallback","message","getApiErrorMessage","id","getTranslationKey"],"mappings":";;;;;AAOA;;;;;;;;;;;;;;;UAgBaA,kBAAAA,GAAqB,IAAA;AAChC,IAAA,MAAM,EAAEC,aAAa,EAAEC,QAAQ,EAAE,GAAGC,OAAAA,EAAAA;AAEpC,IAAA,OAAOC,KAAAA,CAAMC,WAAW,CACtB,CAACC,KAAAA,EAAgBC,QAAAA,GAAAA;AACf,QAAA,MAAMC,UAAUC,kBAAAA,CAAmBH,KAAAA,CAAAA;AAEnC,QAAA,IAAI,CAACE,OAAAA,EAAS;YACZ,OAAOD,QAAAA;AACT,QAAA;AAEA,QAAA,MAAMG,EAAAA,GAAKC,iBAAAA,CAAkB,CAAC,SAAS,EAAEH,OAAAA,CAAAA,CAAS,CAAA;AAElD,QAAA,OAAON,QAAQ,CAACQ,EAAAA,CAAG,GAAGT,aAAAA,CAAc;AAAES,YAAAA;SAAG,CAAA,GAAKF,OAAAA;IAChD,CAAA,EACA;AAACP,QAAAA,aAAAA;AAAeC,QAAAA;AAAS,KAAA,CAAA;AAE7B;;;;"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var strapiAdmin = require('@strapi/admin/strapi-admin');
|
|
5
|
+
var ee = require('@strapi/admin/strapi-admin/ee');
|
|
6
|
+
var settings = require('../services/settings.js');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Media Library version tag stamped on every event fired from the new
|
|
10
|
+
* (`src/future`) Media Library. Legacy events omit it, so analytics can filter
|
|
11
|
+
* new usage from the old plan while both trees emit the SAME event names (see
|
|
12
|
+
* CMS-246). Bump this if a future revamp ever needs its own bucket.
|
|
13
|
+
*/ const MEDIA_LIBRARY_VERSION = 'v2';
|
|
14
|
+
/**
|
|
15
|
+
* `location` value for every new Media Library event. The new tree is the
|
|
16
|
+
* standalone Media Library page, which the legacy plan tags `'upload'` (as
|
|
17
|
+
* opposed to `'content-manager'` for the asset-picker modal). Kept identical so
|
|
18
|
+
* migrated events line up with the legacy ones on the `location` axis.
|
|
19
|
+
*/ const MEDIA_LIBRARY_LOCATION = 'upload';
|
|
20
|
+
/**
|
|
21
|
+
* Tracking wrapper scoped to the new Media Library. Mirrors the legacy
|
|
22
|
+
* `admin/src/hooks/useTracking` — it forwards to the admin `trackUsage` and
|
|
23
|
+
* injects `isAiMediaLibraryConfigured` when AI is available — and additionally
|
|
24
|
+
* stamps `mediaLibraryVersion` on every event so the migrated plan stays
|
|
25
|
+
* distinguishable from the legacy one.
|
|
26
|
+
*
|
|
27
|
+
* The cast mirrors the legacy wrapper: these two properties are cross-cutting
|
|
28
|
+
* media-tracking metadata that the admin `TrackingEvent` type does not (and
|
|
29
|
+
* should not) enumerate per event.
|
|
30
|
+
*/ const useTracking = ()=>{
|
|
31
|
+
const { trackUsage: trackStrapiUsage } = strapiAdmin.useTracking();
|
|
32
|
+
const { data } = settings.useGetUploadSettingsQuery();
|
|
33
|
+
const isAiAvailable = ee.useAIAvailability();
|
|
34
|
+
// Memoised so consumers can safely list `trackUsage` in effect deps (the
|
|
35
|
+
// search-input debounce commit does) without re-firing every render.
|
|
36
|
+
const trackUsage = React.useCallback((event, properties)=>{
|
|
37
|
+
return trackStrapiUsage(event, {
|
|
38
|
+
...properties,
|
|
39
|
+
...isAiAvailable ? {
|
|
40
|
+
isAiMediaLibraryConfigured: Boolean(data?.data?.aiMetadata)
|
|
41
|
+
} : {},
|
|
42
|
+
mediaLibraryVersion: MEDIA_LIBRARY_VERSION
|
|
43
|
+
});
|
|
44
|
+
}, [
|
|
45
|
+
trackStrapiUsage,
|
|
46
|
+
isAiAvailable,
|
|
47
|
+
data
|
|
48
|
+
]);
|
|
49
|
+
return {
|
|
50
|
+
trackUsage
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
exports.MEDIA_LIBRARY_LOCATION = MEDIA_LIBRARY_LOCATION;
|
|
55
|
+
exports.MEDIA_LIBRARY_VERSION = MEDIA_LIBRARY_VERSION;
|
|
56
|
+
exports.useTracking = useTracking;
|
|
57
|
+
//# sourceMappingURL=useTracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTracking.js","sources":["../../../../admin/src/future/hooks/useTracking.ts"],"sourcesContent":["import { useCallback } from 'react';\n\nimport { useTracking as useStrapiTracking, type TrackingEvent } from '@strapi/admin/strapi-admin';\nimport { useAIAvailability } from '@strapi/admin/strapi-admin/ee';\n\nimport { useGetUploadSettingsQuery } from '../services/settings';\n\n/**\n * Media Library version tag stamped on every event fired from the new\n * (`src/future`) Media Library. Legacy events omit it, so analytics can filter\n * new usage from the old plan while both trees emit the SAME event names (see\n * CMS-246). Bump this if a future revamp ever needs its own bucket.\n */\nexport const MEDIA_LIBRARY_VERSION = 'v2';\n\n/**\n * `location` value for every new Media Library event. The new tree is the\n * standalone Media Library page, which the legacy plan tags `'upload'` (as\n * opposed to `'content-manager'` for the asset-picker modal). Kept identical so\n * migrated events line up with the legacy ones on the `location` axis.\n */\nexport const MEDIA_LIBRARY_LOCATION = 'upload';\n\n/**\n * Tracking wrapper scoped to the new Media Library. Mirrors the legacy\n * `admin/src/hooks/useTracking` — it forwards to the admin `trackUsage` and\n * injects `isAiMediaLibraryConfigured` when AI is available — and additionally\n * stamps `mediaLibraryVersion` on every event so the migrated plan stays\n * distinguishable from the legacy one.\n *\n * The cast mirrors the legacy wrapper: these two properties are cross-cutting\n * media-tracking metadata that the admin `TrackingEvent` type does not (and\n * should not) enumerate per event.\n */\nexport const useTracking = () => {\n const { trackUsage: trackStrapiUsage } = useStrapiTracking();\n const { data } = useGetUploadSettingsQuery();\n const isAiAvailable = useAIAvailability();\n\n // Memoised so consumers can safely list `trackUsage` in effect deps (the\n // search-input debounce commit does) without re-firing every render.\n const trackUsage = useCallback(\n <TEvent extends TrackingEvent>(event: TEvent['name'], properties?: TEvent['properties']) => {\n return trackStrapiUsage(event, {\n ...properties,\n ...(isAiAvailable ? { isAiMediaLibraryConfigured: Boolean(data?.data?.aiMetadata) } : {}),\n mediaLibraryVersion: MEDIA_LIBRARY_VERSION,\n } as TEvent['properties']);\n },\n [trackStrapiUsage, isAiAvailable, data]\n );\n\n return { trackUsage };\n};\n"],"names":["MEDIA_LIBRARY_VERSION","MEDIA_LIBRARY_LOCATION","useTracking","trackUsage","trackStrapiUsage","useStrapiTracking","data","useGetUploadSettingsQuery","isAiAvailable","useAIAvailability","useCallback","event","properties","isAiMediaLibraryConfigured","Boolean","aiMetadata","mediaLibraryVersion"],"mappings":";;;;;;;AAOA;;;;;IAMO,MAAMA,qBAAAA,GAAwB;AAErC;;;;;IAMO,MAAMC,sBAAAA,GAAyB;AAEtC;;;;;;;;;;UAWaC,WAAAA,GAAc,IAAA;AACzB,IAAA,MAAM,EAAEC,UAAAA,EAAYC,gBAAgB,EAAE,GAAGC,uBAAAA,EAAAA;IACzC,MAAM,EAAEC,IAAI,EAAE,GAAGC,kCAAAA,EAAAA;AACjB,IAAA,MAAMC,aAAAA,GAAgBC,oBAAAA,EAAAA;;;IAItB,MAAMN,UAAAA,GAAaO,iBAAAA,CACjB,CAA+BC,KAAAA,EAAuBC,UAAAA,GAAAA;AACpD,QAAA,OAAOR,iBAAiBO,KAAAA,EAAO;AAC7B,YAAA,GAAGC,UAAU;AACb,YAAA,GAAIJ,aAAAA,GAAgB;gBAAEK,0BAAAA,EAA4BC,OAAAA,CAAQR,MAAMA,IAAAA,EAAMS,UAAAA;AAAY,aAAA,GAAI,EAAE;YACxFC,mBAAAA,EAAqBhB;AACvB,SAAA,CAAA;IACF,CAAA,EACA;AAACI,QAAAA,gBAAAA;AAAkBI,QAAAA,aAAAA;AAAeF,QAAAA;AAAK,KAAA,CAAA;IAGzC,OAAO;AAAEH,QAAAA;AAAW,KAAA;AACtB;;;;;;"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { useTracking as useTracking$1 } from '@strapi/admin/strapi-admin';
|
|
3
|
+
import { useAIAvailability } from '@strapi/admin/strapi-admin/ee';
|
|
4
|
+
import { useGetUploadSettingsQuery } from '../services/settings.mjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Media Library version tag stamped on every event fired from the new
|
|
8
|
+
* (`src/future`) Media Library. Legacy events omit it, so analytics can filter
|
|
9
|
+
* new usage from the old plan while both trees emit the SAME event names (see
|
|
10
|
+
* CMS-246). Bump this if a future revamp ever needs its own bucket.
|
|
11
|
+
*/ const MEDIA_LIBRARY_VERSION = 'v2';
|
|
12
|
+
/**
|
|
13
|
+
* `location` value for every new Media Library event. The new tree is the
|
|
14
|
+
* standalone Media Library page, which the legacy plan tags `'upload'` (as
|
|
15
|
+
* opposed to `'content-manager'` for the asset-picker modal). Kept identical so
|
|
16
|
+
* migrated events line up with the legacy ones on the `location` axis.
|
|
17
|
+
*/ const MEDIA_LIBRARY_LOCATION = 'upload';
|
|
18
|
+
/**
|
|
19
|
+
* Tracking wrapper scoped to the new Media Library. Mirrors the legacy
|
|
20
|
+
* `admin/src/hooks/useTracking` — it forwards to the admin `trackUsage` and
|
|
21
|
+
* injects `isAiMediaLibraryConfigured` when AI is available — and additionally
|
|
22
|
+
* stamps `mediaLibraryVersion` on every event so the migrated plan stays
|
|
23
|
+
* distinguishable from the legacy one.
|
|
24
|
+
*
|
|
25
|
+
* The cast mirrors the legacy wrapper: these two properties are cross-cutting
|
|
26
|
+
* media-tracking metadata that the admin `TrackingEvent` type does not (and
|
|
27
|
+
* should not) enumerate per event.
|
|
28
|
+
*/ const useTracking = ()=>{
|
|
29
|
+
const { trackUsage: trackStrapiUsage } = useTracking$1();
|
|
30
|
+
const { data } = useGetUploadSettingsQuery();
|
|
31
|
+
const isAiAvailable = useAIAvailability();
|
|
32
|
+
// Memoised so consumers can safely list `trackUsage` in effect deps (the
|
|
33
|
+
// search-input debounce commit does) without re-firing every render.
|
|
34
|
+
const trackUsage = useCallback((event, properties)=>{
|
|
35
|
+
return trackStrapiUsage(event, {
|
|
36
|
+
...properties,
|
|
37
|
+
...isAiAvailable ? {
|
|
38
|
+
isAiMediaLibraryConfigured: Boolean(data?.data?.aiMetadata)
|
|
39
|
+
} : {},
|
|
40
|
+
mediaLibraryVersion: MEDIA_LIBRARY_VERSION
|
|
41
|
+
});
|
|
42
|
+
}, [
|
|
43
|
+
trackStrapiUsage,
|
|
44
|
+
isAiAvailable,
|
|
45
|
+
data
|
|
46
|
+
]);
|
|
47
|
+
return {
|
|
48
|
+
trackUsage
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { MEDIA_LIBRARY_LOCATION, MEDIA_LIBRARY_VERSION, useTracking };
|
|
53
|
+
//# sourceMappingURL=useTracking.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTracking.mjs","sources":["../../../../admin/src/future/hooks/useTracking.ts"],"sourcesContent":["import { useCallback } from 'react';\n\nimport { useTracking as useStrapiTracking, type TrackingEvent } from '@strapi/admin/strapi-admin';\nimport { useAIAvailability } from '@strapi/admin/strapi-admin/ee';\n\nimport { useGetUploadSettingsQuery } from '../services/settings';\n\n/**\n * Media Library version tag stamped on every event fired from the new\n * (`src/future`) Media Library. Legacy events omit it, so analytics can filter\n * new usage from the old plan while both trees emit the SAME event names (see\n * CMS-246). Bump this if a future revamp ever needs its own bucket.\n */\nexport const MEDIA_LIBRARY_VERSION = 'v2';\n\n/**\n * `location` value for every new Media Library event. The new tree is the\n * standalone Media Library page, which the legacy plan tags `'upload'` (as\n * opposed to `'content-manager'` for the asset-picker modal). Kept identical so\n * migrated events line up with the legacy ones on the `location` axis.\n */\nexport const MEDIA_LIBRARY_LOCATION = 'upload';\n\n/**\n * Tracking wrapper scoped to the new Media Library. Mirrors the legacy\n * `admin/src/hooks/useTracking` — it forwards to the admin `trackUsage` and\n * injects `isAiMediaLibraryConfigured` when AI is available — and additionally\n * stamps `mediaLibraryVersion` on every event so the migrated plan stays\n * distinguishable from the legacy one.\n *\n * The cast mirrors the legacy wrapper: these two properties are cross-cutting\n * media-tracking metadata that the admin `TrackingEvent` type does not (and\n * should not) enumerate per event.\n */\nexport const useTracking = () => {\n const { trackUsage: trackStrapiUsage } = useStrapiTracking();\n const { data } = useGetUploadSettingsQuery();\n const isAiAvailable = useAIAvailability();\n\n // Memoised so consumers can safely list `trackUsage` in effect deps (the\n // search-input debounce commit does) without re-firing every render.\n const trackUsage = useCallback(\n <TEvent extends TrackingEvent>(event: TEvent['name'], properties?: TEvent['properties']) => {\n return trackStrapiUsage(event, {\n ...properties,\n ...(isAiAvailable ? { isAiMediaLibraryConfigured: Boolean(data?.data?.aiMetadata) } : {}),\n mediaLibraryVersion: MEDIA_LIBRARY_VERSION,\n } as TEvent['properties']);\n },\n [trackStrapiUsage, isAiAvailable, data]\n );\n\n return { trackUsage };\n};\n"],"names":["MEDIA_LIBRARY_VERSION","MEDIA_LIBRARY_LOCATION","useTracking","trackUsage","trackStrapiUsage","useStrapiTracking","data","useGetUploadSettingsQuery","isAiAvailable","useAIAvailability","useCallback","event","properties","isAiMediaLibraryConfigured","Boolean","aiMetadata","mediaLibraryVersion"],"mappings":";;;;;AAOA;;;;;IAMO,MAAMA,qBAAAA,GAAwB;AAErC;;;;;IAMO,MAAMC,sBAAAA,GAAyB;AAEtC;;;;;;;;;;UAWaC,WAAAA,GAAc,IAAA;AACzB,IAAA,MAAM,EAAEC,UAAAA,EAAYC,gBAAgB,EAAE,GAAGC,aAAAA,EAAAA;IACzC,MAAM,EAAEC,IAAI,EAAE,GAAGC,yBAAAA,EAAAA;AACjB,IAAA,MAAMC,aAAAA,GAAgBC,iBAAAA,EAAAA;;;IAItB,MAAMN,UAAAA,GAAaO,WAAAA,CACjB,CAA+BC,KAAAA,EAAuBC,UAAAA,GAAAA;AACpD,QAAA,OAAOR,iBAAiBO,KAAAA,EAAO;AAC7B,YAAA,GAAGC,UAAU;AACb,YAAA,GAAIJ,aAAAA,GAAgB;gBAAEK,0BAAAA,EAA4BC,OAAAA,CAAQR,MAAMA,IAAAA,EAAMS,UAAAA;AAAY,aAAA,GAAI,EAAE;YACxFC,mBAAAA,EAAqBhB;AACvB,SAAA,CAAA;IACF,CAAA,EACA;AAACI,QAAAA,gBAAAA;AAAkBI,QAAAA,aAAAA;AAAeF,QAAAA;AAAK,KAAA,CAAA;IAGzC,OAAO;AAAEH,QAAAA;AAAW,KAAA;AACtB;;;;"}
|
|
@@ -8,9 +8,11 @@ var designSystem = require('@strapi/design-system');
|
|
|
8
8
|
var icons = require('@strapi/icons');
|
|
9
9
|
var reactIntl = require('react-intl');
|
|
10
10
|
var styledComponents = require('styled-components');
|
|
11
|
+
var typeFromMime = require('../../../utils/typeFromMime.js');
|
|
11
12
|
var BetaNotice = require('../../components/BetaNotice.js');
|
|
12
13
|
var useAIMetadataEnabled = require('../../hooks/useAIMetadataEnabled.js');
|
|
13
14
|
var useMediaLibraryPermissions = require('../../hooks/useMediaLibraryPermissions.js');
|
|
15
|
+
var useTracking = require('../../hooks/useTracking.js');
|
|
14
16
|
var api = require('../../services/api.js');
|
|
15
17
|
var folders = require('../../services/folders.js');
|
|
16
18
|
var settings = require('../../services/settings.js');
|
|
@@ -488,8 +490,20 @@ const AssetsPage = ()=>{
|
|
|
488
490
|
// dialog. No mime argument: the files are not known until they are picked,
|
|
489
491
|
// and the server filters the batch on the same allowlist anyway.
|
|
490
492
|
const isAiMetadataEnabled = useAIMetadataEnabled.useAIMetadataEnabled();
|
|
493
|
+
const { trackUsage } = useTracking.useTracking();
|
|
491
494
|
const uploadFilesToFolder = async (files, folderId)=>{
|
|
492
495
|
if (files.length === 0) return;
|
|
496
|
+
// Mirror the legacy `willAddMediaLibraryAssets` payload: the count of files
|
|
497
|
+
// about to upload, broken down by asset type.
|
|
498
|
+
const assetsCountByType = files.reduce((acc, file)=>{
|
|
499
|
+
const type = typeFromMime.typeFromMime(file.type);
|
|
500
|
+
acc[type] = (acc[type] ?? 0) + 1;
|
|
501
|
+
return acc;
|
|
502
|
+
}, {});
|
|
503
|
+
trackUsage('willAddMediaLibraryAssets', {
|
|
504
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION,
|
|
505
|
+
...assetsCountByType
|
|
506
|
+
});
|
|
493
507
|
const formData = new FormData();
|
|
494
508
|
const fileInfoArray = [];
|
|
495
509
|
files.forEach((file)=>{
|
|
@@ -519,6 +533,10 @@ const AssetsPage = ()=>{
|
|
|
519
533
|
const handleFileChange = async (e)=>{
|
|
520
534
|
const files = e.target.files;
|
|
521
535
|
if (files && files.length > 0) {
|
|
536
|
+
trackUsage('didSelectFile', {
|
|
537
|
+
source: 'computer',
|
|
538
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION
|
|
539
|
+
});
|
|
522
540
|
await uploadFilesToFolder(Array.from(files), currentFolderId);
|
|
523
541
|
}
|
|
524
542
|
e.target.value = '';
|
|
@@ -527,9 +545,22 @@ const AssetsPage = ()=>{
|
|
|
527
545
|
// Defence in depth: the provider is `disabled` without `assets.create`
|
|
528
546
|
// (so onDrop won't fire), but guard here too in case it's ever wired live.
|
|
529
547
|
if (!canCreate) return;
|
|
548
|
+
trackUsage('didSelectFile', {
|
|
549
|
+
source: 'computer',
|
|
550
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION
|
|
551
|
+
});
|
|
530
552
|
await uploadFilesToFolder(files, currentFolderId);
|
|
531
553
|
};
|
|
532
554
|
const handleUrlUpload = async (urls)=>{
|
|
555
|
+
trackUsage('didSelectFile', {
|
|
556
|
+
source: 'url',
|
|
557
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION
|
|
558
|
+
});
|
|
559
|
+
// Counts-by-type aren't available client-side for the URL flow (the server
|
|
560
|
+
// fetches the files), so this fires the event with location only.
|
|
561
|
+
trackUsage('willAddMediaLibraryAssets', {
|
|
562
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION
|
|
563
|
+
});
|
|
533
564
|
try {
|
|
534
565
|
await uploadFromUrls({
|
|
535
566
|
urls,
|