From 4acdc6a4e2734104a77396c2dd858c58517ecc07 Mon Sep 17 00:00:00 2001 From: Hleb Kryshyn Date: Wed, 20 May 2026 15:50:01 +0200 Subject: [PATCH 1/3] feat(uploads-manager): integrate shared feature into ContentUploader Wire @box/uploads-manager UploadsManager into ContentUploader behind the enableModernizedUploads flag. Maps legacy upload state to the shared feature's item shape and delegates per-item cancel/retry/remove actions to existing handlers. --- .../content-uploader/ContentUploader.tsx | 33 +++++++- .../__tests__/ContentUploader.test.js | 82 ++++++++++++++++++- .../mapToModernizedUploadItem.test.ts | 79 ++++++++++++++++++ .../utils/mapToModernizedUploadItem.ts | 47 +++++++++++ 4 files changed, 237 insertions(+), 4 deletions(-) create mode 100644 src/elements/content-uploader/utils/__tests__/mapToModernizedUploadItem.test.ts create mode 100644 src/elements/content-uploader/utils/mapToModernizedUploadItem.ts diff --git a/src/elements/content-uploader/ContentUploader.tsx b/src/elements/content-uploader/ContentUploader.tsx index 9923bf3ced..1dfda498a5 100644 --- a/src/elements/content-uploader/ContentUploader.tsx +++ b/src/elements/content-uploader/ContentUploader.tsx @@ -12,6 +12,7 @@ import { AxiosRequestConfig, AxiosResponse } from 'axios'; import DroppableContent from './DroppableContent'; import Footer from './Footer'; import UploadsManager from './UploadsManager'; +import { mapToModernizedUploadItems } from './utils/mapToModernizedUploadItem'; import API from '../../api'; import Browser from '../../utils/Browser'; import Internationalize from '../common/Internationalize'; @@ -1219,6 +1220,28 @@ class ContentUploader extends Component { } }; + /** + * Find legacy UploadItem by the id used by the modernized uploads manager. + */ + findItemByModernizedId = (id: string): UploadItem | undefined => { + const { rootFolderId } = this.props; + return this.state.items.find(item => getFileId(item.file, rootFolderId) === id); + }; + + handleModernizedItemAction = (id: string) => { + const item = this.findItemByModernizedId(id); + if (item) { + this.onClick(item); + } + }; + + handleModernizedItemRemove = (id: string) => { + const item = this.findItemByModernizedId(id); + if (item) { + this.removeFileFromUploadQueue(item); + } + }; + /** * Empties the items queue * @@ -1282,6 +1305,7 @@ class ContentUploader extends Component { messages, onClose, onUpgradeCTAClick, + rootFolderId, theme, useUploadsManager, }: ContentUploaderProps = this.props; @@ -1303,7 +1327,14 @@ class ContentUploader extends Component { return (
- +
); } diff --git a/src/elements/content-uploader/__tests__/ContentUploader.test.js b/src/elements/content-uploader/__tests__/ContentUploader.test.js index 10b0afefcc..4348945f12 100644 --- a/src/elements/content-uploader/__tests__/ContentUploader.test.js +++ b/src/elements/content-uploader/__tests__/ContentUploader.test.js @@ -7,6 +7,7 @@ import { ContentUploaderComponent, CHUNKED_UPLOAD_MIN_SIZE_BYTES } from '../Cont import Footer from '../Footer'; import UploadsManager from '../UploadsManager'; import DroppableContent from '../DroppableContent'; +import { UploadsManager as UploadsManagerBP } from '@box/uploads-manager'; import { STATUS_PENDING, STATUS_IN_PROGRESS, @@ -775,18 +776,93 @@ describe('elements/content-uploader/ContentUploader', () => { expect(wrapper.find(UploadsManagerBP)).toHaveLength(0); }); - test('should render modernized UploadsManager when enableModernizedUploads is true', () => { + test('should render modernized UploadsManagerBP when enableModernizedUploads is true', () => { const wrapper = getWrapper({ enableModernizedUploads: true }); expect(wrapper.find(UploadsManagerBP)).toHaveLength(1); expect(wrapper.find(UploadsManager)).toHaveLength(0); expect(wrapper.find(DroppableContent)).toHaveLength(0); }); - test('should render modernized UploadsManager when enableModernizedUploads is true and useUploadsManager is true', () => { + test('should render modernized UploadsManagerBP even when useUploadsManager is true', () => { const wrapper = getWrapper({ enableModernizedUploads: true, useUploadsManager: true }); expect(wrapper.find(UploadsManagerBP)).toHaveLength(1); expect(wrapper.find(UploadsManager)).toHaveLength(0); - expect(wrapper.find(DroppableContent)).toHaveLength(0); + }); + + test('should map state.items to modernized item shape', () => { + const wrapper = getWrapper({ enableModernizedUploads: true }); + wrapper.setState({ + items: [ + { + name: 'foo.pdf', + extension: 'pdf', + progress: 42, + status: STATUS_IN_PROGRESS, + file: { name: 'foo.pdf' }, + }, + ], + }); + const items = wrapper.find(UploadsManagerBP).prop('items'); + expect(items).toHaveLength(1); + expect(items[0]).toMatchObject({ + name: 'foo.pdf', + extension: 'pdf', + progress: 42, + status: 'uploading', + }); + }); + + test('should pass isExpanded from state', () => { + const wrapper = getWrapper({ enableModernizedUploads: true }); + wrapper.setState({ isUploadsManagerExpanded: true }); + expect(wrapper.find(UploadsManagerBP).prop('isExpanded')).toBe(true); + }); + + test('should call onClick when onItemCancel is invoked', () => { + const wrapper = getWrapper({ enableModernizedUploads: true }); + const item = { + name: 'foo.pdf', + extension: 'pdf', + progress: 0, + status: STATUS_PENDING, + file: { name: 'foo.pdf' }, + }; + wrapper.setState({ items: [item] }); + const instance = wrapper.instance(); + const onClickSpy = jest.spyOn(instance, 'onClick').mockImplementation(() => {}); + + wrapper.find(UploadsManagerBP).prop('onItemCancel')('foo.pdf'); + + expect(onClickSpy).toHaveBeenCalledWith(item); + }); + + test('should call removeFileFromUploadQueue when onItemRemove is invoked', () => { + const wrapper = getWrapper({ enableModernizedUploads: true }); + const item = { + name: 'foo.pdf', + extension: 'pdf', + progress: 0, + status: STATUS_COMPLETE, + file: { name: 'foo.pdf' }, + }; + wrapper.setState({ items: [item] }); + const instance = wrapper.instance(); + const removeSpy = jest.spyOn(instance, 'removeFileFromUploadQueue').mockImplementation(() => {}); + + wrapper.find(UploadsManagerBP).prop('onItemRemove')('foo.pdf'); + + expect(removeSpy).toHaveBeenCalledWith(item); + }); + + test('should no-op when modernized id does not match any item', () => { + const wrapper = getWrapper({ enableModernizedUploads: true }); + wrapper.setState({ items: [] }); + const instance = wrapper.instance(); + const onClickSpy = jest.spyOn(instance, 'onClick').mockImplementation(() => {}); + + wrapper.find(UploadsManagerBP).prop('onItemCancel')('missing-id'); + + expect(onClickSpy).not.toHaveBeenCalled(); }); }); }); diff --git a/src/elements/content-uploader/utils/__tests__/mapToModernizedUploadItem.test.ts b/src/elements/content-uploader/utils/__tests__/mapToModernizedUploadItem.test.ts new file mode 100644 index 0000000000..4d521f8d86 --- /dev/null +++ b/src/elements/content-uploader/utils/__tests__/mapToModernizedUploadItem.test.ts @@ -0,0 +1,79 @@ +import { + STATUS_PENDING, + STATUS_IN_PROGRESS, + STATUS_STAGED, + STATUS_COMPLETE, + STATUS_ERROR, +} from '../../../../constants'; +import { mapToModernizedUploadItem, mapToModernizedUploadItems } from '../mapToModernizedUploadItem'; + +const buildLegacyItem = (overrides = {}) => ({ + name: 'foo.pdf', + extension: 'pdf', + progress: 50, + status: STATUS_IN_PROGRESS, + size: 100, + file: { name: 'foo.pdf' } as File, + api: {} as never, + ...overrides, +}); + +describe('mapToModernizedUploadItem()', () => { + test('maps core fields', () => { + const result = mapToModernizedUploadItem(buildLegacyItem(), '0'); + expect(result).toEqual({ + id: 'foo.pdf', + name: 'foo.pdf', + extension: 'pdf', + progress: 50, + status: 'uploading', + isFolder: undefined, + errorMessage: undefined, + }); + }); + + test.each([ + [STATUS_PENDING, 'pending'], + [STATUS_IN_PROGRESS, 'uploading'], + [STATUS_STAGED, 'staged'], + [STATUS_COMPLETE, 'complete'], + [STATUS_ERROR, 'error'], + ])('maps legacy status %s to modernized %s', (legacy, modernized) => { + const result = mapToModernizedUploadItem(buildLegacyItem({ status: legacy }), '0'); + expect(result.status).toBe(modernized); + }); + + test('extracts errorMessage from item.error', () => { + const result = mapToModernizedUploadItem( + buildLegacyItem({ status: STATUS_ERROR, error: { message: 'Boom' } }), + '0', + ); + expect(result.errorMessage).toBe('Boom'); + }); + + test('forwards isFolder', () => { + const result = mapToModernizedUploadItem(buildLegacyItem({ isFolder: true }), '0'); + expect(result.isFolder).toBe(true); + }); + + test('defaults missing extension and progress', () => { + const result = mapToModernizedUploadItem( + buildLegacyItem({ extension: undefined, progress: undefined }), + '0', + ); + expect(result.extension).toBe(''); + expect(result.progress).toBe(0); + }); +}); + +describe('mapToModernizedUploadItems()', () => { + test('maps a list', () => { + const result = mapToModernizedUploadItems( + [buildLegacyItem({ name: 'a.pdf', file: { name: 'a.pdf' } as File }), buildLegacyItem({ name: 'b.pdf', file: { name: 'b.pdf' } as File })], + '0', + ); + expect(result).toHaveLength(2); + expect(result[0].id).toBe('a.pdf'); + expect(result[1].id).toBe('b.pdf'); + }); +}); diff --git a/src/elements/content-uploader/utils/mapToModernizedUploadItem.ts b/src/elements/content-uploader/utils/mapToModernizedUploadItem.ts new file mode 100644 index 0000000000..c98389f974 --- /dev/null +++ b/src/elements/content-uploader/utils/mapToModernizedUploadItem.ts @@ -0,0 +1,47 @@ +import { + STATUS_PENDING, + STATUS_IN_PROGRESS, + STATUS_STAGED, + STATUS_COMPLETE, + STATUS_ERROR, +} from '../../../constants'; +import { getFileId } from '../../../utils/uploads'; +import { UploadItem as LegacyUploadItem } from '../../../common/types/upload'; + +type ModernizedStatus = 'pending' | 'uploading' | 'staged' | 'complete' | 'error' | 'canceled'; + +export interface ModernizedUploadItem { + id: string; + name: string; + extension: string; + progress: number; + status: ModernizedStatus; + isFolder?: boolean; + errorMessage?: string; +} + +const STATUS_MAP: Record = { + [STATUS_PENDING]: 'pending', + [STATUS_IN_PROGRESS]: 'uploading', + [STATUS_STAGED]: 'staged', + [STATUS_COMPLETE]: 'complete', + [STATUS_ERROR]: 'error', +}; + +export function mapToModernizedUploadItem(item: LegacyUploadItem, rootFolderId: string): ModernizedUploadItem { + const errorMessage = item.error ? (item.error as { message?: string }).message : undefined; + + return { + id: getFileId(item.file, rootFolderId), + name: item.name, + extension: item.extension ?? '', + progress: item.progress ?? 0, + status: STATUS_MAP[item.status] ?? 'pending', + isFolder: item.isFolder, + errorMessage, + }; +} + +export function mapToModernizedUploadItems(items: LegacyUploadItem[], rootFolderId: string): ModernizedUploadItem[] { + return items.map(item => mapToModernizedUploadItem(item, rootFolderId)); +} From a90dda9e43fe4e0ec3d51bad8294e97493588887 Mon Sep 17 00:00:00 2001 From: Hleb Kryshyn Date: Mon, 25 May 2026 16:54:09 +0200 Subject: [PATCH 2/3] fix(content-uploader): remove duplicated import --- src/elements/content-uploader/__tests__/ContentUploader.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/elements/content-uploader/__tests__/ContentUploader.test.js b/src/elements/content-uploader/__tests__/ContentUploader.test.js index 4348945f12..7892eb9f18 100644 --- a/src/elements/content-uploader/__tests__/ContentUploader.test.js +++ b/src/elements/content-uploader/__tests__/ContentUploader.test.js @@ -7,7 +7,6 @@ import { ContentUploaderComponent, CHUNKED_UPLOAD_MIN_SIZE_BYTES } from '../Cont import Footer from '../Footer'; import UploadsManager from '../UploadsManager'; import DroppableContent from '../DroppableContent'; -import { UploadsManager as UploadsManagerBP } from '@box/uploads-manager'; import { STATUS_PENDING, STATUS_IN_PROGRESS, From 5480f478094ebb8b3ab9ab058386e8b4bc5e4a6d Mon Sep 17 00:00:00 2001 From: Hleb Kryshyn Date: Mon, 25 May 2026 17:49:43 +0200 Subject: [PATCH 3/3] fix(content-uploader): fix uploading mapping --- package.json | 4 +- .../content-uploader/ContentUploader.tsx | 16 ++--- .../__tests__/ContentUploader.test.js | 38 +++++++++++ .../mapToModernizedUploadItem.test.ts | 65 +++++++++++++++++-- .../utils/mapToModernizedUploadItem.ts | 44 ++++++------- yarn.lock | 39 ++--------- 6 files changed, 134 insertions(+), 72 deletions(-) diff --git a/package.json b/package.json index 3cb7386867..7727269fb1 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "@box/types": "^2.1.8", "@box/unified-share-modal": "^2.15.16", "@box/user-selector": "^1.76.19", - "@box/uploads-manager": "^1.14.0", + "@box/uploads-manager": "^1.15.0", "@cfaester/enzyme-adapter-react-18": "^0.8.0", "@chromatic-com/storybook": "^4.0.1", "@commitlint/cli": "^19.8.0", @@ -314,7 +314,7 @@ "@box/types": "^2.1.8", "@box/unified-share-modal": "^2.15.16", "@box/user-selector": "^1.76.19", - "@box/uploads-manager": "^1.14.0", + "@box/uploads-manager": "^1.15.0", "@hapi/address": "^2.1.4", "@tanstack/react-virtual": "^3.13.12", "axios": "^0.31.1", diff --git a/src/elements/content-uploader/ContentUploader.tsx b/src/elements/content-uploader/ContentUploader.tsx index 1dfda498a5..9e9cf4f193 100644 --- a/src/elements/content-uploader/ContentUploader.tsx +++ b/src/elements/content-uploader/ContentUploader.tsx @@ -12,7 +12,7 @@ import { AxiosRequestConfig, AxiosResponse } from 'axios'; import DroppableContent from './DroppableContent'; import Footer from './Footer'; import UploadsManager from './UploadsManager'; -import { mapToModernizedUploadItems } from './utils/mapToModernizedUploadItem'; +import { getModernizedItemId, mapToModernizedUploadItems } from './utils/mapToModernizedUploadItem'; import API from '../../api'; import Browser from '../../utils/Browser'; import Internationalize from '../common/Internationalize'; @@ -1225,7 +1225,7 @@ class ContentUploader extends Component { */ findItemByModernizedId = (id: string): UploadItem | undefined => { const { rootFolderId } = this.props; - return this.state.items.find(item => getFileId(item.file, rootFolderId) === id); + return this.state.items.find(item => getModernizedItemId(item, rootFolderId) === id); }; handleModernizedItemAction = (id: string) => { @@ -1357,9 +1357,9 @@ class ContentUploader extends Component { view={view} /> - ) + ); } - + return (
@@ -1384,14 +1384,12 @@ class ContentUploader extends Component { isDone={isDone} />
- ) - } + ); + }; return ( - - {renderUploader()} - + {renderUploader()} ); } diff --git a/src/elements/content-uploader/__tests__/ContentUploader.test.js b/src/elements/content-uploader/__tests__/ContentUploader.test.js index 7892eb9f18..d3591d8687 100644 --- a/src/elements/content-uploader/__tests__/ContentUploader.test.js +++ b/src/elements/content-uploader/__tests__/ContentUploader.test.js @@ -863,6 +863,44 @@ describe('elements/content-uploader/ContentUploader', () => { expect(onClickSpy).not.toHaveBeenCalled(); }); + + test('should not crash when state contains a folder item without a file', () => { + const wrapper = getWrapper({ enableModernizedUploads: true, rootFolderId: '0' }); + const folderItem = { + name: 'my-folder', + extension: '', + progress: 0, + status: STATUS_PENDING, + isFolder: true, + api: {}, + }; + wrapper.setState({ items: [folderItem] }); + + expect(() => wrapper.find(UploadsManagerBP).prop('items')).not.toThrow(); + const items = wrapper.find(UploadsManagerBP).prop('items'); + expect(items).toHaveLength(1); + expect(items[0]).toMatchObject({ name: 'my-folder', isFolder: true }); + }); + + test('should resolve folder item handler via modernized id', () => { + const wrapper = getWrapper({ enableModernizedUploads: true, rootFolderId: '0' }); + const folderItem = { + name: 'my-folder', + extension: '', + progress: 0, + status: STATUS_PENDING, + isFolder: true, + api: {}, + }; + wrapper.setState({ items: [folderItem] }); + const instance = wrapper.instance(); + const onClickSpy = jest.spyOn(instance, 'onClick').mockImplementation(() => {}); + + const folderId = wrapper.find(UploadsManagerBP).prop('items')[0].id; + wrapper.find(UploadsManagerBP).prop('onItemCancel')(folderId); + + expect(onClickSpy).toHaveBeenCalledWith(folderItem); + }); }); }); }); diff --git a/src/elements/content-uploader/utils/__tests__/mapToModernizedUploadItem.test.ts b/src/elements/content-uploader/utils/__tests__/mapToModernizedUploadItem.test.ts index 4d521f8d86..3376be23a1 100644 --- a/src/elements/content-uploader/utils/__tests__/mapToModernizedUploadItem.test.ts +++ b/src/elements/content-uploader/utils/__tests__/mapToModernizedUploadItem.test.ts @@ -57,10 +57,7 @@ describe('mapToModernizedUploadItem()', () => { }); test('defaults missing extension and progress', () => { - const result = mapToModernizedUploadItem( - buildLegacyItem({ extension: undefined, progress: undefined }), - '0', - ); + const result = mapToModernizedUploadItem(buildLegacyItem({ extension: undefined, progress: undefined }), '0'); expect(result.extension).toBe(''); expect(result.progress).toBe(0); }); @@ -69,11 +66,69 @@ describe('mapToModernizedUploadItem()', () => { describe('mapToModernizedUploadItems()', () => { test('maps a list', () => { const result = mapToModernizedUploadItems( - [buildLegacyItem({ name: 'a.pdf', file: { name: 'a.pdf' } as File }), buildLegacyItem({ name: 'b.pdf', file: { name: 'b.pdf' } as File })], + [ + buildLegacyItem({ name: 'a.pdf', file: { name: 'a.pdf' } as File }), + buildLegacyItem({ name: 'b.pdf', file: { name: 'b.pdf' } as File }), + ], '0', ); expect(result).toHaveLength(2); expect(result[0].id).toBe('a.pdf'); expect(result[1].id).toBe('b.pdf'); }); + + test('does not crash when item has no file (folder item)', () => { + const folderItem = { + name: 'my-folder', + extension: '', + progress: 0, + status: STATUS_PENDING, + size: 1, + isFolder: true, + api: {} as never, + } as never; + + expect(() => mapToModernizedUploadItems([folderItem], '0')).not.toThrow(); + }); + + test('produces stable id for folder item without options', () => { + const folderItem = { + name: 'my-folder', + extension: '', + progress: 0, + status: STATUS_PENDING, + size: 1, + isFolder: true, + api: {} as never, + } as never; + + const result = mapToModernizedUploadItems([folderItem], '0'); + expect(result[0].id).toBe('my-folder_0'); + }); + + test('produces distinct ids for folder items with different folderId options', () => { + const folderA = { + name: 'shared', + extension: '', + progress: 0, + status: STATUS_PENDING, + size: 1, + isFolder: true, + options: { folderId: '111' }, + api: {} as never, + } as never; + const folderB = { + name: 'shared', + extension: '', + progress: 0, + status: STATUS_PENDING, + size: 1, + isFolder: true, + options: { folderId: '222' }, + api: {} as never, + } as never; + + const result = mapToModernizedUploadItems([folderA, folderB], '0'); + expect(result[0].id).not.toBe(result[1].id); + }); }); diff --git a/src/elements/content-uploader/utils/mapToModernizedUploadItem.ts b/src/elements/content-uploader/utils/mapToModernizedUploadItem.ts index c98389f974..21bf262931 100644 --- a/src/elements/content-uploader/utils/mapToModernizedUploadItem.ts +++ b/src/elements/content-uploader/utils/mapToModernizedUploadItem.ts @@ -1,26 +1,9 @@ -import { - STATUS_PENDING, - STATUS_IN_PROGRESS, - STATUS_STAGED, - STATUS_COMPLETE, - STATUS_ERROR, -} from '../../../constants'; +import type { UploadItem, UploadItemStatus } from '@box/uploads-manager'; +import { STATUS_PENDING, STATUS_IN_PROGRESS, STATUS_STAGED, STATUS_COMPLETE, STATUS_ERROR } from '../../../constants'; import { getFileId } from '../../../utils/uploads'; -import { UploadItem as LegacyUploadItem } from '../../../common/types/upload'; +import { UploadItem as LegacyUploadItem, FolderUploadItem } from '../../../common/types/upload'; -type ModernizedStatus = 'pending' | 'uploading' | 'staged' | 'complete' | 'error' | 'canceled'; - -export interface ModernizedUploadItem { - id: string; - name: string; - extension: string; - progress: number; - status: ModernizedStatus; - isFolder?: boolean; - errorMessage?: string; -} - -const STATUS_MAP: Record = { +const STATUS_MAP: Record = { [STATUS_PENDING]: 'pending', [STATUS_IN_PROGRESS]: 'uploading', [STATUS_STAGED]: 'staged', @@ -28,11 +11,21 @@ const STATUS_MAP: Record = { [STATUS_ERROR]: 'error', }; -export function mapToModernizedUploadItem(item: LegacyUploadItem, rootFolderId: string): ModernizedUploadItem { +export function getModernizedItemId(item: LegacyUploadItem | FolderUploadItem, rootFolderId: string): string { + const fileItem = item as LegacyUploadItem; + if (fileItem.file) { + const fileWithOptions = fileItem.options ? { file: fileItem.file, options: fileItem.options } : fileItem.file; + return getFileId(fileWithOptions, rootFolderId); + } + const folderId = item.options?.folderId ?? rootFolderId; + return `${item.name}_${folderId}`; +} + +export function mapToModernizedUploadItem(item: LegacyUploadItem | FolderUploadItem, rootFolderId: string): UploadItem { const errorMessage = item.error ? (item.error as { message?: string }).message : undefined; return { - id: getFileId(item.file, rootFolderId), + id: getModernizedItemId(item, rootFolderId), name: item.name, extension: item.extension ?? '', progress: item.progress ?? 0, @@ -42,6 +35,9 @@ export function mapToModernizedUploadItem(item: LegacyUploadItem, rootFolderId: }; } -export function mapToModernizedUploadItems(items: LegacyUploadItem[], rootFolderId: string): ModernizedUploadItem[] { +export function mapToModernizedUploadItems( + items: Array, + rootFolderId: string, +): UploadItem[] { return items.map(item => mapToModernizedUploadItem(item, rootFolderId)); } diff --git a/yarn.lock b/yarn.lock index e084dff5b5..8173e025bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1242,10 +1242,10 @@ resolved "https://registry.yarnpkg.com/@box/unified-share-modal/-/unified-share-modal-2.15.16.tgz#49deb182bf1ac7f1ffe4bae713ab12ff2822533e" integrity sha512-Y1bE+JWDQm058lT+AcsfwJqK3WvGAsZj6ro9PLvejJZ1LxzexvOzyQFkM0sL4Kmj/93k2VEKoAJ/onBgheAJoQ== -"@box/uploads-manager@^1.14.0": - version "1.14.0" - resolved "https://registry.yarnpkg.com/@box/uploads-manager/-/uploads-manager-1.14.0.tgz#573cf4533f80332cf044693a23a299552f3355d8" - integrity sha512-OtsKfRymJsWlErIC1tkU8Fn9aUbxDHF4PevalLpYPwLlXd/HtSbktBIGmxvr22PAH2sNQ9TILuXqBeJVe+/tsg== +"@box/uploads-manager@^1.15.0": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@box/uploads-manager/-/uploads-manager-1.15.0.tgz#59e68734bb2dd0c84b356e3270f7d41e964dcbc9" + integrity sha512-pvz8wsZbhfoDK6tPfYl3Yo+48++C9Rcx6NxNVQxeq0dTGCjQeP4z0nLPvEaAGOUDI6osyF31pKSTDhwBSQsM7g== "@box/user-selector@^1.76.19": version "1.76.19" @@ -17794,7 +17794,7 @@ string-replace-loader@^3.1.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -17820,15 +17820,6 @@ string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -17957,7 +17948,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -17978,13 +17969,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -19518,7 +19502,7 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -19544,15 +19528,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"