@strapi/upload 5.50.1 → 5.51.0

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.
Files changed (75) hide show
  1. package/dist/admin/ai/components/AIAssetCard.js +7 -1
  2. package/dist/admin/ai/components/AIAssetCard.js.map +1 -1
  3. package/dist/admin/ai/components/AIAssetCard.mjs +7 -1
  4. package/dist/admin/ai/components/AIAssetCard.mjs.map +1 -1
  5. package/dist/admin/components/AssetCard/AssetCard.js +6 -0
  6. package/dist/admin/components/AssetCard/AssetCard.js.map +1 -1
  7. package/dist/admin/components/AssetCard/AssetCard.mjs +6 -0
  8. package/dist/admin/components/AssetCard/AssetCard.mjs.map +1 -1
  9. package/dist/admin/components/AssetCard/ImageAssetCard.js +3 -2
  10. package/dist/admin/components/AssetCard/ImageAssetCard.js.map +1 -1
  11. package/dist/admin/components/AssetCard/ImageAssetCard.mjs +3 -2
  12. package/dist/admin/components/AssetCard/ImageAssetCard.mjs.map +1 -1
  13. package/dist/admin/components/EditAssetDialog/EditAssetContent.js +2 -2
  14. package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
  15. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs +2 -2
  16. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
  17. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.js +8 -0
  18. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.js.map +1 -1
  19. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.mjs +8 -0
  20. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.mjs.map +1 -1
  21. package/dist/admin/components/TableList/PreviewCell.js +5 -1
  22. package/dist/admin/components/TableList/PreviewCell.js.map +1 -1
  23. package/dist/admin/components/TableList/PreviewCell.mjs +5 -1
  24. package/dist/admin/components/TableList/PreviewCell.mjs.map +1 -1
  25. package/dist/admin/future/pages/Assets/AssetsPage.js +6 -11
  26. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  27. package/dist/admin/future/pages/Assets/AssetsPage.mjs +6 -11
  28. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  29. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js +6 -3
  30. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js.map +1 -1
  31. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs +6 -3
  32. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs.map +1 -1
  33. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +8 -12
  34. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
  35. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +10 -14
  36. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  37. package/dist/admin/future/pages/Assets/components/AssetsTable.js +15 -27
  38. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
  39. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +16 -28
  40. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
  41. package/dist/admin/future/pages/Assets/components/EmptyState.js +63 -0
  42. package/dist/admin/future/pages/Assets/components/EmptyState.js.map +1 -0
  43. package/dist/admin/future/pages/Assets/components/EmptyState.mjs +61 -0
  44. package/dist/admin/future/pages/Assets/components/EmptyState.mjs.map +1 -0
  45. package/dist/admin/future/services/uploadFileViaXHR.js +23 -2
  46. package/dist/admin/future/services/uploadFileViaXHR.js.map +1 -1
  47. package/dist/admin/future/services/uploadFileViaXHR.mjs +23 -2
  48. package/dist/admin/future/services/uploadFileViaXHR.mjs.map +1 -1
  49. package/dist/admin/hooks/useUpload.js +15 -9
  50. package/dist/admin/hooks/useUpload.js.map +1 -1
  51. package/dist/admin/hooks/useUpload.mjs +17 -11
  52. package/dist/admin/hooks/useUpload.mjs.map +1 -1
  53. package/dist/admin/src/components/AssetCard/ImageAssetCard.d.ts +2 -1
  54. package/dist/admin/src/future/pages/Assets/components/AssetsGrid.d.ts +1 -1
  55. package/dist/admin/src/future/pages/Assets/components/AssetsTable.d.ts +1 -1
  56. package/dist/admin/src/future/pages/Assets/components/EmptyState.d.ts +11 -0
  57. package/dist/admin/src/future/services/uploadFileViaXHR.d.ts +1 -17
  58. package/dist/admin/src/hooks/useAiAvailability.d.ts +1 -1
  59. package/dist/admin/src/hooks/useEditAsset.d.ts +4 -4
  60. package/dist/admin/src/hooks/useEditFolder.d.ts +4 -4
  61. package/dist/admin/src/hooks/useUpload.d.ts +1 -1
  62. package/dist/admin/translations/en.json.js +3 -0
  63. package/dist/admin/translations/en.json.js.map +1 -1
  64. package/dist/admin/translations/en.json.mjs +3 -0
  65. package/dist/admin/translations/en.json.mjs.map +1 -1
  66. package/dist/admin/translations/ko.json.js +183 -1
  67. package/dist/admin/translations/ko.json.js.map +1 -1
  68. package/dist/admin/translations/ko.json.mjs +183 -1
  69. package/dist/admin/translations/ko.json.mjs.map +1 -1
  70. package/dist/server/src/controllers/index.d.ts +1 -1
  71. package/dist/server/src/index.d.ts +11 -11
  72. package/dist/server/src/routes/index.d.ts +1 -1
  73. package/dist/server/src/services/image-manipulation.d.ts +3 -3
  74. package/dist/server/src/services/index.d.ts +9 -9
  75. package/package.json +17 -13
