refactor isSelectable usage + fix grid view selection

This commit is contained in:
Julie Plantey 2022-11-24 19:47:56 +01:00
parent 36cf9ea857
commit 1824d5f8be
12 changed files with 284 additions and 235 deletions

View File

@ -6,34 +6,21 @@ import { VideoAssetCard } from './VideoAssetCard';
import { DocAssetCard } from './DocAssetCard'; import { DocAssetCard } from './DocAssetCard';
import { AudioAssetCard } from './AudioAssetCard'; import { AudioAssetCard } from './AudioAssetCard';
import { AssetType, AssetDefinition } from '../../constants'; import { AssetType, AssetDefinition } from '../../constants';
import { createAssetUrl, toSingularTypes } from '../../utils'; import { createAssetUrl } from '../../utils';
export const AssetCard = ({ export const AssetCard = ({ asset, isSelected, onSelect, onEdit, onRemove, size, local }) => {
allowedTypes,
asset,
isSelected,
onSelect,
onEdit,
onRemove,
size,
local,
}) => {
const singularTypes = toSingularTypes(allowedTypes);
const fileType = asset.mime.split('/')[0];
const handleSelect = onSelect ? () => onSelect(asset) : undefined; const handleSelect = onSelect ? () => onSelect(asset) : undefined;
const canSelectAsset =
singularTypes.includes(fileType) ||
(singularTypes.includes('file') && !['video', 'image', 'audio'].includes(fileType));
const commonAssetCardProps = { const commonAssetCardProps = {
id: asset.id, id: asset.id,
isSelectable: asset.isSelectable,
extension: getFileExtension(asset.ext), extension: getFileExtension(asset.ext),
key: asset.id, key: asset.id,
name: asset.name, name: asset.name,
url: local ? asset.url : createAssetUrl(asset, true), url: local ? asset.url : createAssetUrl(asset, true),
mime: asset.mime, mime: asset.mime,
onEdit: onEdit ? () => onEdit(asset) : undefined, onEdit: onEdit ? () => onEdit(asset) : undefined,
onSelect: !canSelectAsset && !isSelected ? undefined : handleSelect, onSelect: handleSelect,
onRemove: onRemove ? () => onRemove(asset) : undefined, onRemove: onRemove ? () => onRemove(asset) : undefined,
selected: isSelected, selected: isSelected,
size, size,
@ -63,7 +50,6 @@ export const AssetCard = ({
}; };
AssetCard.defaultProps = { AssetCard.defaultProps = {
allowedTypes: ['images', 'files', 'videos', 'audios'],
isSelected: false, isSelected: false,
// Determine if the asset is loaded locally or from a remote resource // Determine if the asset is loaded locally or from a remote resource
local: false, local: false,
@ -74,7 +60,6 @@ AssetCard.defaultProps = {
}; };
AssetCard.propTypes = { AssetCard.propTypes = {
allowedTypes: PropTypes.array,
asset: AssetDefinition.isRequired, asset: AssetDefinition.isRequired,
local: PropTypes.bool, local: PropTypes.bool,
onSelect: PropTypes.func, onSelect: PropTypes.func,

View File

@ -44,12 +44,13 @@ const CardContainer = styled(Card)`
export const AssetCardBase = ({ export const AssetCardBase = ({
children, children,
name,
extension, extension,
selected, isSelectable,
name,
onSelect, onSelect,
onRemove, onRemove,
onEdit, onEdit,
selected,
subtitle, subtitle,
variant, variant,
}) => { }) => {
@ -76,7 +77,7 @@ export const AssetCardBase = ({
return ( return (
<CardContainer role="button" height="100%" tabIndex={-1} onClick={handleClick}> <CardContainer role="button" height="100%" tabIndex={-1} onClick={handleClick}>
<CardHeader> <CardHeader>
{onSelect && ( {isSelectable && (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<div onClick={handlePropagationClick}> <div onClick={handlePropagationClick}>
<CardCheckbox value={selected} onValueChange={onSelect} /> <CardCheckbox value={selected} onValueChange={onSelect} />
@ -129,10 +130,11 @@ export const AssetCardBase = ({
AssetCardBase.defaultProps = { AssetCardBase.defaultProps = {
children: undefined, children: undefined,
selected: false, isSelectable: true,
onEdit: undefined, onEdit: undefined,
onSelect: undefined, onSelect: undefined,
onRemove: undefined, onRemove: undefined,
selected: false,
subtitle: '', subtitle: '',
variant: 'Image', variant: 'Image',
}; };
@ -140,6 +142,7 @@ AssetCardBase.defaultProps = {
AssetCardBase.propTypes = { AssetCardBase.propTypes = {
children: PropTypes.node, children: PropTypes.node,
extension: PropTypes.string.isRequired, extension: PropTypes.string.isRequired,
isSelectable: PropTypes.bool,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
onEdit: PropTypes.func, onEdit: PropTypes.func,
onSelect: PropTypes.func, onSelect: PropTypes.func,

View File

@ -25,7 +25,7 @@ import {
localStorageKeys, localStorageKeys,
} from '../../../constants'; } from '../../../constants';
import getTrad from '../../../utils/getTrad'; import getTrad from '../../../utils/getTrad';
import { getBreadcrumbDataCM } from '../../../utils'; import { getBreadcrumbDataCM, toSingularTypes } from '../../../utils';
import getAllowedFiles from '../../../utils/getAllowedFiles'; import getAllowedFiles from '../../../utils/getAllowedFiles';
import { AssetGridList } from '../../AssetGridList'; import { AssetGridList } from '../../AssetGridList';
import { TableList } from '../../TableList'; import { TableList } from '../../TableList';
@ -39,6 +39,7 @@ import { Filters } from './Filters';
import PaginationFooter from './PaginationFooter'; import PaginationFooter from './PaginationFooter';
import PageSize from './PageSize'; import PageSize from './PageSize';
import SearchAsset from './SearchAsset'; import SearchAsset from './SearchAsset';
import { isSelectable } from './utils/isSelectable';
const StartBlockActions = styled(Flex)` const StartBlockActions = styled(Flex)`
& > * + * { & > * + * {
@ -65,7 +66,7 @@ const ActionContainer = styled(Box)`
export const BrowseStep = ({ export const BrowseStep = ({
allowedTypes, allowedTypes,
assets, assets: rawAssets,
canCreate, canCreate,
canRead, canRead,
folders, folders,
@ -96,6 +97,13 @@ export const BrowseStep = ({
} }
); );
const singularTypes = toSingularTypes(allowedTypes);
const assets = rawAssets.map((asset) => {
const fileType = asset?.mime?.split('/')?.[0];
return { ...asset, isSelectable: isSelectable(singularTypes, fileType) };
});
const breadcrumbs = !isCurrentFolderLoading && getBreadcrumbDataCM(currentFolder); const breadcrumbs = !isCurrentFolderLoading && getBreadcrumbDataCM(currentFolder);
const allAllowedAsset = getAllowedFiles(allowedTypes, assets); const allAllowedAsset = getAllowedFiles(allowedTypes, assets);
@ -249,10 +257,7 @@ export const BrowseStep = ({
// TODO: remove when fixed on DS side // TODO: remove when fixed on DS side
// when number of rows in Table changes, the keyboard tab from a row to another // when number of rows in Table changes, the keyboard tab from a row to another
// is not working for 1st and last column // is not working for 1st and last column
[ [...folders.map((folder) => ({ ...folder, type: 'folder' })), ...assets]
...folders.map((folder) => ({ ...folder, type: 'folder' })),
...assets.map((asset) => ({ ...asset, type: 'asset' })),
]
} }
selected={selectedAssets} selected={selectedAssets}
shouldDisableBulkSelect={!multiple} shouldDisableBulkSelect={!multiple}

View File

@ -0,0 +1,3 @@
export const isSelectable = (allowedTypes, fileType) =>
allowedTypes.includes(fileType) ||
(allowedTypes.includes('file') && !['video', 'image', 'audio'].includes(fileType));

View File

@ -0,0 +1,19 @@
import { isSelectable } from '../isSelectable';
describe('TableList | isSelectable', () => {
it('should return true if asset is an allowed file type', () => {
expect(isSelectable(['image', 'file', 'video', 'audio'], 'image')).toEqual(true);
});
it('should return true if asset type is not contained in allowed types array but file type is contained', () => {
expect(isSelectable(['video', 'audio', 'file'], 'pdf')).toEqual(true);
});
it('should return false if asset type is not contained in allowed types array and file type is image, video or audio', () => {
expect(isSelectable(['video', 'audio', 'file'], 'image')).toEqual(false);
expect(isSelectable(['image', 'audio', 'file'], 'video')).toEqual(false);
expect(isSelectable(['image', 'video', 'file'], 'audio')).toEqual(false);
});
});

View File

@ -11,14 +11,10 @@ import Pencil from '@strapi/icons/Pencil';
import Eye from '@strapi/icons/Eye'; import Eye from '@strapi/icons/Eye';
import { CellContent } from './CellContent'; import { CellContent } from './CellContent';
import { isSelectable } from './utils/isSelectable';
import { AssetDefinition, FolderDefinition, tableHeaders as cells } from '../../constants'; import { AssetDefinition, FolderDefinition, tableHeaders as cells } from '../../constants';
import { getTrad, toSingularTypes } from '../../utils'; import { getTrad } from '../../utils';
export const TableRows = ({ export const TableRows = ({
allowedTypes,
canUpdate,
isFolderSelectionAllowed,
onChangeFolder, onChangeFolder,
onEditAsset, onEditAsset,
onEditFolder, onEditFolder,
@ -36,14 +32,13 @@ export const TableRows = ({
} }
}; };
const singularTypes = toSingularTypes(allowedTypes);
return ( return (
<Tbody> <Tbody>
{rows.map((element) => { {rows.map((element) => {
const { const {
alternativeText, alternativeText,
id, id,
isSelectable,
name, name,
ext, ext,
url, url,
@ -53,10 +48,6 @@ export const TableRows = ({
type: elementType, type: elementType,
} = element; } = element;
const fileType = mime?.split('/')?.[0];
const canBeSelected =
isSelectable(singularTypes, elementType, fileType, isFolderSelectionAllowed) && canUpdate;
const isSelected = !!selected.find((currentRow) => currentRow.id === id); const isSelected = !!selected.find((currentRow) => currentRow.id === id);
return ( return (
@ -76,7 +67,7 @@ export const TableRows = ({
}, },
{ name } { name }
)} )}
disabled={!canBeSelected} disabled={!isSelectable}
onValueChange={() => onSelectOne(element)} onValueChange={() => onSelectOne(element)}
checked={isSelected} checked={isSelected}
/> />
@ -136,22 +127,16 @@ export const TableRows = ({
}; };
TableRows.defaultProps = { TableRows.defaultProps = {
allowedTypes: ['images', 'files', 'videos', 'audios'],
canUpdate: true,
onChangeFolder: null, onChangeFolder: null,
isFolderSelectionAllowed: true,
rows: [], rows: [],
selected: [], selected: [],
}; };
TableRows.propTypes = { TableRows.propTypes = {
allowedTypes: PropTypes.arrayOf(PropTypes.string),
canUpdate: PropTypes.bool,
isFolderSelectionAllowed: PropTypes.bool,
rows: PropTypes.arrayOf(AssetDefinition, FolderDefinition),
onChangeFolder: PropTypes.func, onChangeFolder: PropTypes.func,
onEditAsset: PropTypes.func.isRequired, onEditAsset: PropTypes.func.isRequired,
onEditFolder: PropTypes.func.isRequired, onEditFolder: PropTypes.func.isRequired,
onSelectOne: PropTypes.func.isRequired, onSelectOne: PropTypes.func.isRequired,
rows: PropTypes.arrayOf(AssetDefinition, FolderDefinition),
selected: PropTypes.arrayOf(AssetDefinition, FolderDefinition), selected: PropTypes.arrayOf(AssetDefinition, FolderDefinition),
}; };

View File

@ -15,9 +15,6 @@ import { TableRows } from './TableRows';
export const TableList = ({ export const TableList = ({
assetCount, assetCount,
isFolderSelectionAllowed,
allowedTypes,
canUpdate,
folderCount, folderCount,
indeterminate, indeterminate,
onChangeSort, onChangeSort,
@ -114,9 +111,6 @@ export const TableList = ({
</Tr> </Tr>
</Thead> </Thead>
<TableRows <TableRows
isFolderSelectionAllowed={isFolderSelectionAllowed}
allowedTypes={allowedTypes}
canUpdate={canUpdate}
onChangeFolder={onChangeFolder} onChangeFolder={onChangeFolder}
onEditAsset={onEditAsset} onEditAsset={onEditAsset}
onEditFolder={onEditFolder} onEditFolder={onEditFolder}
@ -130,11 +124,8 @@ export const TableList = ({
TableList.defaultProps = { TableList.defaultProps = {
assetCount: 0, assetCount: 0,
allowedTypes: ['images', 'files', 'videos', 'audios'],
canUpdate: true,
folderCount: 0, folderCount: 0,
indeterminate: false, indeterminate: false,
isFolderSelectionAllowed: true,
onChangeSort: null, onChangeSort: null,
onChangeFolder: null, onChangeFolder: null,
onEditAsset: null, onEditAsset: null,
@ -146,12 +137,9 @@ TableList.defaultProps = {
}; };
TableList.propTypes = { TableList.propTypes = {
allowedTypes: PropTypes.arrayOf(PropTypes.string),
assetCount: PropTypes.number, assetCount: PropTypes.number,
canUpdate: PropTypes.bool,
folderCount: PropTypes.number, folderCount: PropTypes.number,
indeterminate: PropTypes.bool, indeterminate: PropTypes.bool,
isFolderSelectionAllowed: PropTypes.bool,
onChangeSort: PropTypes.func, onChangeSort: PropTypes.func,
onChangeFolder: PropTypes.func, onChangeFolder: PropTypes.func,
onEditAsset: PropTypes.func, onEditAsset: PropTypes.func,

View File

@ -1,13 +0,0 @@
export const isSelectable = (allowedTypes, elementType, fileType, isFolderSelectionAllowed) => {
let canSelectElement;
if (elementType === 'folder') {
canSelectElement = isFolderSelectionAllowed;
} else {
canSelectElement =
allowedTypes.includes(fileType) ||
(allowedTypes.includes('file') && !['video', 'image', 'audio'].includes(fileType));
}
return canSelectElement;
};

View File

@ -1,74 +0,0 @@
import { isSelectable } from '../isSelectable';
const ALLOWED_TYPES_FIXTURE = ['image', 'file', 'video', 'audio'];
const ELEMENT_TYPE_FIXTURE = 'asset';
const FILE_TYPE_FIXTURE = 'image';
const IS_FOLDER_SELECTION_ALLOWED_FIXTURE = true;
describe('TableList | isSelectable', () => {
it('should return true if asset is an allowed file type', () => {
expect(
isSelectable(
ALLOWED_TYPES_FIXTURE,
ELEMENT_TYPE_FIXTURE,
FILE_TYPE_FIXTURE,
IS_FOLDER_SELECTION_ALLOWED_FIXTURE
)
).toEqual(true);
});
it('should return true if asset type is not contained in allowed types array but file type is contained', () => {
expect(
isSelectable(
['video', 'audio', 'file'],
ELEMENT_TYPE_FIXTURE,
'pdf',
IS_FOLDER_SELECTION_ALLOWED_FIXTURE
)
).toEqual(true);
});
it('should return false if asset type is not contained in allowed types array and file type is image, video or audio', () => {
expect(
isSelectable(
['video', 'audio', 'file'],
ELEMENT_TYPE_FIXTURE,
'image',
IS_FOLDER_SELECTION_ALLOWED_FIXTURE
)
).toEqual(false);
expect(
isSelectable(
['image', 'audio', 'file'],
ELEMENT_TYPE_FIXTURE,
'video',
IS_FOLDER_SELECTION_ALLOWED_FIXTURE
)
).toEqual(false);
expect(
isSelectable(
['image', 'video', 'file'],
ELEMENT_TYPE_FIXTURE,
'audio',
IS_FOLDER_SELECTION_ALLOWED_FIXTURE
)
).toEqual(false);
});
it('should return true if folder is allowed', () => {
expect(
isSelectable(
ALLOWED_TYPES_FIXTURE,
'folder',
FILE_TYPE_FIXTURE,
IS_FOLDER_SELECTION_ALLOWED_FIXTURE
)
).toEqual(true);
});
it('should return false if folder is not allowed', () => {
expect(isSelectable(ALLOWED_TYPES_FIXTURE, 'folder', FILE_TYPE_FIXTURE, false)).toEqual(false);
});
});

View File

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PendingAssetStep snapshots the component with valid cards 1`] = ` exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
.c52 { .c55 {
border: 0; border: 0;
-webkit-clip: rect(0 0 0 0); -webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0); clip: rect(0 0 0 0);
@ -48,33 +48,37 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
} }
.c24 { .c24 {
position: start;
}
.c29 {
position: end; position: end;
} }
.c32 { .c35 {
padding-top: 8px; padding-top: 8px;
padding-right: 12px; padding-right: 12px;
padding-bottom: 8px; padding-bottom: 8px;
padding-left: 12px; padding-left: 12px;
} }
.c35 { .c38 {
padding-top: 4px; padding-top: 4px;
} }
.c38 { .c41 {
background: #f6f6f9; background: #f6f6f9;
padding: 4px; padding: 4px;
border-radius: 4px; border-radius: 4px;
min-width: 20px; min-width: 20px;
} }
.c42 { .c45 {
width: 100%; width: 100%;
height: 5.5rem; height: 5.5rem;
} }
.c46 { .c49 {
background: #32324d; background: #32324d;
color: #ffffff; color: #ffffff;
padding: 4px; padding: 4px;
@ -145,7 +149,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
flex-direction: row; flex-direction: row;
} }
.c33 { .c36 {
-webkit-align-items: flex-start; -webkit-align-items: flex-start;
-webkit-box-align: flex-start; -webkit-box-align: flex-start;
-ms-flex-align: flex-start; -ms-flex-align: flex-start;
@ -159,7 +163,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
flex-direction: row; flex-direction: row;
} }
.c39 { .c42 {
-webkit-align-items: center; -webkit-align-items: center;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
@ -205,7 +209,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
color: #32324d; color: #32324d;
} }
.c41 { .c44 {
font-weight: 600; font-weight: 600;
font-size: 0.6875rem; font-size: 0.6875rem;
line-height: 1.45; line-height: 1.45;
@ -213,7 +217,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
color: #666687; color: #666687;
} }
.c48 { .c51 {
font-size: 0.75rem; font-size: 0.75rem;
line-height: 1.33; line-height: 1.33;
color: #ffffff; color: #ffffff;
@ -370,7 +374,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
fill: #ffffff; fill: #ffffff;
} }
.c51 { .c54 {
-webkit-align-items: center; -webkit-align-items: center;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
@ -384,7 +388,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
background: #ffffff; background: #ffffff;
} }
.c51 .c0 { .c54 .c0 {
display: -webkit-box; display: -webkit-box;
display: -webkit-flex; display: -webkit-flex;
display: -ms-flexbox; display: -ms-flexbox;
@ -395,55 +399,123 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
align-items: center; align-items: center;
} }
.c51 .c4 { .c54 .c4 {
color: #ffffff; color: #ffffff;
} }
.c51[aria-disabled='true'] { .c54[aria-disabled='true'] {
border: 1px solid #dcdce4; border: 1px solid #dcdce4;
background: #eaeaef; background: #eaeaef;
} }
.c51[aria-disabled='true'] .c4 { .c54[aria-disabled='true'] .c4 {
color: #666687; color: #666687;
} }
.c51[aria-disabled='true'] svg > g, .c54[aria-disabled='true'] svg > g,
.c51[aria-disabled='true'] svg path { .c54[aria-disabled='true'] svg path {
fill: #666687; fill: #666687;
} }
.c51[aria-disabled='true']:active { .c54[aria-disabled='true']:active {
border: 1px solid #dcdce4; border: 1px solid #dcdce4;
background: #eaeaef; background: #eaeaef;
} }
.c51[aria-disabled='true']:active .c4 { .c54[aria-disabled='true']:active .c4 {
color: #666687; color: #666687;
} }
.c51[aria-disabled='true']:active svg > g, .c54[aria-disabled='true']:active svg > g,
.c51[aria-disabled='true']:active svg path { .c54[aria-disabled='true']:active svg path {
fill: #666687; fill: #666687;
} }
.c51:hover { .c54:hover {
background-color: #f6f6f9; background-color: #f6f6f9;
} }
.c51:active { .c54:active {
background-color: #eaeaef; background-color: #eaeaef;
} }
.c51 .c4 { .c54 .c4 {
color: #32324d; color: #32324d;
} }
.c51 svg > g, .c54 svg > g,
.c51 svg path { .c54 svg path {
fill: #32324d; fill: #32324d;
} }
.c28 {
margin: 0;
height: 18px;
min-width: 18px;
border-radius: 4px;
border: 1px solid #c0c0cf;
-webkit-appearance: none;
background-color: #ffffff;
cursor: pointer;
}
.c28:checked {
background-color: #4945ff;
border: 1px solid #4945ff;
}
.c28:checked:after {
content: '';
display: block;
position: relative;
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iOCIgdmlld0JveD0iMCAwIDEwIDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGgKICAgIGQ9Ik04LjU1MzIzIDAuMzk2OTczQzguNjMxMzUgMC4zMTYzNTUgOC43NjA1MSAwLjMxNTgxMSA4LjgzOTMxIDAuMzk1NzY4TDkuODYyNTYgMS40MzQwN0M5LjkzODkzIDEuNTExNTcgOS45MzkzNSAxLjYzNTkgOS44NjM0OSAxLjcxMzlMNC4wNjQwMSA3LjY3NzI0QzMuOTg1OSA3Ljc1NzU1IDMuODU3MDcgNy43NTgwNSAzLjc3ODM0IDcuNjc4MzRMMC4xMzg2NiAzLjk5MzMzQzAuMDYxNzc5OCAzLjkxNTQ5IDAuMDYxNzEwMiAzLjc5MDMyIDAuMTM4NTA0IDMuNzEyNEwxLjE2MjEzIDIuNjczNzJDMS4yNDAzOCAyLjU5NDMyIDEuMzY4NDMgMi41OTQyMiAxLjQ0NjggMi42NzM0OEwzLjkyMTc0IDUuMTc2NDdMOC41NTMyMyAwLjM5Njk3M1oiCiAgICBmaWxsPSJ3aGl0ZSIKICAvPgo8L3N2Zz4=) no-repeat no-repeat center center;
width: 10px;
height: 10px;
left: 50%;
top: 50%;
-webkit-transform: translateX(-50%) translateY(-50%);
-ms-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
.c28:checked:disabled:after {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iOCIgdmlld0JveD0iMCAwIDEwIDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGgKICAgIGQ9Ik04LjU1MzIzIDAuMzk2OTczQzguNjMxMzUgMC4zMTYzNTUgOC43NjA1MSAwLjMxNTgxMSA4LjgzOTMxIDAuMzk1NzY4TDkuODYyNTYgMS40MzQwN0M5LjkzODkzIDEuNTExNTcgOS45MzkzNSAxLjYzNTkgOS44NjM0OSAxLjcxMzlMNC4wNjQwMSA3LjY3NzI0QzMuOTg1OSA3Ljc1NzU1IDMuODU3MDcgNy43NTgwNSAzLjc3ODM0IDcuNjc4MzRMMC4xMzg2NiAzLjk5MzMzQzAuMDYxNzc5OCAzLjkxNTQ5IDAuMDYxNzEwMiAzLjc5MDMyIDAuMTM4NTA0IDMuNzEyNEwxLjE2MjEzIDIuNjczNzJDMS4yNDAzOCAyLjU5NDMyIDEuMzY4NDMgMi41OTQyMiAxLjQ0NjggMi42NzM0OEwzLjkyMTc0IDUuMTc2NDdMOC41NTMyMyAwLjM5Njk3M1oiCiAgICBmaWxsPSIjOEU4RUE5IgogIC8+Cjwvc3ZnPg==) no-repeat no-repeat center center;
}
.c28:disabled {
background-color: #dcdce4;
border: 1px solid #c0c0cf;
}
.c28:indeterminate {
background-color: #4945ff;
border: 1px solid #4945ff;
}
.c28:indeterminate:after {
content: '';
display: block;
position: relative;
color: white;
height: 2px;
width: 10px;
background-color: #ffffff;
left: 50%;
top: 50%;
-webkit-transform: translateX(-50%) translateY(-50%);
-ms-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
.c28:indeterminate:disabled {
background-color: #dcdce4;
border: 1px solid #c0c0cf;
}
.c28:indeterminate:disabled:after {
background-color: #8e8ea9;
}
.c7 { .c7 {
display: -webkit-box; display: -webkit-box;
display: -webkit-flex; display: -webkit-flex;
@ -489,12 +561,12 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
border-bottom: 1px solid #eaeaef; border-bottom: 1px solid #eaeaef;
} }
.c49 { .c52 {
border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px;
border-top: 1px solid #eaeaef; border-top: 1px solid #eaeaef;
} }
.c50 > * + * { .c53 > * + * {
margin-left: 8px; margin-left: 8px;
} }
@ -514,13 +586,19 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
max-width: 100%; max-width: 100%;
} }
.c28 { .c27 {
position: absolute;
top: 12px;
left: 12px;
}
.c31 {
position: absolute; position: absolute;
top: 12px; top: 12px;
right: 12px; right: 12px;
} }
.c31 { .c34 {
margin: 0; margin: 0;
padding: 0; padding: 0;
max-height: 100%; max-height: 100%;
@ -528,7 +606,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
object-fit: contain; object-fit: contain;
} }
.c30 { .c33 {
display: -webkit-box; display: -webkit-box;
display: -webkit-flex; display: -webkit-flex;
display: -ms-flexbox; display: -ms-flexbox;
@ -544,18 +622,18 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
border-top-right-radius: 4px; border-top-right-radius: 4px;
} }
.c37 { .c40 {
margin-left: auto; margin-left: auto;
-webkit-flex-shrink: 0; -webkit-flex-shrink: 0;
-ms-flex-negative: 0; -ms-flex-negative: 0;
flex-shrink: 0; flex-shrink: 0;
} }
.c40 { .c43 {
margin-left: 4px; margin-left: 4px;
} }
.c34 { .c37 {
word-break: break-all; word-break: break-all;
} }
@ -564,21 +642,21 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
border-bottom: 1px solid #eaeaef; border-bottom: 1px solid #eaeaef;
} }
.c47 { .c50 {
position: absolute; position: absolute;
bottom: 4px; bottom: 4px;
right: 4px; right: 4px;
} }
.c36 { .c39 {
text-transform: uppercase; text-transform: uppercase;
} }
.c29 { .c32 {
opacity: 0; opacity: 0;
} }
.c29:focus-within { .c32:focus-within {
opacity: 1; opacity: 1;
} }
@ -586,22 +664,22 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
cursor: pointer; cursor: pointer;
} }
.c21:hover .c27 { .c21:hover .c30 {
opacity: 1; opacity: 1;
} }
.c45 canvas, .c48 canvas,
.c45 video { .c48 video {
display: block; display: block;
max-width: 100%; max-width: 100%;
max-height: 5.5rem; max-height: 5.5rem;
} }
.c44 svg { .c47 svg {
font-size: 3rem; font-size: 3rem;
} }
.c43 { .c46 {
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
background: linear-gradient(180deg,#ffffff 0%,#f6f6f9 121.48%); background: linear-gradient(180deg,#ffffff 0%,#f6f6f9 121.48%);
} }
@ -717,8 +795,24 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
<div <div
class="c0 c22 c23" class="c0 c22 c23"
> >
<div>
<div <div
class="c0 c24 c25 c26 c27 c28 c29" class="c0 c24 c25 c26 c27"
spacing="2"
>
<div
class="c0 "
>
<input
aria-labelledby="card-1-title"
class="c28"
type="checkbox"
/>
</div>
</div>
</div>
<div
class="c0 c29 c25 c26 c30 c31 c32"
spacing="2" spacing="2"
> >
<span> <span>
@ -783,27 +877,27 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</span> </span>
</div> </div>
<div <div
class="c30" class="c33"
> >
<img <img
alt="something.jpg" alt="something.jpg"
aria-hidden="true" aria-hidden="true"
class="c31" class="c34"
src="http://localhost:5000/CPAM.jpg" src="http://localhost:5000/CPAM.jpg"
/> />
</div> </div>
</div> </div>
<div
class="c0 c32"
>
<div
class="c0 c33"
>
<div
class="c0 c34"
>
<div <div
class="c0 c35" class="c0 c35"
>
<div
class="c0 c36"
>
<div
class="c0 c37"
>
<div
class="c0 c38"
> >
<h2 <h2
class="c4 c14" class="c4 c14"
@ -816,7 +910,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
class="c4 c15" class="c4 c15"
> >
<span <span
class="c36" class="c39"
> >
jpg jpg
</span> </span>
@ -824,13 +918,13 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</div> </div>
</div> </div>
<div <div
class="c37" class="c40"
> >
<div <div
class="c0 c38 c39 c40" class="c0 c41 c42 c43"
> >
<span <span
class="c4 c41" class="c4 c44"
> >
Image Image
</span> </span>
@ -857,8 +951,24 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
<div <div
class="c0 c22 c23" class="c0 c22 c23"
> >
<div>
<div <div
class="c0 c24 c25 c26 c27 c28 c29" class="c0 c24 c25 c26 c27"
spacing="2"
>
<div
class="c0 "
>
<input
aria-labelledby="card-6-title"
class="c28"
type="checkbox"
/>
</div>
</div>
</div>
<div
class="c0 c29 c25 c26 c30 c31 c32"
spacing="2" spacing="2"
> >
<span> <span>
@ -923,12 +1033,12 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</span> </span>
</div> </div>
<div <div
class="c0 c42 c22 c43" class="c0 c45 c22 c46"
height="5.5rem" height="5.5rem"
width="100%" width="100%"
> >
<span <span
class="c44" class="c47"
> >
<svg <svg
aria-label="something.pdf" aria-label="something.pdf"
@ -952,17 +1062,17 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</span> </span>
</div> </div>
</div> </div>
<div
class="c0 c32"
>
<div
class="c0 c33"
>
<div
class="c0 c34"
>
<div <div
class="c0 c35" class="c0 c35"
>
<div
class="c0 c36"
>
<div
class="c0 c37"
>
<div
class="c0 c38"
> >
<h2 <h2
class="c4 c14" class="c4 c14"
@ -975,7 +1085,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
class="c4 c15" class="c4 c15"
> >
<span <span
class="c36" class="c39"
> >
pdf pdf
</span> </span>
@ -983,13 +1093,13 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</div> </div>
</div> </div>
<div <div
class="c37" class="c40"
> >
<div <div
class="c0 c38 c39 c40" class="c0 c41 c42 c43"
> >
<span <span
class="c4 c41" class="c4 c44"
> >
Doc Doc
</span> </span>
@ -1016,8 +1126,24 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
<div <div
class="c0 c22 c23" class="c0 c22 c23"
> >
<div>
<div <div
class="c0 c24 c25 c26 c27 c28 c29" class="c0 c24 c25 c26 c27"
spacing="2"
>
<div
class="c0 "
>
<input
aria-labelledby="card-11-title"
class="c28"
type="checkbox"
/>
</div>
</div>
</div>
<div
class="c0 c29 c25 c26 c30 c31 c32"
spacing="2" spacing="2"
> >
<span> <span>
@ -1082,13 +1208,13 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</span> </span>
</div> </div>
<div <div
class="c30" class="c33"
> >
<div <div
class="c0 c25" class="c0 c25"
> >
<div <div
class="c0 c45" class="c0 c48"
> >
<figure <figure
class="c0 " class="c0 "
@ -1111,26 +1237,26 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</div> </div>
</div> </div>
<time <time
class="c0 c46 c47" class="c0 c49 c50"
> >
<span <span
class="c4 c48" class="c4 c51"
> >
... ...
</span> </span>
</time> </time>
</div> </div>
<div
class="c0 c32"
>
<div
class="c0 c33"
>
<div
class="c0 c34"
>
<div <div
class="c0 c35" class="c0 c35"
>
<div
class="c0 c36"
>
<div
class="c0 c37"
>
<div
class="c0 c38"
> >
<h2 <h2
class="c4 c14" class="c4 c14"
@ -1143,7 +1269,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
class="c4 c15" class="c4 c15"
> >
<span <span
class="c36" class="c39"
> >
mp4 mp4
</span> </span>
@ -1151,13 +1277,13 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</div> </div>
</div> </div>
<div <div
class="c37" class="c40"
> >
<div <div
class="c0 c38 c39 c40" class="c0 c41 c42 c43"
> >
<span <span
class="c4 c41" class="c4 c44"
> >
Video Video
</span> </span>
@ -1173,17 +1299,17 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</div> </div>
</div> </div>
<div <div
class="c0 c1 c49" class="c0 c1 c52"
> >
<div <div
class="c0 c3" class="c0 c3"
> >
<div <div
class="c0 c25 c50" class="c0 c25 c53"
> >
<button <button
aria-disabled="false" aria-disabled="false"
class="c6 c51" class="c6 c54"
type="button" type="button"
> >
<span <span
@ -1194,7 +1320,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</button> </button>
</div> </div>
<div <div
class="c0 c25 c50" class="c0 c25 c53"
> >
<button <button
aria-disabled="false" aria-disabled="false"
@ -1212,7 +1338,7 @@ exports[`PendingAssetStep snapshots the component with valid cards 1`] = `
</div> </div>
</form> </form>
<div <div
class="c52" class="c55"
> >
<p <p
aria-live="polite" aria-live="polite"

View File

@ -124,9 +124,12 @@ export const MediaLibrary = () => {
...folder, ...folder,
type: 'folder', type: 'folder',
folderURL: getFolderURL(pathname, query, folder.id), folderURL: getFolderURL(pathname, query, folder.id),
isSelectable: canUpdate,
})) ?? []; })) ?? [];
const folderCount = folders?.length || 0; const folderCount = folders?.length || 0;
const assets = assetsData?.results?.map((asset) => ({ ...asset, type: 'asset' })) || []; const assets =
assetsData?.results?.map((asset) => ({ ...asset, type: 'asset', isSelectable: canUpdate })) ||
[];
const assetCount = assets?.length ?? 0; const assetCount = assets?.length ?? 0;
const isLoading = isCurrentFolderLoading || foldersLoading || permissionsLoading || assetsLoading; const isLoading = isCurrentFolderLoading || foldersLoading || permissionsLoading || assetsLoading;
@ -278,9 +281,7 @@ export const MediaLibrary = () => {
{canRead && !isGridView && (assetCount > 0 || folderCount > 0) && ( {canRead && !isGridView && (assetCount > 0 || folderCount > 0) && (
<TableList <TableList
assetCount={assetCount} assetCount={assetCount}
canUpdate={canUpdate}
folderCount={folderCount} folderCount={folderCount}
// folderURL={getFolderURL(pathname, query, folderID)}
indeterminate={indeterminateBulkSelect} indeterminate={indeterminateBulkSelect}
onChangeSort={handleChangeSort} onChangeSort={handleChangeSort}
onChangeFolder={(folderID) => push(getFolderURL(pathname, query, folderID))} onChangeFolder={(folderID) => push(getFolderURL(pathname, query, folderID))}
@ -339,13 +340,13 @@ export const MediaLibrary = () => {
id={`folder-${folder.id}`} id={`folder-${folder.id}`}
to={url} to={url}
startAction={ startAction={
selectOne && ( selectOne && folder.isSelectable ? (
<FolderCardCheckbox <FolderCardCheckbox
data-testid={`folder-checkbox-${folder.id}`} data-testid={`folder-checkbox-${folder.id}`}
value={isSelected} value={isSelected}
onChange={() => selectOne(folder)} onChange={() => selectOne(folder)}
/> />
) ) : undefined
} }
cardActions={ cardActions={
<IconButton <IconButton

View File

@ -225,6 +225,11 @@ describe('Media library homepage', () => {
}); });
it('hides the select all button when the user is not allowed to update', () => { it('hides the select all button when the user is not allowed to update', () => {
useMediaLibraryPermissions.mockReturnValueOnce({
canUpdate: true,
canRead: true,
canCreate: true,
});
useMediaLibraryPermissions.mockReturnValue({ useMediaLibraryPermissions.mockReturnValue({
isLoading: false, isLoading: false,
canRead: true, canRead: true,
@ -260,6 +265,11 @@ describe('Media library homepage', () => {
describe('create folder', () => { describe('create folder', () => {
it('shows the create button if the user has create permissions', () => { it('shows the create button if the user has create permissions', () => {
useMediaLibraryPermissions.mockReturnValueOnce({
canUpdate: true,
canRead: true,
canCreate: true,
});
renderML(); renderML();
expect(screen.getByText('Add new folder')).toBeInTheDocument(); expect(screen.getByText('Add new folder')).toBeInTheDocument();
}); });
@ -353,6 +363,11 @@ describe('Media library homepage', () => {
}); });
it('displays folder with checked checkbox when is selected', () => { it('displays folder with checked checkbox when is selected', () => {
useMediaLibraryPermissions.mockReturnValueOnce({
canUpdate: true,
canRead: true,
canCreate: true,
});
useSelectionState.mockReturnValueOnce([ useSelectionState.mockReturnValueOnce([
[ [
{ {
@ -374,7 +389,13 @@ describe('Media library homepage', () => {
}); });
it('doest not displays folder with checked checkbox when is not selected', () => { it('doest not displays folder with checked checkbox when is not selected', () => {
useMediaLibraryPermissions.mockReturnValueOnce({
canUpdate: true,
canRead: true,
canCreate: true,
});
renderML(); renderML();
expect(screen.getByTestId('folder-checkbox-1')).not.toBeChecked(); expect(screen.getByTestId('folder-checkbox-1')).not.toBeChecked();
}); });