diff --git a/i18n/en-US.properties b/i18n/en-US.properties index 597ad95e7b..101e919d7d 100644 --- a/i18n/en-US.properties +++ b/i18n/en-US.properties @@ -72,6 +72,10 @@ be.appActivity.altIcon = {appActivityName} Icon be.appActivity.deleteMenuItem = Delete # Confirmation prompt text to delete app activity be.appActivity.deletePrompt = Are you sure you want to permanently delete this app activity? +# Icon title for a Box item of type folder is an archive +be.archive = Archive +# Icon title for a Box item of type folder is in archive +be.archivedFolder = Archived Folder # Label for back button be.back = Back # Icon title for a Box item of type bookmark or web-link diff --git a/src/common/types/core.js b/src/common/types/core.js index d38390b52b..a1b4f47572 100644 --- a/src/common/types/core.js +++ b/src/common/types/core.js @@ -302,6 +302,7 @@ type SharedLinkFeatures = { type BoxItem = { allowed_shared_link_access_levels?: Array, + archive_type?: 'archive' | 'folder_archive' | 'file' | 'web_link', authenticated_download_url?: string, content_created_at?: string, content_modified_at?: string, diff --git a/src/constants.js b/src/constants.js index acb96f1bd2..62931a88e8 100644 --- a/src/constants.js +++ b/src/constants.js @@ -35,6 +35,12 @@ export const TYPE_FOLDER: 'folder' = 'folder'; export const TYPE_FILE: 'file' = 'file'; export const TYPE_WEBLINK: 'web_link' = 'web_link'; +/* ----------------------- Archive Types ---------------------------- */ +export const TYPE_ARCHIVE: 'archive' = 'archive'; +export const TYPE_ARCHIVE_FOLDER: 'folder_archive' = 'folder_archive'; +export const TYPE_ARCHIVE_FILE: 'file' = 'file'; +export const TYPE_ARCHIVE_WEB_LINK: 'web_link' = 'web_link'; + /* ----------------------- Feed Items Types ---------------------------- */ export const FEED_ITEM_TYPE_APP_ACTIVITY: 'app_activity' = 'app_activity'; export const FEED_ITEM_TYPE_ANNOTATION: 'annotation' = 'annotation'; diff --git a/src/elements/common/item/IconCell.js b/src/elements/common/item/IconCell.js index 2c524b265b..e99fcd1dd6 100644 --- a/src/elements/common/item/IconCell.js +++ b/src/elements/common/item/IconCell.js @@ -7,6 +7,7 @@ import * as React from 'react'; import { injectIntl } from 'react-intl'; import type { IntlShape } from 'react-intl'; +import { Archive, FolderArchive } from '@box/blueprint-web-assets/icons/Content'; import FileIcon from '../../../icons/file-icon/FileIcon'; import FolderIcon from '../../../icons/folder-icon/FolderIcon'; import BookmarkIcon from '../../../icons/bookmark-icon/BookmarkIcon'; @@ -20,13 +21,35 @@ import './IconCell.scss'; type Props = { dimension?: number, intl: IntlShape, rowData: BoxItem }; const IconCell = ({ intl, rowData, dimension }: Props) => { - const { type, extension, has_collaborations, is_externally_owned }: BoxItem = rowData; + const { type, extension, has_collaborations, is_externally_owned, archive_type }: BoxItem = rowData; let title; + const is_archive = archive_type === 'archive'; + const is_archive_folder = archive_type === 'folder_archive'; switch (type) { case TYPE_FILE: title = intl.formatMessage(messages.file); return ; case TYPE_FOLDER: + if (is_archive) { + return ( + + ); + } + if (is_archive_folder) { + return ( + + ); + } if (has_collaborations) { title = intl.formatMessage(messages.collaboratedFolder); } else if (is_externally_owned) { diff --git a/src/elements/common/item/__tests__/IconCell.test.js b/src/elements/common/item/__tests__/IconCell.test.js index 457cc2a5bd..36decf24e3 100644 --- a/src/elements/common/item/__tests__/IconCell.test.js +++ b/src/elements/common/item/__tests__/IconCell.test.js @@ -1,5 +1,6 @@ import * as React from 'react'; +import { render, screen } from '../../../../test-utils/testing-library'; import { IconCellBase as IconCell } from '../IconCell'; const intl = { @@ -7,16 +8,38 @@ const intl = { }; describe('elements/common/item/IconCell', () => { - const getWrapper = props => shallow(); + const getWrapper = props => render(); describe('render()', () => { test('should render default file icon', () => { const rowData = { type: undefined }; - const wrapper = getWrapper({ rowData }); + getWrapper({ rowData }); - expect(wrapper.name()).toBe('FileIcon'); - expect(wrapper.prop('extension')).toBe(undefined); - expect(wrapper.prop('title')).toBe('File'); + expect(screen.getByTitle('File')).toBeInTheDocument(); + }); + + test('should render archive icon', () => { + const rowData = { + type: 'folder', + archive_type: 'archive', + has_collaborations: false, + is_externally_owned: false, + }; + getWrapper({ rowData }); + + expect(screen.getByTestId('archive-icon-cell')).toBeVisible(); + }); + + test('should render archived folder icon', () => { + const rowData = { + type: 'folder', + archive_type: 'folder_archive', + has_collaborations: false, + is_externally_owned: false, + }; + getWrapper({ rowData }); + + expect(screen.getByTestId('folder-archive-icon-cell')).toBeVisible(); }); [ @@ -58,31 +81,25 @@ describe('elements/common/item/IconCell', () => { }, ].forEach(({ rowData, title }) => { test('should render correct folder icon', () => { - const wrapper = getWrapper({ rowData }); + getWrapper({ rowData }); - expect(wrapper.name()).toBe('FolderIcon'); - expect(wrapper.prop('isCollab')).toBe(rowData.has_collaborations); - expect(wrapper.prop('isExternal')).toBe(rowData.is_externally_owned); - expect(wrapper.prop('title')).toBe(title); + expect(screen.getByTitle(title)).toBeInTheDocument(); }); }); test('should render correct file icon', () => { const extension = 'boxnote'; const rowData = { type: 'file', extension }; - const wrapper = getWrapper({ rowData }); + getWrapper({ rowData }); - expect(wrapper.name()).toBe('FileIcon'); - expect(wrapper.prop('extension')).toBe(extension); - expect(wrapper.prop('title')).toBe('File'); + expect(screen.getByTitle('File')).toBeInTheDocument(); }); test('should render correct bookmark icon', () => { const rowData = { type: 'web_link' }; - const wrapper = getWrapper({ rowData }); + getWrapper({ rowData }); - expect(wrapper.name()).toBe('BookmarkIcon'); - expect(wrapper.prop('title')).toBe('Bookmark'); + expect(screen.getByTitle('Bookmark')).toBeInTheDocument(); }); }); }); diff --git a/src/elements/common/messages.js b/src/elements/common/messages.js index 950672d4e6..adb77a32d5 100644 --- a/src/elements/common/messages.js +++ b/src/elements/common/messages.js @@ -1025,6 +1025,16 @@ const messages = defineMessages({ description: 'Icon title for a Box item of type bookmark or web-link', defaultMessage: 'Bookmark', }, + archive: { + id: 'be.archive', + description: 'Icon title for a Box item of type folder is an archive', + defaultMessage: 'Archive', + }, + archivedFolder: { + id: 'be.archivedFolder', + description: 'Icon title for a Box item of type folder is in archive', + defaultMessage: 'Archived Folder', + }, collaboratedFolder: { id: 'be.collaboratedFolder', description: 'Icon title for a Box item of type folder that has collaborators', diff --git a/src/elements/content-explorer/stories/__mocks__/mockRootFolder.ts b/src/elements/content-explorer/stories/__mocks__/mockRootFolder.ts index 9b75f6b7a5..b03dd3891a 100644 --- a/src/elements/content-explorer/stories/__mocks__/mockRootFolder.ts +++ b/src/elements/content-explorer/stories/__mocks__/mockRootFolder.ts @@ -99,6 +99,120 @@ const mockRootFolder = { is_watermarked: false, }, }, + { + type: 'folder', + id: '73426618531', + etag: '3', + name: 'Archive', + size: 1231231, + parent: { + type: 'folder', + id: '69083462919', + sequence_id: '2', + etag: '2', + name: 'Preview Test Folder', + }, + permissions: { + can_download: true, + can_upload: false, + can_rename: false, + can_delete: false, + can_share: false, + can_invite_collaborator: false, + can_set_share_access: false, + }, + path_collection: { + total_count: 2, + entries: [ + { + type: 'folder', + id: '0', + sequence_id: null, + etag: null, + name: 'All Files', + }, + { + type: 'folder', + id: '69083462919', + sequence_id: '2', + etag: '2', + name: 'Preview Test Folder', + }, + ], + }, + modified_at: '2020-12-16T03:21:44-07:00', + created_at: '2020-11-12T09:33:22-07:00', + modified_by: { + type: 'user', + id: '7503712462', + name: 'Preview', + login: 'preview@boxdemo.com', + }, + has_collaborations: true, + is_externally_owned: false, + shared_link: null, + watermark_info: { + is_watermarked: false, + }, + archive_type: 'archive', + }, + { + type: 'folder', + id: '73426618532', + etag: '3', + name: 'Archived Folder', + size: 1231231, + parent: { + type: 'folder', + id: '69083462919', + sequence_id: '2', + etag: '2', + name: 'Preview Test Folder', + }, + permissions: { + can_download: true, + can_upload: false, + can_rename: false, + can_delete: false, + can_share: false, + can_invite_collaborator: false, + can_set_share_access: false, + }, + path_collection: { + total_count: 2, + entries: [ + { + type: 'folder', + id: '0', + sequence_id: null, + etag: null, + name: 'All Files', + }, + { + type: 'folder', + id: '69083462919', + sequence_id: '2', + etag: '2', + name: 'Preview Test Folder', + }, + ], + }, + modified_at: '2020-12-17T05:21:44-07:00', + created_at: '2020-11-12T12:33:22-07:00', + modified_by: { + type: 'user', + id: '7503712462', + name: 'Preview', + login: 'preview@boxdemo.com', + }, + has_collaborations: true, + is_externally_owned: false, + shared_link: null, + watermark_info: { + is_watermarked: false, + }, + archive_type: 'folder_archive', + }, { type: 'file', id: '416044542013', diff --git a/src/elements/content-explorer/stories/tests/ContentExplorer-visual.stories.js b/src/elements/content-explorer/stories/tests/ContentExplorer-visual.stories.js index 5a8d71a2d3..e8aee3a354 100644 --- a/src/elements/content-explorer/stories/tests/ContentExplorer-visual.stories.js +++ b/src/elements/content-explorer/stories/tests/ContentExplorer-visual.stories.js @@ -15,6 +15,12 @@ export const basic = { expect(await canvas.findByText('An Ordered Folder')).toBeInTheDocument(); expect(canvas.getByText('Tue Apr 16 2019 by Preview')).toBeInTheDocument(); + expect(canvas.getByText('Archive')).toBeInTheDocument(); + expect(canvas.getByText('Wed Dec 16 2020 by Preview')).toBeInTheDocument(); + + expect(canvas.getByText('Archived Folder')).toBeInTheDocument(); + expect(canvas.getByText('Thu Dec 17 2020 by Preview')).toBeInTheDocument(); + expect(canvas.getByText('Book Sample.pdf')).toBeInTheDocument(); expect(canvas.getByText('Thu Dec 8 2022 by Preview')).toBeInTheDocument(); }, diff --git a/src/features/content-explorer/item-list/ItemList.js b/src/features/content-explorer/item-list/ItemList.js index 5df1ac0ba3..a6df0a9f05 100644 --- a/src/features/content-explorer/item-list/ItemList.js +++ b/src/features/content-explorer/item-list/ItemList.js @@ -41,7 +41,7 @@ const TableResponsive = withAutoSizer(Table); const itemIconCellRenderer = rendererParams => { const { - rowData: { type, extension, hasCollaborations, isExternallyOwned }, + rowData: { type, extension, hasCollaborations, isExternallyOwned, archiveType }, columnData: { itemIconRenderer }, } = rendererParams; return ( @@ -54,6 +54,7 @@ const itemIconCellRenderer = rendererParams => { extension={extension} hasCollaborations={hasCollaborations} isExternallyOwned={isExternallyOwned} + archiveType={archiveType} /> )} diff --git a/src/features/content-explorer/item-list/ItemListIcon.js b/src/features/content-explorer/item-list/ItemListIcon.js index eae2e996d6..4d4a6fa00f 100644 --- a/src/features/content-explorer/item-list/ItemListIcon.js +++ b/src/features/content-explorer/item-list/ItemListIcon.js @@ -1,11 +1,17 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { ItemTypePropType } from '../prop-types'; +import { ItemTypePropType, ItemArchiveTypePropType } from '../prop-types'; import IconCell from '../../../elements/common/item/IconCell'; -const ItemListIcon = ({ type, extension, hasCollaborations = false, isExternallyOwned = false }) => { - const rowData = { type, extension, has_collaborations: hasCollaborations, is_externally_owned: isExternallyOwned }; +const ItemListIcon = ({ archiveType, extension, type, hasCollaborations = false, isExternallyOwned = false }) => { + const rowData = { + type, + extension, + has_collaborations: hasCollaborations, + is_externally_owned: isExternallyOwned, + archive_type: archiveType, + }; return ; }; @@ -14,6 +20,7 @@ ItemListIcon.propTypes = { extension: PropTypes.string, hasCollaborations: PropTypes.bool, isExternallyOwned: PropTypes.bool, + archiveType: ItemArchiveTypePropType, }; export default ItemListIcon; diff --git a/src/features/content-explorer/item-list/__tests__/ItemListIcon.test.js b/src/features/content-explorer/item-list/__tests__/ItemListIcon.test.js index 31cf7699cb..4c9fb409ae 100644 --- a/src/features/content-explorer/item-list/__tests__/ItemListIcon.test.js +++ b/src/features/content-explorer/item-list/__tests__/ItemListIcon.test.js @@ -1,71 +1,100 @@ import * as React from 'react'; import ItemListIcon from '../ItemListIcon'; +import { render, screen } from '../../../../test-utils/testing-library'; describe('features/content-explorer/item-list/ItemListIcon', () => { - const renderComponent = props => shallow(); + const renderComponent = props => render(); describe('render()', () => { - test('should render default component', () => { - const wrapper = renderComponent(); + test('should render default file icon', () => { + renderComponent({}); - expect(wrapper.find('IconCell').length).toBe(1); - expect(wrapper.prop('rowData')).toEqual({ - type: undefined, - extension: undefined, - has_collaborations: false, - is_externally_owned: false, - }); + expect(screen.getByTitle('File')).toBeInTheDocument(); }); - [ - // personalFolder - { + test('should render archive icon', () => { + const rowData = { type: 'folder', + archiveType: 'archive', hasCollaborations: false, isExternallyOwned: false, + }; + renderComponent(rowData); + + expect(screen.getByTestId('archive-icon-cell')).toBeVisible(); + }); + + test('should render archived folder icon', () => { + const rowData = { + type: 'folder', + archiveType: 'folder_archive', + hasCollaborations: false, + isExternallyOwned: false, + }; + renderComponent(rowData); + + expect(screen.getByTestId('folder-archive-icon-cell')).toBeVisible(); + }); + + [ + // personalFolder + { + rowData: { + type: 'folder', + hasCollaborations: false, + isExternallyOwned: false, + }, + title: 'Personal Folder', }, // collabFolder { - type: 'folder', - hasCollaborations: true, - isExternallyOwned: false, + rowData: { + type: 'folder', + hasCollaborations: true, + isExternallyOwned: false, + }, + title: 'Collaborated Folder', }, // externalCollabFolder { - type: 'folder', - hasCollaborations: true, - isExternallyOwned: true, + rowData: { + type: 'folder', + hasCollaborations: true, + isExternallyOwned: true, + }, + title: 'Collaborated Folder', }, // externalFolder { - type: 'folder', - hasCollaborations: false, - isExternallyOwned: true, + rowData: { + type: 'folder', + hasCollaborations: false, + isExternallyOwned: true, + }, + title: 'External Folder', }, - ].forEach(rowData => { + ].forEach(({ rowData, title }) => { test('should render correct folder icon', () => { - const wrapper = renderComponent(rowData); + renderComponent(rowData); - expect(wrapper.find('IconCell').length).toBe(1); - expect(wrapper).toMatchSnapshot(); + expect(screen.getByTitle(title)).toBeInTheDocument(); }); }); test('should render correct file icon', () => { - const rowData = { type: 'file', extension: 'boxnote' }; - const wrapper = renderComponent(rowData); + const extension = 'boxnote'; + const rowData = { type: 'file', extension }; + renderComponent(rowData); - expect(wrapper.find('IconCell').length).toBe(1); - expect(wrapper.prop('rowData')).toEqual(expect.objectContaining(rowData)); + expect(screen.getByTitle('File')).toBeInTheDocument(); }); test('should render correct bookmark icon', () => { const rowData = { type: 'web_link' }; - const wrapper = renderComponent(rowData); + renderComponent(rowData); - expect(wrapper.find('IconCell').length).toBe(1); - expect(wrapper.prop('rowData')).toEqual(expect.objectContaining(rowData)); + expect(screen.getByTitle('Bookmark')).toBeInTheDocument(); }); }); }); diff --git a/src/features/content-explorer/item-list/__tests__/__snapshots__/ItemListIcon.test.js.snap b/src/features/content-explorer/item-list/__tests__/__snapshots__/ItemListIcon.test.js.snap deleted file mode 100644 index 1682f696ec..0000000000 --- a/src/features/content-explorer/item-list/__tests__/__snapshots__/ItemListIcon.test.js.snap +++ /dev/null @@ -1,53 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`features/content-explorer/item-list/ItemListIcon render() should render correct folder icon 1`] = ` - -`; - -exports[`features/content-explorer/item-list/ItemListIcon render() should render correct folder icon 2`] = ` - -`; - -exports[`features/content-explorer/item-list/ItemListIcon render() should render correct folder icon 3`] = ` - -`; - -exports[`features/content-explorer/item-list/ItemListIcon render() should render correct folder icon 4`] = ` - -`; diff --git a/src/features/content-explorer/prop-types.js b/src/features/content-explorer/prop-types.js index 6024201f09..32c707d9af 100644 --- a/src/features/content-explorer/prop-types.js +++ b/src/features/content-explorer/prop-types.js @@ -1,7 +1,15 @@ import PropTypes from 'prop-types'; import ContentExplorerModes from './modes'; -import { TYPE_FILE, TYPE_FOLDER, TYPE_WEBLINK } from '../../constants'; +import { + TYPE_ARCHIVE, + TYPE_ARCHIVE_FILE, + TYPE_ARCHIVE_FOLDER, + TYPE_ARCHIVE_WEB_LINK, + TYPE_FILE, + TYPE_FOLDER, + TYPE_WEBLINK, +} from '../../constants'; const ContentExplorerModePropType = PropTypes.oneOf([ ContentExplorerModes.COPY, @@ -19,12 +27,19 @@ const FolderPropType = PropTypes.shape({ const FoldersPathPropType = PropTypes.arrayOf(FolderPropType); const ItemTypePropType = PropTypes.oneOf([TYPE_FILE, TYPE_FOLDER, TYPE_WEBLINK]); +const ItemArchiveTypePropType = PropTypes.oneOf([ + TYPE_ARCHIVE, + TYPE_ARCHIVE_FOLDER, + TYPE_ARCHIVE_WEB_LINK, + TYPE_ARCHIVE_FILE, +]); const ItemPropType = PropTypes.shape({ id: PropTypes.string.isRequired, type: ItemTypePropType, name: PropTypes.string.isRequired, label: PropTypes.string, + archiveType: ItemArchiveTypePropType, extension: PropTypes.string, hasCollaborations: PropTypes.bool, isExternallyOwned: PropTypes.bool, @@ -59,4 +74,5 @@ export { ItemPropType, ItemsPropType, ItemsMapPropType, + ItemArchiveTypePropType, };