@@ -1 +1 @@
1
- {"version":3,"file":"AssetsTable.mjs","sources":["../../../../../../admin/src/future/pages/Assets/components/AssetsTable.tsx"],"sourcesContent":["import { useIsMobile } from '@strapi/admin/strapi-admin';\nimport {\n Flex,\n IconButton,\n RawTable,\n RawTbody,\n RawTd,\n RawTh,\n RawThead,\n RawTr,\n Typography,\n VisuallyHidden,\n} from '@strapi/design-system';\nimport { Folder as FolderIcon, More } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled, css } from 'styled-components';\n\nimport { formatBytes } from '../../../utils/files';\nimport { getAssetIcon } from '../../../utils/getAssetIcon';\nimport { getTranslationKey } from '../../../utils/translations';\nimport { TABLE_HEADERS } from '../constants';\nimport { useFolderNavigation } from '../hooks/useFolderNavigation';\n\nimport { useAssetsDndOptional } from './Dnd/AssetsDndProvider';\nimport { useFileDraggable, useFolderDraggableDroppable } from './Dnd/useAssetDnd';\n\nimport type { File } from '../../../../../../shared/contracts/files';\nimport type { Folder } from '../../../../../../shared/contracts/folders';\n\nconst StyledTable = styled(RawTable)`\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n border: 1px solid ${({ theme }) => theme.colors.neutral150};\n border-radius: 4px;\n overflow: hidden;\n`;\n\nconst StyledThead = styled(RawThead)`\n background: ${({ theme }) => theme.colors.neutral100};\n\n tr {\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};\n }\n`;\n\nconst StyledTh = styled(RawTh)`\n height: 40px;\n padding: 0 ${({ theme }) => theme.spaces[4]};\n text-align: left;\n`;\n\nconst StyledTd = styled(RawTd)`\n padding: 0 ${({ theme }) => theme.spaces[4]};\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};\n`;\n\nconst StyledTr = styled.tr<{\n $isDragging?: boolean;\n $isMovePending?: boolean;\n $isValidDropTarget?: boolean;\n $isInvalidDropTarget?: boolean;\n}>`\n height: 48px;\n background: ${({ theme }) => theme.colors.neutral0};\n cursor: ${({ $isMovePending, $isInvalidDropTarget }) => {\n if ($isMovePending) {\n return 'wait';\n }\n\n return $isInvalidDropTarget ? 'not-allowed' : 'pointer';\n }};\n opacity: ${({ $isDragging }) => ($isDragging ? 0.4 : 1)};\n pointer-events: ${({ $isMovePending }) => ($isMovePending ? 'none' : 'auto')};\n\n ${({ $isValidDropTarget, theme }) =>\n $isValidDropTarget &&\n css`\n background: ${theme.colors.primary100};\n outline: 1px dashed ${theme.colors.primary600};\n outline-offset: -1px;\n `}\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n\n &:last-child {\n ${StyledTd} {\n border-bottom: 0;\n }\n }\n`;\n\nconst StyledBodyTd = styled(RawTd)`\n padding: ${({ theme }) => theme.spaces[4]};\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};\n`;\n\ninterface AssetPreviewCellProps {\n asset: File;\n}\n\nconst AssetPreviewCell = ({ asset }: AssetPreviewCellProps) => {\n const { ext, mime } = asset;\n\n const DocIcon = getAssetIcon(mime, ext);\n\n return (\n <Flex\n justifyContent=\"center\"\n alignItems=\"center\"\n borderRadius=\"4px\"\n color=\"neutral500\"\n width=\"3.2rem\"\n height=\"3.2rem\"\n shrink={0}\n >\n <DocIcon width={20} height={20} />\n </Flex>\n );\n};\n\ninterface AssetRowProps {\n asset: File;\n onAssetItemClick: (assetId: number) => void;\n}\n\nconst AssetRow = ({ asset, onAssetItemClick }: AssetRowProps) => {\n const isMobile = useIsMobile();\n const { formatDate, formatMessage } = useIntl();\n const { isMovePending } = useAssetsDndOptional() ?? { isMovePending: false };\n const { attributes, listeners, setNodeRef, isDragging } = useFileDraggable(asset);\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onAssetItemClick(asset.id);\n }\n };\n\n return (\n <StyledTr\n ref={setNodeRef}\n {...attributes}\n {...listeners}\n $isDragging={isDragging}\n $isMovePending={isMovePending}\n tabIndex={0}\n role=\"row\"\n onDragStart={(e) => e.preventDefault()}\n onClick={() => onAssetItemClick(asset.id)}\n onKeyDown={handleKeyDown}\n >\n <StyledTd>\n <Flex gap={3} alignItems=\"center\">\n <AssetPreviewCell asset={asset} />\n <Flex direction=\"column\" alignItems=\"flex-start\">\n <Typography textColor=\"neutral800\" fontWeight=\"semiBold\" ellipsis>\n {asset.name}\n </Typography>\n {isMobile && (\n <Typography textColor=\"neutral600\" variant=\"pi\">\n {asset.size ? formatBytes(asset.size, 1) : '-'}\n </Typography>\n )}\n </Flex>\n </Flex>\n </StyledTd>\n {!isMobile && (\n <>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {asset.createdAt ? formatDate(new Date(asset.createdAt), { dateStyle: 'long' }) : '-'}\n </Typography>\n </StyledTd>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {asset.updatedAt ? formatDate(new Date(asset.updatedAt), { dateStyle: 'long' }) : '-'}\n </Typography>\n </StyledTd>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {asset.size ? formatBytes(asset.size, 1) : '-'}\n </Typography>\n </StyledTd>\n </>\n )}\n <StyledTd>\n <Flex justifyContent=\"flex-end\">\n <IconButton\n label={formatMessage({\n id: getTranslationKey('control-card.more-actions'),\n defaultMessage: 'More actions',\n })}\n variant=\"ghost\"\n onClick={(e: React.MouseEvent) => e.stopPropagation()}\n >\n <More />\n </IconButton>\n </Flex>\n </StyledTd>\n </StyledTr>\n );\n};\n\nconst FolderTr = styled(StyledTr)`\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n`;\n\ninterface FolderRowProps {\n folder: Folder;\n}\n\nconst FolderRow = ({ folder }: FolderRowProps) => {\n const isMobile = useIsMobile();\n const { formatDate, formatMessage } = useIntl();\n const { navigateToFolder } = useFolderNavigation();\n const { isMovePending } = useAssetsDndOptional() ?? { isMovePending: false };\n const {\n draggable: { attributes, listeners, setNodeRef: setDragRef, isDragging },\n droppable: { setNodeRef: setDropRef },\n showValidDropHighlight,\n showInvalidDropCursor,\n } = useFolderDraggableDroppable(folder);\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateToFolder(folder);\n }\n };\n\n return (\n <FolderTr\n ref={(node) => {\n setDragRef(node);\n setDropRef(node);\n }}\n {...attributes}\n {...listeners}\n $isDragging={isDragging}\n $isMovePending={isMovePending}\n $isValidDropTarget={showValidDropHighlight}\n $isInvalidDropTarget={showInvalidDropCursor}\n tabIndex={0}\n role=\"row\"\n onDragStart={(e) => e.preventDefault()}\n onClick={() => navigateToFolder(folder)}\n onKeyDown={handleKeyDown}\n >\n <StyledTd>\n <Flex gap={3} alignItems=\"center\">\n <Flex\n justifyContent=\"center\"\n alignItems=\"center\"\n borderRadius=\"4px\"\n color=\"neutral600\"\n width=\"3.2rem\"\n height=\"3.2rem\"\n shrink={0}\n >\n <FolderIcon width={20} height={20} />\n </Flex>\n <Typography textColor=\"neutral800\" fontWeight=\"semiBold\" ellipsis>\n {folder.name}\n </Typography>\n </Flex>\n </StyledTd>\n {!isMobile && (\n <>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {folder.createdAt\n ? formatDate(new Date(folder.createdAt), { dateStyle: 'long' })\n : '-'}\n </Typography>\n </StyledTd>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {folder.updatedAt\n ? formatDate(new Date(folder.updatedAt), { dateStyle: 'long' })\n : '-'}\n </Typography>\n </StyledTd>\n <StyledTd>\n <Typography textColor=\"neutral600\">-</Typography>\n </StyledTd>\n </>\n )}\n <StyledTd>\n <Flex justifyContent=\"flex-end\">\n <IconButton\n label={formatMessage({\n id: getTranslationKey('control-card.more-actions'),\n defaultMessage: 'More actions',\n })}\n variant=\"ghost\"\n onClick={(e: React.MouseEvent) => e.stopPropagation()}\n >\n <More />\n </IconButton>\n </Flex>\n </StyledTd>\n </FolderTr>\n );\n};\n\ninterface AssetsTableProps {\n assets: File[];\n folders?: Folder[];\n onAssetItemClick: (assetId: number) => void;\n}\n\nexport const AssetsTable = ({ assets, folders = [], onAssetItemClick }: AssetsTableProps) => {\n const isMobile = useIsMobile();\n const { formatMessage } = useIntl();\n\n const visibleHeaders = isMobile\n ? TABLE_HEADERS.filter((h) => h.name === 'name' || h.name === 'actions')\n : TABLE_HEADERS;\n\n const totalRows = folders.length + assets.length;\n\n return (\n <StyledTable colCount={visibleHeaders.length} rowCount={totalRows + 1}>\n <StyledThead>\n <RawTr>\n {visibleHeaders.map((header) => {\n const tableHeaderLabel = formatMessage(header.label);\n const isVisuallyHidden = 'isVisuallyHidden' in header && header.isVisuallyHidden;\n\n if (isVisuallyHidden) {\n return (\n <StyledTh key={header.name}>\n <VisuallyHidden>\n {formatMessage({\n id: getTranslationKey('table.header.actions'),\n defaultMessage: 'actions',\n })}\n </VisuallyHidden>\n </StyledTh>\n );\n }\n\n return (\n <StyledTh key={header.name}>\n <Typography textColor=\"neutral600\" variant=\"sigma\">\n {tableHeaderLabel}\n </Typography>\n </StyledTh>\n );\n })}\n </RawTr>\n </StyledThead>\n <RawTbody>\n {totalRows === 0 ? (\n <RawTr>\n <StyledBodyTd colSpan={visibleHeaders.length}>\n <Typography textColor=\"neutral600\">\n {formatMessage({\n id: 'app.components.EmptyStateLayout.content-document',\n defaultMessage: 'No content found',\n })}\n </Typography>\n </StyledBodyTd>\n </RawTr>\n ) : (\n <>\n {folders.map((folder) => (\n <FolderRow key={`folder-${folder.id}`} folder={folder} />\n ))}\n {assets.map((asset) => (\n <AssetRow key={asset.id} asset={asset} onAssetItemClick={onAssetItemClick} />\n ))}\n </>\n )}\n </RawTbody>\n </StyledTable>\n );\n};\n"],"names":["StyledTable","styled","RawTable","theme","colors","neutral150","StyledThead","RawThead","neutral100","StyledTh","RawTh","spaces","StyledTd","RawTd","StyledTr","tr","neutral0","$isMovePending","$isInvalidDropTarget","$isDragging","$isValidDropTarget","css","primary100","primary600","StyledBodyTd","AssetPreviewCell","asset","ext","mime","DocIcon","getAssetIcon","_jsx","Flex","justifyContent","alignItems","borderRadius","color","width","height","shrink","AssetRow","onAssetItemClick","isMobile","useIsMobile","formatDate","formatMessage","useIntl","isMovePending","useAssetsDndOptional","attributes","listeners","setNodeRef","isDragging","useFileDraggable","handleKeyDown","e","key","preventDefault","id","_jsxs","ref","tabIndex","role","onDragStart","onClick","onKeyDown","gap","direction","Typography","textColor","fontWeight","ellipsis","name","variant","size","formatBytes","_Fragment","createdAt","Date","dateStyle","updatedAt","IconButton","label","getTranslationKey","defaultMessage","stopPropagation","More","FolderTr","FolderRow","folder","navigateToFolder","useFolderNavigation","draggable","setDragRef","droppable","setDropRef","showValidDropHighlight","showInvalidDropCursor","useFolderDraggableDroppable","node","FolderIcon","AssetsTable","assets","folders","visibleHeaders","TABLE_HEADERS","filter","h","totalRows","length","colCount","rowCount","RawTr","map","header","tableHeaderLabel","isVisuallyHidden","VisuallyHidden","RawTbody","colSpan"],"mappings":"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"}
1
+ {"version":3,"file":"AssetsTable.mjs","sources":["../../../../../../admin/src/future/pages/Assets/components/AssetsTable.tsx"],"sourcesContent":["import { useIsMobile } from '@strapi/admin/strapi-admin';\nimport {\n Flex,\n IconButton,\n RawTable,\n RawTbody,\n RawTd,\n RawTh,\n RawThead,\n RawTr,\n Typography,\n VisuallyHidden,\n} from '@strapi/design-system';\nimport { Folder as FolderIcon, More } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled, css } from 'styled-components';\n\nimport { formatBytes } from '../../../utils/files';\nimport { getAssetIcon } from '../../../utils/getAssetIcon';\nimport { getTranslationKey } from '../../../utils/translations';\nimport { TABLE_HEADERS } from '../constants';\nimport { useFolderNavigation } from '../hooks/useFolderNavigation';\n\nimport { useAssetsDndOptional } from './Dnd/AssetsDndProvider';\nimport { useFileDraggable, useFolderDraggableDroppable } from './Dnd/useAssetDnd';\n\nimport type { File } from '../../../../../../shared/contracts/files';\nimport type { Folder } from '../../../../../../shared/contracts/folders';\n\nconst StyledTable = styled(RawTable)`\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n border: 1px solid ${({ theme }) => theme.colors.neutral150};\n border-radius: 4px;\n overflow: hidden;\n`;\n\nconst StyledThead = styled(RawThead)`\n background: ${({ theme }) => theme.colors.neutral100};\n\n tr {\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};\n }\n`;\n\nconst StyledTh = styled(RawTh)`\n height: 40px;\n padding: 0 ${({ theme }) => theme.spaces[4]};\n text-align: left;\n`;\n\nconst StyledTd = styled(RawTd)`\n padding: 0 ${({ theme }) => theme.spaces[4]};\n border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};\n`;\n\nconst StyledTr = styled.tr<{\n $isDragging?: boolean;\n $isMovePending?: boolean;\n $isValidDropTarget?: boolean;\n $isInvalidDropTarget?: boolean;\n}>`\n height: 48px;\n background: ${({ theme }) => theme.colors.neutral0};\n cursor: ${({ $isMovePending, $isInvalidDropTarget }) => {\n if ($isMovePending) {\n return 'wait';\n }\n\n return $isInvalidDropTarget ? 'not-allowed' : 'pointer';\n }};\n opacity: ${({ $isDragging }) => ($isDragging ? 0.4 : 1)};\n pointer-events: ${({ $isMovePending }) => ($isMovePending ? 'none' : 'auto')};\n\n ${({ $isValidDropTarget, theme }) =>\n $isValidDropTarget &&\n css`\n background: ${theme.colors.primary100};\n outline: 1px dashed ${theme.colors.primary600};\n outline-offset: -1px;\n `}\n\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n\n &:focus-visible {\n outline: 2px solid ${({ theme }) => theme.colors.primary600};\n outline-offset: -2px;\n }\n\n &:last-child {\n ${StyledTd} {\n border-bottom: 0;\n }\n }\n`;\n\ninterface AssetPreviewCellProps {\n asset: File;\n}\n\nconst AssetPreviewCell = ({ asset }: AssetPreviewCellProps) => {\n const { ext, mime } = asset;\n\n const DocIcon = getAssetIcon(mime, ext);\n\n return (\n <Flex\n justifyContent=\"center\"\n alignItems=\"center\"\n borderRadius=\"4px\"\n color=\"neutral500\"\n width=\"3.2rem\"\n height=\"3.2rem\"\n shrink={0}\n >\n <DocIcon width={20} height={20} />\n </Flex>\n );\n};\n\ninterface AssetRowProps {\n asset: File;\n onAssetItemClick: (assetId: number) => void;\n}\n\nconst AssetRow = ({ asset, onAssetItemClick }: AssetRowProps) => {\n const isMobile = useIsMobile();\n const { formatDate, formatMessage } = useIntl();\n const { isMovePending } = useAssetsDndOptional() ?? { isMovePending: false };\n const { attributes, listeners, setNodeRef, isDragging } = useFileDraggable(asset);\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onAssetItemClick(asset.id);\n }\n };\n\n return (\n <StyledTr\n ref={setNodeRef}\n {...attributes}\n {...listeners}\n $isDragging={isDragging}\n $isMovePending={isMovePending}\n tabIndex={0}\n role=\"row\"\n onDragStart={(e) => e.preventDefault()}\n onClick={() => onAssetItemClick(asset.id)}\n onKeyDown={handleKeyDown}\n >\n <StyledTd>\n <Flex gap={3} alignItems=\"center\">\n <AssetPreviewCell asset={asset} />\n <Flex direction=\"column\" alignItems=\"flex-start\">\n <Typography textColor=\"neutral800\" fontWeight=\"semiBold\" ellipsis>\n {asset.name}\n </Typography>\n {isMobile && (\n <Typography textColor=\"neutral600\" variant=\"pi\">\n {asset.size ? formatBytes(asset.size, 1) : '-'}\n </Typography>\n )}\n </Flex>\n </Flex>\n </StyledTd>\n {!isMobile && (\n <>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {asset.createdAt ? formatDate(new Date(asset.createdAt), { dateStyle: 'long' }) : '-'}\n </Typography>\n </StyledTd>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {asset.updatedAt ? formatDate(new Date(asset.updatedAt), { dateStyle: 'long' }) : '-'}\n </Typography>\n </StyledTd>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {asset.size ? formatBytes(asset.size, 1) : '-'}\n </Typography>\n </StyledTd>\n </>\n )}\n <StyledTd>\n <Flex justifyContent=\"flex-end\">\n <IconButton\n label={formatMessage({\n id: getTranslationKey('control-card.more-actions'),\n defaultMessage: 'More actions',\n })}\n variant=\"ghost\"\n onClick={(e: React.MouseEvent) => e.stopPropagation()}\n >\n <More />\n </IconButton>\n </Flex>\n </StyledTd>\n </StyledTr>\n );\n};\n\nconst FolderTr = styled(StyledTr)`\n &:hover {\n background: ${({ theme }) => theme.colors.primary100};\n }\n`;\n\ninterface FolderRowProps {\n folder: Folder;\n}\n\nconst FolderRow = ({ folder }: FolderRowProps) => {\n const isMobile = useIsMobile();\n const { formatDate, formatMessage } = useIntl();\n const { navigateToFolder } = useFolderNavigation();\n const { isMovePending } = useAssetsDndOptional() ?? { isMovePending: false };\n const {\n draggable: { attributes, listeners, setNodeRef: setDragRef, isDragging },\n droppable: { setNodeRef: setDropRef },\n showValidDropHighlight,\n showInvalidDropCursor,\n } = useFolderDraggableDroppable(folder);\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateToFolder(folder);\n }\n };\n\n return (\n <FolderTr\n ref={(node) => {\n setDragRef(node);\n setDropRef(node);\n }}\n {...attributes}\n {...listeners}\n $isDragging={isDragging}\n $isMovePending={isMovePending}\n $isValidDropTarget={showValidDropHighlight}\n $isInvalidDropTarget={showInvalidDropCursor}\n tabIndex={0}\n role=\"row\"\n onDragStart={(e) => e.preventDefault()}\n onClick={() => navigateToFolder(folder)}\n onKeyDown={handleKeyDown}\n >\n <StyledTd>\n <Flex gap={3} alignItems=\"center\">\n <Flex\n justifyContent=\"center\"\n alignItems=\"center\"\n borderRadius=\"4px\"\n color=\"neutral600\"\n width=\"3.2rem\"\n height=\"3.2rem\"\n shrink={0}\n >\n <FolderIcon width={20} height={20} />\n </Flex>\n <Typography textColor=\"neutral800\" fontWeight=\"semiBold\" ellipsis>\n {folder.name}\n </Typography>\n </Flex>\n </StyledTd>\n {!isMobile && (\n <>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {folder.createdAt\n ? formatDate(new Date(folder.createdAt), { dateStyle: 'long' })\n : '-'}\n </Typography>\n </StyledTd>\n <StyledTd>\n <Typography textColor=\"neutral600\">\n {folder.updatedAt\n ? formatDate(new Date(folder.updatedAt), { dateStyle: 'long' })\n : '-'}\n </Typography>\n </StyledTd>\n <StyledTd>\n <Typography textColor=\"neutral600\">-</Typography>\n </StyledTd>\n </>\n )}\n <StyledTd>\n <Flex justifyContent=\"flex-end\">\n <IconButton\n label={formatMessage({\n id: getTranslationKey('control-card.more-actions'),\n defaultMessage: 'More actions',\n })}\n variant=\"ghost\"\n onClick={(e: React.MouseEvent) => e.stopPropagation()}\n >\n <More />\n </IconButton>\n </Flex>\n </StyledTd>\n </FolderTr>\n );\n};\n\ninterface AssetsTableProps {\n assets: File[];\n folders?: Folder[];\n onAssetItemClick: (assetId: number) => void;\n}\n\nexport const AssetsTable = ({ assets, folders = [], onAssetItemClick }: AssetsTableProps) => {\n const isMobile = useIsMobile();\n const { formatMessage } = useIntl();\n\n const visibleHeaders = isMobile\n ? TABLE_HEADERS.filter((h) => h.name === 'name' || h.name === 'actions')\n : TABLE_HEADERS;\n\n const totalRows = folders.length + assets.length;\n\n // The empty state is owned by the page (`AssetsView` renders `EmptyState`) — an\n // empty table renders nothing at all, not headers over an empty body.\n if (totalRows === 0) {\n return null;\n }\n\n return (\n <StyledTable colCount={visibleHeaders.length} rowCount={totalRows + 1}>\n <StyledThead>\n <RawTr>\n {visibleHeaders.map((header) => {\n const tableHeaderLabel = formatMessage(header.label);\n const isVisuallyHidden = 'isVisuallyHidden' in header && header.isVisuallyHidden;\n\n if (isVisuallyHidden) {\n return (\n <StyledTh key={header.name}>\n <VisuallyHidden>\n {formatMessage({\n id: getTranslationKey('table.header.actions'),\n defaultMessage: 'actions',\n })}\n </VisuallyHidden>\n </StyledTh>\n );\n }\n\n return (\n <StyledTh key={header.name}>\n <Typography textColor=\"neutral600\" variant=\"sigma\">\n {tableHeaderLabel}\n </Typography>\n </StyledTh>\n );\n })}\n </RawTr>\n </StyledThead>\n <RawTbody>\n {folders.map((folder) => (\n <FolderRow key={`folder-${folder.id}`} folder={folder} />\n ))}\n {assets.map((asset) => (\n <AssetRow key={asset.id} asset={asset} onAssetItemClick={onAssetItemClick} />\n ))}\n </RawTbody>\n </StyledTable>\n );\n};\n"],"names":["StyledTable","styled","RawTable","theme","colors","neutral150","StyledThead","RawThead","neutral100","StyledTh","RawTh","spaces","StyledTd","RawTd","StyledTr","tr","neutral0","$isMovePending","$isInvalidDropTarget","$isDragging","$isValidDropTarget","css","primary100","primary600","AssetPreviewCell","asset","ext","mime","DocIcon","getAssetIcon","_jsx","Flex","justifyContent","alignItems","borderRadius","color","width","height","shrink","AssetRow","onAssetItemClick","isMobile","useIsMobile","formatDate","formatMessage","useIntl","isMovePending","useAssetsDndOptional","attributes","listeners","setNodeRef","isDragging","useFileDraggable","handleKeyDown","e","key","preventDefault","id","_jsxs","ref","tabIndex","role","onDragStart","onClick","onKeyDown","gap","direction","Typography","textColor","fontWeight","ellipsis","name","variant","size","formatBytes","_Fragment","createdAt","Date","dateStyle","updatedAt","IconButton","label","getTranslationKey","defaultMessage","stopPropagation","More","FolderTr","FolderRow","folder","navigateToFolder","useFolderNavigation","draggable","setDragRef","droppable","setDropRef","showValidDropHighlight","showInvalidDropCursor","useFolderDraggableDroppable","node","FolderIcon","AssetsTable","assets","folders","visibleHeaders","TABLE_HEADERS","filter","h","totalRows","length","colCount","rowCount","RawTr","map","header","tableHeaderLabel","isVisuallyHidden","VisuallyHidden","RawTbody"],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var designSystem = require('@strapi/design-system');
5
+ var symbols = require('@strapi/icons/symbols');
6
+ var reactIntl = require('react-intl');
7
+ var translations = require('../../../utils/translations.js');
8
+
9
+ /**
10
+ * Empty state for the assets list (both views) when the current folder holds
11
+ * no assets and no folders. The "Add assets" button opens the same file picker
12
+ * as New > File upload; drag-and-drop upload keeps working since the page-wide
13
+ * drop zone wraps this component.
14
+ */ const EmptyState = ({ onAddAssets })=>{
15
+ const { formatMessage } = reactIntl.useIntl();
16
+ return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
17
+ direction: "column",
18
+ alignItems: "center",
19
+ gap: 6,
20
+ padding: 11,
21
+ children: [
22
+ /*#__PURE__*/ jsxRuntime.jsx(symbols.EmptyDocuments, {
23
+ width: "16rem",
24
+ height: "8.8rem"
25
+ }),
26
+ /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
27
+ direction: "column",
28
+ alignItems: "center",
29
+ gap: 2,
30
+ textAlign: "center",
31
+ children: [
32
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
33
+ variant: "delta",
34
+ tag: "p",
35
+ fontWeight: "bold",
36
+ textColor: "neutral800",
37
+ children: formatMessage({
38
+ id: translations.getTranslationKey('list.empty.title'),
39
+ defaultMessage: 'No assets yet'
40
+ })
41
+ }),
42
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
43
+ textColor: "neutral600",
44
+ children: formatMessage({
45
+ id: translations.getTranslationKey('list.empty.description'),
46
+ defaultMessage: 'Get started by uploading assets or creating a folder.'
47
+ })
48
+ })
49
+ ]
50
+ }),
51
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
52
+ onClick: onAddAssets,
53
+ children: formatMessage({
54
+ id: translations.getTranslationKey('list.empty.add-assets'),
55
+ defaultMessage: 'Add assets'
56
+ })
57
+ })
58
+ ]
59
+ });
60
+ };
61
+
62
+ exports.EmptyState = EmptyState;
63
+ //# sourceMappingURL=EmptyState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.js","sources":["../../../../../../admin/src/future/pages/Assets/components/EmptyState.tsx"],"sourcesContent":["import { Button, Flex, Typography } from '@strapi/design-system';\nimport { EmptyDocuments } from '@strapi/icons/symbols';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslationKey } from '../../../utils/translations';\n\ninterface EmptyStateProps {\n onAddAssets: () => void;\n}\n\n/**\n * Empty state for the assets list (both views) when the current folder holds\n * no assets and no folders. The \"Add assets\" button opens the same file picker\n * as New > File upload; drag-and-drop upload keeps working since the page-wide\n * drop zone wraps this component.\n */\nexport const EmptyState = ({ onAddAssets }: EmptyStateProps) => {\n const { formatMessage } = useIntl();\n\n return (\n <Flex direction=\"column\" alignItems=\"center\" gap={6} padding={11}>\n <EmptyDocuments width=\"16rem\" height=\"8.8rem\" />\n <Flex direction=\"column\" alignItems=\"center\" gap={2} textAlign=\"center\">\n <Typography variant=\"delta\" tag=\"p\" fontWeight=\"bold\" textColor=\"neutral800\">\n {formatMessage({\n id: getTranslationKey('list.empty.title'),\n defaultMessage: 'No assets yet',\n })}\n </Typography>\n <Typography textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('list.empty.description'),\n defaultMessage: 'Get started by uploading assets or creating a folder.',\n })}\n </Typography>\n </Flex>\n <Button onClick={onAddAssets}>\n {formatMessage({\n id: getTranslationKey('list.empty.add-assets'),\n defaultMessage: 'Add assets',\n })}\n </Button>\n </Flex>\n );\n};\n"],"names":["EmptyState","onAddAssets","formatMessage","useIntl","_jsxs","Flex","direction","alignItems","gap","padding","_jsx","EmptyDocuments","width","height","textAlign","Typography","variant","tag","fontWeight","textColor","id","getTranslationKey","defaultMessage","Button","onClick"],"mappings":";;;;;;;;AAUA;;;;;AAKC,IACM,MAAMA,UAAAA,GAAa,CAAC,EAAEC,WAAW,EAAmB,GAAA;IACzD,MAAM,EAAEC,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;AAE1B,IAAA,qBACEC,eAAA,CAACC,iBAAAA,EAAAA;QAAKC,SAAAA,EAAU,QAAA;QAASC,UAAAA,EAAW,QAAA;QAASC,GAAAA,EAAK,CAAA;QAAGC,OAAAA,EAAS,EAAA;;0BAC5DC,cAAA,CAACC,sBAAAA,EAAAA;gBAAeC,KAAAA,EAAM,OAAA;gBAAQC,MAAAA,EAAO;;0BACrCT,eAAA,CAACC,iBAAAA,EAAAA;gBAAKC,SAAAA,EAAU,QAAA;gBAASC,UAAAA,EAAW,QAAA;gBAASC,GAAAA,EAAK,CAAA;gBAAGM,SAAAA,EAAU,QAAA;;kCAC7DJ,cAAA,CAACK,uBAAAA,EAAAA;wBAAWC,OAAAA,EAAQ,OAAA;wBAAQC,GAAAA,EAAI,GAAA;wBAAIC,UAAAA,EAAW,MAAA;wBAAOC,SAAAA,EAAU,YAAA;kCAC7DjB,aAAAA,CAAc;AACbkB,4BAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,kBAAA,CAAA;4BACtBC,cAAAA,EAAgB;AAClB,yBAAA;;kCAEFZ,cAAA,CAACK,uBAAAA,EAAAA;wBAAWI,SAAAA,EAAU,YAAA;kCACnBjB,aAAAA,CAAc;AACbkB,4BAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,wBAAA,CAAA;4BACtBC,cAAAA,EAAgB;AAClB,yBAAA;;;;0BAGJZ,cAAA,CAACa,mBAAAA,EAAAA;gBAAOC,OAAAA,EAASvB,WAAAA;0BACdC,aAAAA,CAAc;AACbkB,oBAAAA,EAAAA,EAAIC,8BAAAA,CAAkB,uBAAA,CAAA;oBACtBC,cAAAA,EAAgB;AAClB,iBAAA;;;;AAIR;;;;"}
@@ -0,0 +1,61 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { Flex, Typography, Button } from '@strapi/design-system';
3
+ import { EmptyDocuments } from '@strapi/icons/symbols';
4
+ import { useIntl } from 'react-intl';
5
+ import { getTranslationKey } from '../../../utils/translations.mjs';
6
+
7
+ /**
8
+ * Empty state for the assets list (both views) when the current folder holds
9
+ * no assets and no folders. The "Add assets" button opens the same file picker
10
+ * as New > File upload; drag-and-drop upload keeps working since the page-wide
11
+ * drop zone wraps this component.
12
+ */ const EmptyState = ({ onAddAssets })=>{
13
+ const { formatMessage } = useIntl();
14
+ return /*#__PURE__*/ jsxs(Flex, {
15
+ direction: "column",
16
+ alignItems: "center",
17
+ gap: 6,
18
+ padding: 11,
19
+ children: [
20
+ /*#__PURE__*/ jsx(EmptyDocuments, {
21
+ width: "16rem",
22
+ height: "8.8rem"
23
+ }),
24
+ /*#__PURE__*/ jsxs(Flex, {
25
+ direction: "column",
26
+ alignItems: "center",
27
+ gap: 2,
28
+ textAlign: "center",
29
+ children: [
30
+ /*#__PURE__*/ jsx(Typography, {
31
+ variant: "delta",
32
+ tag: "p",
33
+ fontWeight: "bold",
34
+ textColor: "neutral800",
35
+ children: formatMessage({
36
+ id: getTranslationKey('list.empty.title'),
37
+ defaultMessage: 'No assets yet'
38
+ })
39
+ }),
40
+ /*#__PURE__*/ jsx(Typography, {
41
+ textColor: "neutral600",
42
+ children: formatMessage({
43
+ id: getTranslationKey('list.empty.description'),
44
+ defaultMessage: 'Get started by uploading assets or creating a folder.'
45
+ })
46
+ })
47
+ ]
48
+ }),
49
+ /*#__PURE__*/ jsx(Button, {
50
+ onClick: onAddAssets,
51
+ children: formatMessage({
52
+ id: getTranslationKey('list.empty.add-assets'),
53
+ defaultMessage: 'Add assets'
54
+ })
55
+ })
56
+ ]
57
+ });
58
+ };
59
+
60
+ export { EmptyState };
61
+ //# sourceMappingURL=EmptyState.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.mjs","sources":["../../../../../../admin/src/future/pages/Assets/components/EmptyState.tsx"],"sourcesContent":["import { Button, Flex, Typography } from '@strapi/design-system';\nimport { EmptyDocuments } from '@strapi/icons/symbols';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslationKey } from '../../../utils/translations';\n\ninterface EmptyStateProps {\n onAddAssets: () => void;\n}\n\n/**\n * Empty state for the assets list (both views) when the current folder holds\n * no assets and no folders. The \"Add assets\" button opens the same file picker\n * as New > File upload; drag-and-drop upload keeps working since the page-wide\n * drop zone wraps this component.\n */\nexport const EmptyState = ({ onAddAssets }: EmptyStateProps) => {\n const { formatMessage } = useIntl();\n\n return (\n <Flex direction=\"column\" alignItems=\"center\" gap={6} padding={11}>\n <EmptyDocuments width=\"16rem\" height=\"8.8rem\" />\n <Flex direction=\"column\" alignItems=\"center\" gap={2} textAlign=\"center\">\n <Typography variant=\"delta\" tag=\"p\" fontWeight=\"bold\" textColor=\"neutral800\">\n {formatMessage({\n id: getTranslationKey('list.empty.title'),\n defaultMessage: 'No assets yet',\n })}\n </Typography>\n <Typography textColor=\"neutral600\">\n {formatMessage({\n id: getTranslationKey('list.empty.description'),\n defaultMessage: 'Get started by uploading assets or creating a folder.',\n })}\n </Typography>\n </Flex>\n <Button onClick={onAddAssets}>\n {formatMessage({\n id: getTranslationKey('list.empty.add-assets'),\n defaultMessage: 'Add assets',\n })}\n </Button>\n </Flex>\n );\n};\n"],"names":["EmptyState","onAddAssets","formatMessage","useIntl","_jsxs","Flex","direction","alignItems","gap","padding","_jsx","EmptyDocuments","width","height","textAlign","Typography","variant","tag","fontWeight","textColor","id","getTranslationKey","defaultMessage","Button","onClick"],"mappings":";;;;;;AAUA;;;;;AAKC,IACM,MAAMA,UAAAA,GAAa,CAAC,EAAEC,WAAW,EAAmB,GAAA;IACzD,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAE1B,IAAA,qBACEC,IAAA,CAACC,IAAAA,EAAAA;QAAKC,SAAAA,EAAU,QAAA;QAASC,UAAAA,EAAW,QAAA;QAASC,GAAAA,EAAK,CAAA;QAAGC,OAAAA,EAAS,EAAA;;0BAC5DC,GAAA,CAACC,cAAAA,EAAAA;gBAAeC,KAAAA,EAAM,OAAA;gBAAQC,MAAAA,EAAO;;0BACrCT,IAAA,CAACC,IAAAA,EAAAA;gBAAKC,SAAAA,EAAU,QAAA;gBAASC,UAAAA,EAAW,QAAA;gBAASC,GAAAA,EAAK,CAAA;gBAAGM,SAAAA,EAAU,QAAA;;kCAC7DJ,GAAA,CAACK,UAAAA,EAAAA;wBAAWC,OAAAA,EAAQ,OAAA;wBAAQC,GAAAA,EAAI,GAAA;wBAAIC,UAAAA,EAAW,MAAA;wBAAOC,SAAAA,EAAU,YAAA;kCAC7DjB,aAAAA,CAAc;AACbkB,4BAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,kBAAA,CAAA;4BACtBC,cAAAA,EAAgB;AAClB,yBAAA;;kCAEFZ,GAAA,CAACK,UAAAA,EAAAA;wBAAWI,SAAAA,EAAU,YAAA;kCACnBjB,aAAAA,CAAc;AACbkB,4BAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,wBAAA,CAAA;4BACtBC,cAAAA,EAAgB;AAClB,yBAAA;;;;0BAGJZ,GAAA,CAACa,MAAAA,EAAAA;gBAAOC,OAAAA,EAASvB,WAAAA;0BACdC,aAAAA,CAAc;AACbkB,oBAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,uBAAA,CAAA;oBACtBC,cAAAA,EAAgB;AAClB,iBAAA;;;;AAIR;;;;"}
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var strapiAdmin = require('@strapi/admin/strapi-admin');
4
+
3
5
  /**
4
6
  * Thrown when an upload is aborted via its `AbortSignal`.
5
7
  * Distinct from {@link UploadFileError} so callers can tell cancellation apart
@@ -31,10 +33,11 @@
31
33
  * @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.
32
34
  * @param signal - Aborts the in-flight request when triggered.
33
35
  * @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.
34
- * @returns The parsed, signed `File` on a 2xx response.
36
+ * @returns The parsed response body on a 2xx response — a signed `File` by default,
37
+ * or `T` when the endpoint returns a different shape (e.g. an array of files).
35
38
  * @throws {UploadAbortedError} When the signal aborts.
36
39
  * @throws {UploadFileError} On a non-2xx response or network error.
37
- */ const uploadFileViaXHR = (url, token, formData, signal, onProgress)=>{
40
+ */ const sendUploadViaXHR = (url, token, formData, signal, onProgress)=>{
38
41
  return new Promise((resolve, reject)=>{
39
42
  if (signal.aborted) {
40
43
  reject(new UploadAbortedError());
@@ -85,6 +88,24 @@
85
88
  xhr.send(formData);
86
89
  });
87
90
  };
91
+ const uploadFileViaXHR = async (url, token, formData, signal, onProgress)=>{
92
+ try {
93
+ return await sendUploadViaXHR(url, token, formData, signal, onProgress);
94
+ } catch (error) {
95
+ if (!(error instanceof UploadFileError) || error.status !== 401) {
96
+ throw error;
97
+ }
98
+ try {
99
+ const refreshedToken = await strapiAdmin.attemptTokenRefresh();
100
+ return await sendUploadViaXHR(url, refreshedToken, formData, signal, onProgress);
101
+ } catch (refreshError) {
102
+ if (refreshError instanceof UploadFileError) {
103
+ throw refreshError;
104
+ }
105
+ throw error;
106
+ }
107
+ }
108
+ };
88
109
 
89
110
  exports.UploadAbortedError = UploadAbortedError;
90
111
  exports.UploadFileError = UploadFileError;
@@ -1 +1 @@
1
- {"version":3,"file":"uploadFileViaXHR.js","sources":["../../../../admin/src/future/services/uploadFileViaXHR.ts"],"sourcesContent":["import type { File } from '../../../../shared/contracts/files';\n\n/**\n * Thrown when an upload is aborted via its `AbortSignal`.\n * Distinct from {@link UploadFileError} so callers can tell cancellation apart\n * from a genuine failure.\n */\nexport class UploadAbortedError extends Error {\n constructor(message = 'Upload aborted') {\n super(message);\n this.name = 'UploadAbortedError';\n }\n}\n\n/**\n * Thrown when an upload fails (non-2xx response, network error, or unparseable body).\n */\nexport class UploadFileError extends Error {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = 'UploadFileError';\n this.status = status;\n }\n}\n\nexport type UploadProgressCallback = (bytes: number, total: number) => void;\n\n/**\n * Uploads a single file via `XMLHttpRequest`, exposing real byte-level upload\n * progress through {@link XMLHttpRequest.upload}'s `progress` event.\n *\n * This is the only place raw XHR lives. `fetch()` is intentionally avoided here\n * because it does not surface upload progress.\n *\n * @param url - The full endpoint URL to POST to.\n * @param token - Admin auth token; the `Authorization` header is only set when present.\n * @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.\n * @param signal - Aborts the in-flight request when triggered.\n * @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.\n * @returns The parsed, signed `File` on a 2xx response.\n * @throws {UploadAbortedError} When the signal aborts.\n * @throws {UploadFileError} On a non-2xx response or network error.\n */\nexport const uploadFileViaXHR = (\n url: string,\n token: string | null | undefined,\n formData: FormData,\n signal: AbortSignal,\n onProgress?: UploadProgressCallback\n): Promise<File> => {\n return new Promise<File>((resolve, reject) => {\n if (signal.aborted) {\n reject(new UploadAbortedError());\n return;\n }\n\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n\n if (token) {\n xhr.setRequestHeader('Authorization', `Bearer ${token}`);\n }\n\n const handleAbort = () => xhr.abort();\n signal.addEventListener('abort', handleAbort);\n\n const cleanup = () => signal.removeEventListener('abort', handleAbort);\n\n if (onProgress) {\n xhr.upload.onprogress = (event: ProgressEvent) => {\n if (event.lengthComputable) {\n onProgress(event.loaded, event.total);\n }\n };\n }\n\n xhr.onload = () => {\n cleanup();\n\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText) as File);\n } catch {\n reject(new UploadFileError('Failed to parse upload response'));\n }\n return;\n }\n\n let message = `Upload failed with status ${xhr.status}`;\n try {\n const parsed = JSON.parse(xhr.responseText);\n message = parsed?.error?.message || parsed?.message || message;\n } catch {\n // Keep the default status-based message.\n }\n reject(new UploadFileError(message, xhr.status));\n };\n\n xhr.onerror = () => {\n cleanup();\n reject(new UploadFileError('Network error occurred'));\n };\n\n xhr.onabort = () => {\n cleanup();\n reject(new UploadAbortedError());\n };\n\n xhr.send(formData);\n });\n};\n"],"names":["UploadAbortedError","Error","message","name","UploadFileError","status","uploadFileViaXHR","url","token","formData","signal","onProgress","Promise","resolve","reject","aborted","xhr","XMLHttpRequest","open","setRequestHeader","handleAbort","abort","addEventListener","cleanup","removeEventListener","upload","onprogress","event","lengthComputable","loaded","total","onload","JSON","parse","responseText","parsed","error","onerror","onabort","send"],"mappings":"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"}
1
+ {"version":3,"file":"uploadFileViaXHR.js","sources":["../../../../admin/src/future/services/uploadFileViaXHR.ts"],"sourcesContent":["import { attemptTokenRefresh } from '@strapi/admin/strapi-admin';\n\nimport type { File } from '../../../../shared/contracts/files';\n\n/**\n * Thrown when an upload is aborted via its `AbortSignal`.\n * Distinct from {@link UploadFileError} so callers can tell cancellation apart\n * from a genuine failure.\n */\nexport class UploadAbortedError extends Error {\n constructor(message = 'Upload aborted') {\n super(message);\n this.name = 'UploadAbortedError';\n }\n}\n\n/**\n * Thrown when an upload fails (non-2xx response, network error, or unparseable body).\n */\nexport class UploadFileError extends Error {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = 'UploadFileError';\n this.status = status;\n }\n}\n\nexport type UploadProgressCallback = (bytes: number, total: number) => void;\n\n/**\n * Uploads a single file via `XMLHttpRequest`, exposing real byte-level upload\n * progress through {@link XMLHttpRequest.upload}'s `progress` event.\n *\n * This is the only place raw XHR lives. `fetch()` is intentionally avoided here\n * because it does not surface upload progress.\n *\n * @param url - The full endpoint URL to POST to.\n * @param token - Admin auth token; the `Authorization` header is only set when present.\n * @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.\n * @param signal - Aborts the in-flight request when triggered.\n * @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.\n * @returns The parsed response body on a 2xx response — a signed `File` by default,\n * or `T` when the endpoint returns a different shape (e.g. an array of files).\n * @throws {UploadAbortedError} When the signal aborts.\n * @throws {UploadFileError} On a non-2xx response or network error.\n */\nconst sendUploadViaXHR = <T>(\n url: string,\n token: string | null | undefined,\n formData: FormData,\n signal: AbortSignal,\n onProgress?: UploadProgressCallback\n): Promise<T> => {\n return new Promise<T>((resolve, reject) => {\n if (signal.aborted) {\n reject(new UploadAbortedError());\n return;\n }\n\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n\n if (token) {\n xhr.setRequestHeader('Authorization', `Bearer ${token}`);\n }\n\n const handleAbort = () => xhr.abort();\n signal.addEventListener('abort', handleAbort);\n\n const cleanup = () => signal.removeEventListener('abort', handleAbort);\n\n if (onProgress) {\n xhr.upload.onprogress = (event: ProgressEvent) => {\n if (event.lengthComputable) {\n onProgress(event.loaded, event.total);\n }\n };\n }\n\n xhr.onload = () => {\n cleanup();\n\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText) as T);\n } catch {\n reject(new UploadFileError('Failed to parse upload response'));\n }\n return;\n }\n\n let message = `Upload failed with status ${xhr.status}`;\n try {\n const parsed = JSON.parse(xhr.responseText);\n message = parsed?.error?.message || parsed?.message || message;\n } catch {\n // Keep the default status-based message.\n }\n reject(new UploadFileError(message, xhr.status));\n };\n\n xhr.onerror = () => {\n cleanup();\n reject(new UploadFileError('Network error occurred'));\n };\n\n xhr.onabort = () => {\n cleanup();\n reject(new UploadAbortedError());\n };\n\n xhr.send(formData);\n });\n};\n\nexport const uploadFileViaXHR = async <T = File>(\n url: string,\n token: string | null | undefined,\n formData: FormData,\n signal: AbortSignal,\n onProgress?: UploadProgressCallback\n): Promise<T> => {\n try {\n return await sendUploadViaXHR<T>(url, token, formData, signal, onProgress);\n } catch (error) {\n if (!(error instanceof UploadFileError) || error.status !== 401) {\n throw error;\n }\n\n try {\n const refreshedToken = await attemptTokenRefresh();\n\n return await sendUploadViaXHR<T>(url, refreshedToken, formData, signal, onProgress);\n } catch (refreshError) {\n if (refreshError instanceof UploadFileError) {\n throw refreshError;\n }\n\n throw error;\n }\n }\n};\n"],"names":["UploadAbortedError","Error","message","name","UploadFileError","status","sendUploadViaXHR","url","token","formData","signal","onProgress","Promise","resolve","reject","aborted","xhr","XMLHttpRequest","open","setRequestHeader","handleAbort","abort","addEventListener","cleanup","removeEventListener","upload","onprogress","event","lengthComputable","loaded","total","onload","JSON","parse","responseText","parsed","error","onerror","onabort","send","uploadFileViaXHR","refreshedToken","attemptTokenRefresh","refreshError"],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ import { attemptTokenRefresh } from '@strapi/admin/strapi-admin';
2
+
1
3
  /**
2
4
  * Thrown when an upload is aborted via its `AbortSignal`.
3
5
  * Distinct from {@link UploadFileError} so callers can tell cancellation apart
@@ -29,10 +31,11 @@
29
31
  * @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.
30
32
  * @param signal - Aborts the in-flight request when triggered.
31
33
  * @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.
32
- * @returns The parsed, signed `File` on a 2xx response.
34
+ * @returns The parsed response body on a 2xx response — a signed `File` by default,
35
+ * or `T` when the endpoint returns a different shape (e.g. an array of files).
33
36
  * @throws {UploadAbortedError} When the signal aborts.
34
37
  * @throws {UploadFileError} On a non-2xx response or network error.
35
- */ const uploadFileViaXHR = (url, token, formData, signal, onProgress)=>{
38
+ */ const sendUploadViaXHR = (url, token, formData, signal, onProgress)=>{
36
39
  return new Promise((resolve, reject)=>{
37
40
  if (signal.aborted) {
38
41
  reject(new UploadAbortedError());
@@ -83,6 +86,24 @@
83
86
  xhr.send(formData);
84
87
  });
85
88
  };
89
+ const uploadFileViaXHR = async (url, token, formData, signal, onProgress)=>{
90
+ try {
91
+ return await sendUploadViaXHR(url, token, formData, signal, onProgress);
92
+ } catch (error) {
93
+ if (!(error instanceof UploadFileError) || error.status !== 401) {
94
+ throw error;
95
+ }
96
+ try {
97
+ const refreshedToken = await attemptTokenRefresh();
98
+ return await sendUploadViaXHR(url, refreshedToken, formData, signal, onProgress);
99
+ } catch (refreshError) {
100
+ if (refreshError instanceof UploadFileError) {
101
+ throw refreshError;
102
+ }
103
+ throw error;
104
+ }
105
+ }
106
+ };
86
107
 
87
108
  export { UploadAbortedError, UploadFileError, uploadFileViaXHR };
88
109
  //# sourceMappingURL=uploadFileViaXHR.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploadFileViaXHR.mjs","sources":["../../../../admin/src/future/services/uploadFileViaXHR.ts"],"sourcesContent":["import type { File } from '../../../../shared/contracts/files';\n\n/**\n * Thrown when an upload is aborted via its `AbortSignal`.\n * Distinct from {@link UploadFileError} so callers can tell cancellation apart\n * from a genuine failure.\n */\nexport class UploadAbortedError extends Error {\n constructor(message = 'Upload aborted') {\n super(message);\n this.name = 'UploadAbortedError';\n }\n}\n\n/**\n * Thrown when an upload fails (non-2xx response, network error, or unparseable body).\n */\nexport class UploadFileError extends Error {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = 'UploadFileError';\n this.status = status;\n }\n}\n\nexport type UploadProgressCallback = (bytes: number, total: number) => void;\n\n/**\n * Uploads a single file via `XMLHttpRequest`, exposing real byte-level upload\n * progress through {@link XMLHttpRequest.upload}'s `progress` event.\n *\n * This is the only place raw XHR lives. `fetch()` is intentionally avoided here\n * because it does not surface upload progress.\n *\n * @param url - The full endpoint URL to POST to.\n * @param token - Admin auth token; the `Authorization` header is only set when present.\n * @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.\n * @param signal - Aborts the in-flight request when triggered.\n * @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.\n * @returns The parsed, signed `File` on a 2xx response.\n * @throws {UploadAbortedError} When the signal aborts.\n * @throws {UploadFileError} On a non-2xx response or network error.\n */\nexport const uploadFileViaXHR = (\n url: string,\n token: string | null | undefined,\n formData: FormData,\n signal: AbortSignal,\n onProgress?: UploadProgressCallback\n): Promise<File> => {\n return new Promise<File>((resolve, reject) => {\n if (signal.aborted) {\n reject(new UploadAbortedError());\n return;\n }\n\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n\n if (token) {\n xhr.setRequestHeader('Authorization', `Bearer ${token}`);\n }\n\n const handleAbort = () => xhr.abort();\n signal.addEventListener('abort', handleAbort);\n\n const cleanup = () => signal.removeEventListener('abort', handleAbort);\n\n if (onProgress) {\n xhr.upload.onprogress = (event: ProgressEvent) => {\n if (event.lengthComputable) {\n onProgress(event.loaded, event.total);\n }\n };\n }\n\n xhr.onload = () => {\n cleanup();\n\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText) as File);\n } catch {\n reject(new UploadFileError('Failed to parse upload response'));\n }\n return;\n }\n\n let message = `Upload failed with status ${xhr.status}`;\n try {\n const parsed = JSON.parse(xhr.responseText);\n message = parsed?.error?.message || parsed?.message || message;\n } catch {\n // Keep the default status-based message.\n }\n reject(new UploadFileError(message, xhr.status));\n };\n\n xhr.onerror = () => {\n cleanup();\n reject(new UploadFileError('Network error occurred'));\n };\n\n xhr.onabort = () => {\n cleanup();\n reject(new UploadAbortedError());\n };\n\n xhr.send(formData);\n });\n};\n"],"names":["UploadAbortedError","Error","message","name","UploadFileError","status","uploadFileViaXHR","url","token","formData","signal","onProgress","Promise","resolve","reject","aborted","xhr","XMLHttpRequest","open","setRequestHeader","handleAbort","abort","addEventListener","cleanup","removeEventListener","upload","onprogress","event","lengthComputable","loaded","total","onload","JSON","parse","responseText","parsed","error","onerror","onabort","send"],"mappings":"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"}
1
+ {"version":3,"file":"uploadFileViaXHR.mjs","sources":["../../../../admin/src/future/services/uploadFileViaXHR.ts"],"sourcesContent":["import { attemptTokenRefresh } from '@strapi/admin/strapi-admin';\n\nimport type { File } from '../../../../shared/contracts/files';\n\n/**\n * Thrown when an upload is aborted via its `AbortSignal`.\n * Distinct from {@link UploadFileError} so callers can tell cancellation apart\n * from a genuine failure.\n */\nexport class UploadAbortedError extends Error {\n constructor(message = 'Upload aborted') {\n super(message);\n this.name = 'UploadAbortedError';\n }\n}\n\n/**\n * Thrown when an upload fails (non-2xx response, network error, or unparseable body).\n */\nexport class UploadFileError extends Error {\n status?: number;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = 'UploadFileError';\n this.status = status;\n }\n}\n\nexport type UploadProgressCallback = (bytes: number, total: number) => void;\n\n/**\n * Uploads a single file via `XMLHttpRequest`, exposing real byte-level upload\n * progress through {@link XMLHttpRequest.upload}'s `progress` event.\n *\n * This is the only place raw XHR lives. `fetch()` is intentionally avoided here\n * because it does not surface upload progress.\n *\n * @param url - The full endpoint URL to POST to.\n * @param token - Admin auth token; the `Authorization` header is only set when present.\n * @param formData - Prebuilt multipart body containing the single file and its `fileInfo`.\n * @param signal - Aborts the in-flight request when triggered.\n * @param onProgress - Called with `(loaded, total)` bytes as the upload progresses.\n * @returns The parsed response body on a 2xx response — a signed `File` by default,\n * or `T` when the endpoint returns a different shape (e.g. an array of files).\n * @throws {UploadAbortedError} When the signal aborts.\n * @throws {UploadFileError} On a non-2xx response or network error.\n */\nconst sendUploadViaXHR = <T>(\n url: string,\n token: string | null | undefined,\n formData: FormData,\n signal: AbortSignal,\n onProgress?: UploadProgressCallback\n): Promise<T> => {\n return new Promise<T>((resolve, reject) => {\n if (signal.aborted) {\n reject(new UploadAbortedError());\n return;\n }\n\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n\n if (token) {\n xhr.setRequestHeader('Authorization', `Bearer ${token}`);\n }\n\n const handleAbort = () => xhr.abort();\n signal.addEventListener('abort', handleAbort);\n\n const cleanup = () => signal.removeEventListener('abort', handleAbort);\n\n if (onProgress) {\n xhr.upload.onprogress = (event: ProgressEvent) => {\n if (event.lengthComputable) {\n onProgress(event.loaded, event.total);\n }\n };\n }\n\n xhr.onload = () => {\n cleanup();\n\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText) as T);\n } catch {\n reject(new UploadFileError('Failed to parse upload response'));\n }\n return;\n }\n\n let message = `Upload failed with status ${xhr.status}`;\n try {\n const parsed = JSON.parse(xhr.responseText);\n message = parsed?.error?.message || parsed?.message || message;\n } catch {\n // Keep the default status-based message.\n }\n reject(new UploadFileError(message, xhr.status));\n };\n\n xhr.onerror = () => {\n cleanup();\n reject(new UploadFileError('Network error occurred'));\n };\n\n xhr.onabort = () => {\n cleanup();\n reject(new UploadAbortedError());\n };\n\n xhr.send(formData);\n });\n};\n\nexport const uploadFileViaXHR = async <T = File>(\n url: string,\n token: string | null | undefined,\n formData: FormData,\n signal: AbortSignal,\n onProgress?: UploadProgressCallback\n): Promise<T> => {\n try {\n return await sendUploadViaXHR<T>(url, token, formData, signal, onProgress);\n } catch (error) {\n if (!(error instanceof UploadFileError) || error.status !== 401) {\n throw error;\n }\n\n try {\n const refreshedToken = await attemptTokenRefresh();\n\n return await sendUploadViaXHR<T>(url, refreshedToken, formData, signal, onProgress);\n } catch (refreshError) {\n if (refreshError instanceof UploadFileError) {\n throw refreshError;\n }\n\n throw error;\n }\n }\n};\n"],"names":["UploadAbortedError","Error","message","name","UploadFileError","status","sendUploadViaXHR","url","token","formData","signal","onProgress","Promise","resolve","reject","aborted","xhr","XMLHttpRequest","open","setRequestHeader","handleAbort","abort","addEventListener","cleanup","removeEventListener","upload","onprogress","event","lengthComputable","loaded","total","onload","JSON","parse","responseText","parsed","error","onerror","onabort","send","uploadFileViaXHR","refreshedToken","attemptTokenRefresh","refreshError"],"mappings":";;AAIA;;;;IAKO,MAAMA,kBAAAA,SAA2BC,KAAAA,CAAAA;IACtC,WAAA,CAAYC,OAAAA,GAAU,gBAAgB,CAAE;AACtC,QAAA,KAAK,CAACA,OAAAA,CAAAA;QACN,IAAI,CAACC,IAAI,GAAG,oBAAA;AACd,IAAA;AACF;AAEA;;IAGO,MAAMC,eAAAA,SAAwBH,KAAAA,CAAAA;IAGnC,WAAA,CAAYC,OAAe,EAAEG,MAAe,CAAE;AAC5C,QAAA,KAAK,CAACH,OAAAA,CAAAA;QACN,IAAI,CAACC,IAAI,GAAG,iBAAA;QACZ,IAAI,CAACE,MAAM,GAAGA,MAAAA;AAChB,IAAA;AACF;AAIA;;;;;;;;;;;;;;;;AAgBC,IACD,MAAMC,gBAAAA,GAAmB,CACvBC,GAAAA,EACAC,KAAAA,EACAC,UACAC,MAAAA,EACAC,UAAAA,GAAAA;IAEA,OAAO,IAAIC,OAAAA,CAAW,CAACC,OAAAA,EAASC,MAAAA,GAAAA;QAC9B,IAAIJ,MAAAA,CAAOK,OAAO,EAAE;AAClBD,YAAAA,MAAAA,CAAO,IAAId,kBAAAA,EAAAA,CAAAA;AACX,YAAA;AACF,QAAA;AAEA,QAAA,MAAMgB,MAAM,IAAIC,cAAAA,EAAAA;QAChBD,GAAAA,CAAIE,IAAI,CAAC,MAAA,EAAQX,GAAAA,CAAAA;AAEjB,QAAA,IAAIC,KAAAA,EAAO;AACTQ,YAAAA,GAAAA,CAAIG,gBAAgB,CAAC,eAAA,EAAiB,CAAC,OAAO,EAAEX,KAAAA,CAAAA,CAAO,CAAA;AACzD,QAAA;QAEA,MAAMY,WAAAA,GAAc,IAAMJ,GAAAA,CAAIK,KAAK,EAAA;QACnCX,MAAAA,CAAOY,gBAAgB,CAAC,OAAA,EAASF,WAAAA,CAAAA;AAEjC,QAAA,MAAMG,OAAAA,GAAU,IAAMb,MAAAA,CAAOc,mBAAmB,CAAC,OAAA,EAASJ,WAAAA,CAAAA;AAE1D,QAAA,IAAIT,UAAAA,EAAY;AACdK,YAAAA,GAAAA,CAAIS,MAAM,CAACC,UAAU,GAAG,CAACC,KAAAA,GAAAA;gBACvB,IAAIA,KAAAA,CAAMC,gBAAgB,EAAE;AAC1BjB,oBAAAA,UAAAA,CAAWgB,KAAAA,CAAME,MAAM,EAAEF,KAAAA,CAAMG,KAAK,CAAA;AACtC,gBAAA;AACF,YAAA,CAAA;AACF,QAAA;AAEAd,QAAAA,GAAAA,CAAIe,MAAM,GAAG,IAAA;AACXR,YAAAA,OAAAA,EAAAA;AAEA,YAAA,IAAIP,IAAIX,MAAM,IAAI,OAAOW,GAAAA,CAAIX,MAAM,GAAG,GAAA,EAAK;gBACzC,IAAI;AACFQ,oBAAAA,OAAAA,CAAQmB,IAAAA,CAAKC,KAAK,CAACjB,GAAAA,CAAIkB,YAAY,CAAA,CAAA;AACrC,gBAAA,CAAA,CAAE,OAAM;AACNpB,oBAAAA,MAAAA,CAAO,IAAIV,eAAAA,CAAgB,iCAAA,CAAA,CAAA;AAC7B,gBAAA;AACA,gBAAA;AACF,YAAA;AAEA,YAAA,IAAIF,UAAU,CAAC,0BAA0B,EAAEc,GAAAA,CAAIX,MAAM,CAAA,CAAE;YACvD,IAAI;AACF,gBAAA,MAAM8B,MAAAA,GAASH,IAAAA,CAAKC,KAAK,CAACjB,IAAIkB,YAAY,CAAA;AAC1ChC,gBAAAA,OAAAA,GAAUiC,MAAAA,EAAQC,KAAAA,EAAOlC,OAAAA,IAAWiC,MAAAA,EAAQjC,OAAAA,IAAWA,OAAAA;AACzD,YAAA,CAAA,CAAE,OAAM;;AAER,YAAA;AACAY,YAAAA,MAAAA,CAAO,IAAIV,eAAAA,CAAgBF,OAAAA,EAASc,GAAAA,CAAIX,MAAM,CAAA,CAAA;AAChD,QAAA,CAAA;AAEAW,QAAAA,GAAAA,CAAIqB,OAAO,GAAG,IAAA;AACZd,YAAAA,OAAAA,EAAAA;AACAT,YAAAA,MAAAA,CAAO,IAAIV,eAAAA,CAAgB,wBAAA,CAAA,CAAA;AAC7B,QAAA,CAAA;AAEAY,QAAAA,GAAAA,CAAIsB,OAAO,GAAG,IAAA;AACZf,YAAAA,OAAAA,EAAAA;AACAT,YAAAA,MAAAA,CAAO,IAAId,kBAAAA,EAAAA,CAAAA;AACb,QAAA,CAAA;AAEAgB,QAAAA,GAAAA,CAAIuB,IAAI,CAAC9B,QAAAA,CAAAA;AACX,IAAA,CAAA,CAAA;AACF,CAAA;MAEa+B,gBAAAA,GAAmB,OAC9BjC,GAAAA,EACAC,KAAAA,EACAC,UACAC,MAAAA,EACAC,UAAAA,GAAAA;IAEA,IAAI;AACF,QAAA,OAAO,MAAML,gBAAAA,CAAoBC,GAAAA,EAAKC,KAAAA,EAAOC,UAAUC,MAAAA,EAAQC,UAAAA,CAAAA;AACjE,IAAA,CAAA,CAAE,OAAOyB,KAAAA,EAAO;QACd,IAAI,EAAEA,KAAAA,YAAiBhC,eAAc,KAAMgC,KAAAA,CAAM/B,MAAM,KAAK,GAAA,EAAK;YAC/D,MAAM+B,KAAAA;AACR,QAAA;QAEA,IAAI;AACF,YAAA,MAAMK,iBAAiB,MAAMC,mBAAAA,EAAAA;AAE7B,YAAA,OAAO,MAAMpC,gBAAAA,CAAoBC,GAAAA,EAAKkC,cAAAA,EAAgBhC,UAAUC,MAAAA,EAAQC,UAAAA,CAAAA;AAC1E,QAAA,CAAA,CAAE,OAAOgC,YAAAA,EAAc;AACrB,YAAA,IAAIA,wBAAwBvC,eAAAA,EAAiB;gBAC3C,MAAMuC,YAAAA;AACR,YAAA;YAEA,MAAMP,KAAAA;AACR,QAAA;AACF,IAAA;AACF;;;;"}
@@ -4,6 +4,7 @@ var React = require('react');
4
4
  var strapiAdmin = require('@strapi/admin/strapi-admin');
5
5
  var reactQuery = require('react-query');
6
6
  var reactRedux = require('react-redux');
7
+ var uploadFileViaXHR = require('../future/services/uploadFileViaXHR.js');
7
8
  var pluginId = require('../pluginId.js');
8
9
 
9
10
  function _interopNamespace(e) {
@@ -27,7 +28,7 @@ function _interopNamespace(e) {
27
28
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
29
 
29
30
  const endpoint = `/${pluginId.pluginId}`;
30
- const uploadAssets = (assets, folderId, signal, onProgress, post)=>{
31
+ const uploadAssets = (assets, folderId, signal, onProgress, token)=>{
31
32
  const assetsArray = Array.isArray(assets) ? assets : [
32
33
  assets
33
34
  ];
@@ -48,12 +49,13 @@ const uploadAssets = (assets, folderId, signal, onProgress, post)=>{
48
49
  }));
49
50
  });
50
51
  /**
51
- * onProgress is not possible using native fetch
52
- * need to look into an alternative to make it work
53
- * perhaps using xhr like Axios does
54
- */ return post(endpoint, formData, {
55
- signal
56
- }).then((res)=>res.data);
52
+ * Native fetch cannot report upload progress, so upload via the shared XHR
53
+ * service and surface its byte-level progress as a 0-100 percentage.
54
+ */ return uploadFileViaXHR.uploadFileViaXHR(`${window.strapi.backendURL}${endpoint}`, token, formData, signal, (loaded, total)=>{
55
+ if (total > 0) {
56
+ onProgress(Math.round(loaded / total * 100));
57
+ }
58
+ });
57
59
  };
58
60
  const useUpload = ()=>{
59
61
  const dispatch = reactRedux.useDispatch();
@@ -61,10 +63,14 @@ const useUpload = ()=>{
61
63
  const queryClient = reactQuery.useQueryClient();
62
64
  const abortController = new AbortController();
63
65
  const signal = abortController.signal;
64
- const { post } = strapiAdmin.useFetchClient();
66
+ const store = reactRedux.useStore();
65
67
  const mutation = reactQuery.useMutation(({ assets, folderId })=>{
66
- return uploadAssets(assets, folderId, signal, setProgress, post);
68
+ return uploadAssets(assets, folderId, signal, setProgress, store.getState().admin_app?.token);
67
69
  }, {
70
+ mutationKey: [
71
+ pluginId.pluginId,
72
+ 'upload'
73
+ ],
68
74
  onSuccess () {
69
75
  queryClient.refetchQueries([
70
76
  pluginId.pluginId,
@@ -1 +1 @@
1
- {"version":3,"file":"useUpload.js","sources":["../../../admin/src/hooks/useUpload.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useFetchClient, FetchClient, adminApi } from '@strapi/admin/strapi-admin';\nimport { useMutation, useQueryClient } from 'react-query';\nimport { useDispatch } from 'react-redux';\n\nimport { File, RawFile, CreateFile } from '../../../shared/contracts/files';\nimport { pluginId } from '../pluginId';\n\nconst endpoint = `/${pluginId}`;\n\ninterface Asset extends Omit<File, 'id' | 'hash'> {\n rawFile?: RawFile;\n id?: File['id'];\n hash?: File['hash'];\n}\n\nconst uploadAssets = (\n assets: Asset | Asset[],\n folderId: number | null,\n signal: AbortSignal,\n onProgress: (progress: number) => void,\n post: FetchClient['post']\n): Promise<CreateFile.Response['data']> => {\n const assetsArray = Array.isArray(assets) ? assets : [assets];\n const formData = new FormData();\n\n // Add all files to the form data\n assetsArray.forEach((asset) => {\n if (asset.rawFile) {\n formData.append('files', asset.rawFile);\n }\n });\n\n // Add each fileInfo as a separate stringified field\n assetsArray.forEach((asset) => {\n formData.append(\n 'fileInfo',\n JSON.stringify({\n name: asset.name,\n caption: asset.caption,\n alternativeText: asset.alternativeText,\n folder: folderId,\n })\n );\n });\n\n /**\n * onProgress is not possible using native fetch\n * need to look into an alternative to make it work\n * perhaps using xhr like Axios does\n */\n return post<CreateFile.Response['data'], CreateFile.Request['body']>(endpoint, formData, {\n signal,\n }).then((res) => res.data);\n};\n\nexport const useUpload = () => {\n const dispatch = useDispatch();\n const [progress, setProgress] = React.useState(0);\n const queryClient = useQueryClient();\n const abortController = new AbortController();\n const signal = abortController.signal;\n const { post } = useFetchClient();\n\n const mutation = useMutation<\n CreateFile.Response['data'],\n CreateFile.Response['error'],\n { assets: Asset | Asset[]; folderId: number | null }\n >(\n ({ assets, folderId }) => {\n return uploadAssets(assets, folderId, signal, setProgress, post);\n },\n {\n onSuccess() {\n queryClient.refetchQueries([pluginId, 'assets'], { active: true });\n queryClient.refetchQueries([pluginId, 'asset-count'], { active: true });\n dispatch(adminApi.util.invalidateTags(['HomepageKeyStatistics', 'AiUsage']));\n },\n }\n );\n\n const upload = (assets: Asset | Asset[], folderId: number | null) =>\n mutation.mutateAsync({ assets, folderId });\n\n const cancel = () => abortController.abort();\n\n return {\n upload,\n isLoading: mutation.isLoading,\n cancel,\n error: mutation.error,\n progress,\n status: mutation.status,\n };\n};\n"],"names":["endpoint","pluginId","uploadAssets","assets","folderId","signal","onProgress","post","assetsArray","Array","isArray","formData","FormData","forEach","asset","rawFile","append","JSON","stringify","name","caption","alternativeText","folder","then","res","data","useUpload","dispatch","useDispatch","progress","setProgress","React","useState","queryClient","useQueryClient","abortController","AbortController","useFetchClient","mutation","useMutation","onSuccess","refetchQueries","active","adminApi","util","invalidateTags","upload","mutateAsync","cancel","abort","isLoading","error","status"],"mappings":"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"}
1
+ {"version":3,"file":"useUpload.js","sources":["../../../admin/src/hooks/useUpload.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { adminApi } from '@strapi/admin/strapi-admin';\nimport { useMutation, useQueryClient } from 'react-query';\nimport { useDispatch, useStore } from 'react-redux';\n\nimport { File, RawFile, CreateFile } from '../../../shared/contracts/files';\nimport { uploadFileViaXHR } from '../future/services/uploadFileViaXHR';\nimport { pluginId } from '../pluginId';\n\nconst endpoint = `/${pluginId}`;\n\ninterface Asset extends Omit<File, 'id' | 'hash'> {\n rawFile?: RawFile;\n id?: File['id'];\n hash?: File['hash'];\n}\n\ninterface StoreState {\n admin_app: {\n token?: string | null;\n };\n}\n\nconst uploadAssets = (\n assets: Asset | Asset[],\n folderId: number | null,\n signal: AbortSignal,\n onProgress: (progress: number) => void,\n token: string | null | undefined\n): Promise<CreateFile.Response['data']> => {\n const assetsArray = Array.isArray(assets) ? assets : [assets];\n const formData = new FormData();\n\n // Add all files to the form data\n assetsArray.forEach((asset) => {\n if (asset.rawFile) {\n formData.append('files', asset.rawFile);\n }\n });\n\n // Add each fileInfo as a separate stringified field\n assetsArray.forEach((asset) => {\n formData.append(\n 'fileInfo',\n JSON.stringify({\n name: asset.name,\n caption: asset.caption,\n alternativeText: asset.alternativeText,\n folder: folderId,\n })\n );\n });\n\n /**\n * Native fetch cannot report upload progress, so upload via the shared XHR\n * service and surface its byte-level progress as a 0-100 percentage.\n */\n return uploadFileViaXHR<CreateFile.Response['data']>(\n `${window.strapi.backendURL}${endpoint}`,\n token,\n formData,\n signal,\n (loaded, total) => {\n if (total > 0) {\n onProgress(Math.round((loaded / total) * 100));\n }\n }\n );\n};\n\nexport const useUpload = () => {\n const dispatch = useDispatch();\n const [progress, setProgress] = React.useState(0);\n const queryClient = useQueryClient();\n const abortController = new AbortController();\n const signal = abortController.signal;\n const store = useStore<StoreState>();\n\n const mutation = useMutation<\n CreateFile.Response['data'],\n CreateFile.Response['error'],\n { assets: Asset | Asset[]; folderId: number | null }\n >(\n ({ assets, folderId }) => {\n return uploadAssets(assets, folderId, signal, setProgress, store.getState().admin_app?.token);\n },\n {\n mutationKey: [pluginId, 'upload'],\n onSuccess() {\n queryClient.refetchQueries([pluginId, 'assets'], { active: true });\n queryClient.refetchQueries([pluginId, 'asset-count'], { active: true });\n dispatch(adminApi.util.invalidateTags(['HomepageKeyStatistics', 'AiUsage']));\n },\n }\n );\n\n const upload = (assets: Asset | Asset[], folderId: number | null) =>\n mutation.mutateAsync({ assets, folderId });\n\n const cancel = () => abortController.abort();\n\n return {\n upload,\n isLoading: mutation.isLoading,\n cancel,\n error: mutation.error,\n progress,\n status: mutation.status,\n };\n};\n"],"names":["endpoint","pluginId","uploadAssets","assets","folderId","signal","onProgress","token","assetsArray","Array","isArray","formData","FormData","forEach","asset","rawFile","append","JSON","stringify","name","caption","alternativeText","folder","uploadFileViaXHR","window","strapi","backendURL","loaded","total","Math","round","useUpload","dispatch","useDispatch","progress","setProgress","React","useState","queryClient","useQueryClient","abortController","AbortController","store","useStore","mutation","useMutation","getState","admin_app","mutationKey","onSuccess","refetchQueries","active","adminApi","util","invalidateTags","upload","mutateAsync","cancel","abort","isLoading","error","status"],"mappings":"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"}
@@ -1,11 +1,12 @@
1
1
  import * as React from 'react';
2
- import { useFetchClient, adminApi } from '@strapi/admin/strapi-admin';
2
+ import { adminApi } from '@strapi/admin/strapi-admin';
3
3
  import { useQueryClient, useMutation } from 'react-query';
4
- import { useDispatch } from 'react-redux';
4
+ import { useDispatch, useStore } from 'react-redux';
5
+ import { uploadFileViaXHR } from '../future/services/uploadFileViaXHR.mjs';
5
6
  import { pluginId } from '../pluginId.mjs';
6
7
 
7
8
  const endpoint = `/${pluginId}`;
8
- const uploadAssets = (assets, folderId, signal, onProgress, post)=>{
9
+ const uploadAssets = (assets, folderId, signal, onProgress, token)=>{
9
10
  const assetsArray = Array.isArray(assets) ? assets : [
10
11
  assets
11
12
  ];
@@ -26,12 +27,13 @@ const uploadAssets = (assets, folderId, signal, onProgress, post)=>{
26
27
  }));
27
28
  });
28
29
  /**
29
- * onProgress is not possible using native fetch
30
- * need to look into an alternative to make it work
31
- * perhaps using xhr like Axios does
32
- */ return post(endpoint, formData, {
33
- signal
34
- }).then((res)=>res.data);
30
+ * Native fetch cannot report upload progress, so upload via the shared XHR
31
+ * service and surface its byte-level progress as a 0-100 percentage.
32
+ */ return uploadFileViaXHR(`${window.strapi.backendURL}${endpoint}`, token, formData, signal, (loaded, total)=>{
33
+ if (total > 0) {
34
+ onProgress(Math.round(loaded / total * 100));
35
+ }
36
+ });
35
37
  };
36
38
  const useUpload = ()=>{
37
39
  const dispatch = useDispatch();
@@ -39,10 +41,14 @@ const useUpload = ()=>{
39
41
  const queryClient = useQueryClient();
40
42
  const abortController = new AbortController();
41
43
  const signal = abortController.signal;
42
- const { post } = useFetchClient();
44
+ const store = useStore();
43
45
  const mutation = useMutation(({ assets, folderId })=>{
44
- return uploadAssets(assets, folderId, signal, setProgress, post);
46
+ return uploadAssets(assets, folderId, signal, setProgress, store.getState().admin_app?.token);
45
47
  }, {
48
+ mutationKey: [
49
+ pluginId,
50
+ 'upload'
51
+ ],
46
52
  onSuccess () {
47
53
  queryClient.refetchQueries([
48
54
  pluginId,