Skip to content

Commit

Permalink
feat(item-list): add archive folder icon to content picker (#3763)
Browse files Browse the repository at this point in the history
* feat(item-list): add archive folder icons

* feat(item-list): change titles in blueprint icons to aria-labels

* feat(item-list): change icon cell folder icons

* feat(item-list): reorder props

* feat(item-list): update archive type

* feat(item-list): update visual regression tests

* feat(item-list): update storybook mocks

* feat(item-list): update changed tests to RTL
  • Loading branch information
michalkowalczyk-box authored Dec 6, 2024
1 parent d400d6c commit 1d4adab
Show file tree
Hide file tree
Showing 13 changed files with 290 additions and 109 deletions.
4 changes: 4 additions & 0 deletions i18n/en-US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/common/types/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ type SharedLinkFeatures = {

type BoxItem = {
allowed_shared_link_access_levels?: Array<Access>,
archive_type?: 'archive' | 'folder_archive' | 'file' | 'web_link',
authenticated_download_url?: string,
content_created_at?: string,
content_modified_at?: string,
Expand Down
6 changes: 6 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
25 changes: 24 additions & 1 deletion src/elements/common/item/IconCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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 <FileIcon dimension={dimension} extension={extension} title={title} />;
case TYPE_FOLDER:
if (is_archive) {
return (
<Archive
aria-label={intl.formatMessage(messages.archive)}
data-testid="archive-icon-cell"
height={dimension}
width={dimension}
/>
);
}
if (is_archive_folder) {
return (
<FolderArchive
aria-label={intl.formatMessage(messages.archivedFolder)}
data-testid="folder-archive-icon-cell"
height={dimension}
width={dimension}
/>
);
}
if (has_collaborations) {
title = intl.formatMessage(messages.collaboratedFolder);
} else if (is_externally_owned) {
Expand Down
51 changes: 34 additions & 17 deletions src/elements/common/item/__tests__/IconCell.test.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
import * as React from 'react';

import { render, screen } from '../../../../test-utils/testing-library';
import { IconCellBase as IconCell } from '../IconCell';

const intl = {
formatMessage: jest.fn().mockImplementation(message => message.defaultMessage),
};

describe('elements/common/item/IconCell', () => {
const getWrapper = props => shallow(<IconCell intl={intl} {...props} />);
const getWrapper = props => render(<IconCell intl={intl} {...props} />);

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();
});

[
Expand Down Expand Up @@ -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();
});
});
});
10 changes: 10 additions & 0 deletions src/elements/common/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
114 changes: 114 additions & 0 deletions src/elements/content-explorer/stories/__mocks__/mockRootFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
},
Expand Down
3 changes: 2 additions & 1 deletion src/features/content-explorer/item-list/ItemList.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -54,6 +54,7 @@ const itemIconCellRenderer = rendererParams => {
extension={extension}
hasCollaborations={hasCollaborations}
isExternallyOwned={isExternallyOwned}
archiveType={archiveType}
/>
)}
</div>
Expand Down
13 changes: 10 additions & 3 deletions src/features/content-explorer/item-list/ItemListIcon.js
Original file line number Diff line number Diff line change
@@ -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 <IconCell rowData={rowData} />;
};

Expand All @@ -14,6 +20,7 @@ ItemListIcon.propTypes = {
extension: PropTypes.string,
hasCollaborations: PropTypes.bool,
isExternallyOwned: PropTypes.bool,
archiveType: ItemArchiveTypePropType,
};

export default ItemListIcon;
Loading

0 comments on commit 1d4adab

Please sign in to comment.