({
...jest.requireActual('@strapi/helper-plugin'),
useTracking: jest.fn(() => ({ trackUsage: jest.fn() })),
@@ -62,38 +67,50 @@ const FIXTURE_FOLDERS = [
},
];
+const client = new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: false,
+ },
+ },
+});
+
const ComponentFixture = props => {
return (
-
-
-
-
-
-
-
+
+
+
+
+ {}}>
+
+
+
+
+
+
);
};
const setup = props => render();
-
describe('BrowseStep', () => {
afterEach(() => {
jest.clearAllMocks();
@@ -101,14 +118,37 @@ describe('BrowseStep', () => {
it('renders and match snapshot', () => {
const { container } = setup();
-
expect(container).toMatchSnapshot();
});
+ it('should not fetch folder if the user does not have the permission', () => {
+ const spy = jest.fn().mockReturnValueOnce({ isLoading: false });
+ useFolder.mockImplementationOnce(spy);
+
+ setup({
+ canRead: false,
+ queryObject: { folder: 1, page: 1, pageSize: 10, filters: { $and: [] } },
+ });
+
+ expect(spy).toHaveBeenCalledWith(1, { enabled: false });
+ });
+
+ it('should show breadcrumbs navigation', () => {
+ setup();
+
+ expect(screen.queryByLabelText('Folders navigation')).toBeInTheDocument();
+ });
+
+ it('should hide breadcrumbs navigation if in root folder', () => {
+ useFolder.mockReturnValueOnce({ isLoading: false, data: undefined });
+ setup();
+
+ expect(screen.queryByLabelText('Folders navigation')).not.toBeInTheDocument();
+ });
+
it('calls onAddAsset callback', () => {
const spy = jest.fn();
const { getByText } = setup({ onAddAsset: spy, folders: [] });
-
fireEvent.click(getByText('Add new assets'));
expect(spy).toHaveBeenCalled();
});
@@ -116,19 +156,16 @@ describe('BrowseStep', () => {
it('calls onChangeFolder callback', () => {
const spy = jest.fn();
const { getByRole } = setup({ onChangeFolder: spy });
-
fireEvent.click(
getByRole('button', {
name: /folder 1 : 1 folder, 1 asset/i,
})
);
-
expect(spy).toHaveBeenCalled();
});
it('does display empty state upload first assets if no folder or assets', () => {
setup({ folders: [], assets: [] });
-
expect(screen.getByText('Upload your first assets...')).toBeInTheDocument();
});
@@ -138,7 +175,6 @@ describe('BrowseStep', () => {
assets: [],
queryObject: { page: 1, pageSize: 10, filters: { $and: [] }, _q: 'true' },
});
-
expect(screen.getByText('There are no assets with the applied filters')).toBeInTheDocument();
});
@@ -148,7 +184,6 @@ describe('BrowseStep', () => {
assets: [],
queryObject: { page: 1, pageSize: 10, filters: { $and: [{ mime: 'audio' }] }, _q: '' },
});
-
expect(screen.getByText('Filters')).toBeInTheDocument();
});
@@ -158,7 +193,6 @@ describe('BrowseStep', () => {
assets: FIXTURE_ASSETS,
queryObject: { page: 1, pageSize: 10, filters: { $and: [] }, _q: 'true' },
});
-
expect(screen.queryByText('Assets')).not.toBeInTheDocument();
});
@@ -166,7 +200,6 @@ describe('BrowseStep', () => {
setup({
queryObject: { page: 1, pageSize: 10, filters: { $and: [] }, _q: 'true' },
});
-
expect(screen.queryByText('Folders')).not.toBeInTheDocument();
});
@@ -175,7 +208,7 @@ describe('BrowseStep', () => {
assets: FIXTURE_ASSETS,
});
- expect(screen.getByText('Folders')).toBeInTheDocument();
- expect(screen.getByText('Assets')).toBeInTheDocument();
+ expect(screen.getByText('Folders (1)')).toBeInTheDocument();
+ expect(screen.getByText('Assets (1)')).toBeInTheDocument();
});
});
diff --git a/packages/core/upload/admin/src/components/AssetDialog/DialogHeader.js b/packages/core/upload/admin/src/components/AssetDialog/DialogHeader.js
deleted file mode 100644
index 2c1726d011..0000000000
--- a/packages/core/upload/admin/src/components/AssetDialog/DialogHeader.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import React from 'react';
-import styled from 'styled-components';
-import PropTypes from 'prop-types';
-import { useIntl } from 'react-intl';
-import { Breadcrumbs, Crumb } from '@strapi/design-system/Breadcrumbs';
-import { ModalHeader } from '@strapi/design-system/ModalLayout';
-import { Stack } from '@strapi/design-system/Stack';
-import { Icon } from '@strapi/design-system/Icon';
-import ArrowLeft from '@strapi/icons/ArrowLeft';
-import { findRecursiveFolderMetadatas, getTrad } from '../../utils';
-import { useFolderStructure } from '../../hooks/useFolderStructure';
-
-const BackButton = styled.button`
- height: ${({ theme }) => theme.spaces[4]};
- color: ${({ theme }) => theme.colors.neutral500};
-
- &:hover,
- &:focus {
- color: ${({ theme }) => theme.colors.neutral600};
- }
-`;
-
-const BackIcon = styled(Icon)`
- path {
- fill: currentColor;
- }
-`;
-
-export const DialogHeader = ({ currentFolder, onChangeFolder, canRead }) => {
- const { formatMessage } = useIntl();
-
- const { data, isLoading } = useFolderStructure({
- enabled: canRead,
- });
-
- const folderMetadatas =
- !isLoading && Array.isArray(data) && findRecursiveFolderMetadatas(data[0], currentFolder);
- const folderLabel =
- folderMetadatas?.currentFolderLabel &&
- (folderMetadatas.currentFolderLabel.length > 60
- ? `${folderMetadatas.currentFolderLabel.slice(0, 60)}...`
- : folderMetadatas.currentFolderLabel);
-
- return (
-
-
- {currentFolder && (
- onChangeFolder(folderMetadatas?.parentId)}
- >
-
-
- )}
-
-
- {formatMessage({
- id: getTrad('header.actions.add-assets'),
- defaultMessage: 'Add new assets',
- })}
-
- {folderLabel && {folderLabel}}
-
-
-
- );
-};
-
-DialogHeader.defaultProps = {
- currentFolder: undefined,
- onChangeFolder: undefined,
-};
-
-DialogHeader.propTypes = {
- canRead: PropTypes.bool.isRequired,
- currentFolder: PropTypes.number,
- onChangeFolder: PropTypes.func,
-};
diff --git a/packages/core/upload/admin/src/components/AssetDialog/index.js b/packages/core/upload/admin/src/components/AssetDialog/index.js
index b11567c659..d27c7cadae 100644
--- a/packages/core/upload/admin/src/components/AssetDialog/index.js
+++ b/packages/core/upload/admin/src/components/AssetDialog/index.js
@@ -1,17 +1,17 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
-import { ModalLayout, ModalBody } from '@strapi/design-system/ModalLayout';
+import { useIntl } from 'react-intl';
+import { ModalLayout, ModalBody, ModalHeader } from '@strapi/design-system/ModalLayout';
import { Flex } from '@strapi/design-system/Flex';
import { Button } from '@strapi/design-system/Button';
import { Divider } from '@strapi/design-system/Divider';
-import { useIntl } from 'react-intl';
+import { Typography } from '@strapi/design-system/Typography';
import { Tabs, Tab, TabGroup, TabPanels, TabPanel } from '@strapi/design-system/Tabs';
import { Badge } from '@strapi/design-system/Badge';
import { Loader } from '@strapi/design-system/Loader';
import { Stack } from '@strapi/design-system/Stack';
import { NoPermissions, AnErrorOccurred, useSelectionState, pxToRem } from '@strapi/helper-plugin';
-
import { getTrad, containsAssetFilter } from '../../utils';
import { SelectedStep } from './SelectedStep';
import { BrowseStep } from './BrowseStep';
@@ -21,7 +21,6 @@ import { useFolders } from '../../hooks/useFolders';
import useModalQueryParams from '../../hooks/useModalQueryParams';
import { AssetDefinition } from '../../constants';
import getAllowedFiles from '../../utils/getAllowedFiles';
-import { DialogHeader } from './DialogHeader';
import { DialogFooter } from './DialogFooter';
import { EditAssetDialog } from '../EditAssetDialog';
import { moveElement } from '../../utils/moveElement';
@@ -55,6 +54,7 @@ export const AssetDialog = ({
canCopyLink,
canDownload,
} = useMediaLibraryPermissions();
+
const [
{ queryObject },
{
@@ -66,11 +66,13 @@ export const AssetDialog = ({
onChangeFolder: onChangeFolderParam,
},
] = useModalQueryParams({ folder: folderId });
+
const {
data: { pagination, results: assets } = {},
isLoading: isLoadingAssets,
error: errorAssets,
} = useAssets({ skipWhen: !canRead, query: queryObject });
+
const { data: folders, isLoading: isLoadingFolders, error: errorFolders } = useFolders({
enabled: canRead && !containsAssetFilter(queryObject) && pagination?.page === 1,
query: queryObject,
@@ -84,6 +86,7 @@ export const AssetDialog = ({
const [initialSelectedTabIndex, setInitialSelectedTabIndex] = useState(
selectedAssets.length > 0 ? 1 : 0
);
+
const handleSelectAllAssets = () => {
const hasAllAssets = assets.every(
asset => selectedAssets.findIndex(curr => curr.id === asset.id) !== -1
@@ -97,6 +100,7 @@ export const AssetDialog = ({
return multiple ? selectAll(allowedAssets) : undefined;
};
+
const handleSelectAsset = asset => {
return multiple ? selectOne(asset) : selectOnly(asset);
};
@@ -107,11 +111,18 @@ export const AssetDialog = ({
if (isLoading) {
return (
-
+
+
+ {formatMessage({
+ id: getTrad('header.actions.add-assets'),
+ defaultMessage: 'Add new assets',
+ })}
+
+
{formatMessage({
- id: getTrad('list.asset.load'),
+ id: getTrad('content.isLoading'),
defaultMessage: 'Content is loading.',
})}
@@ -124,7 +135,14 @@ export const AssetDialog = ({
if (hasError) {
return (
-
+
+
+ {formatMessage({
+ id: getTrad('header.actions.add-assets'),
+ defaultMessage: 'Add new assets',
+ })}
+
+
@@ -134,7 +152,14 @@ export const AssetDialog = ({
if (!canRead) {
return (
-
+
+
+ {formatMessage({
+ id: getTrad('header.actions.add-assets'),
+ defaultMessage: 'Add new assets',
+ })}
+
+
@@ -168,7 +193,6 @@ export const AssetDialog = ({
const offset = destIndex - hoverIndex;
const orderedAssetsClone = selectedAssets.slice();
const nextAssets = moveElement(orderedAssetsClone, hoverIndex, offset);
-
setSelections(nextAssets);
};
@@ -179,11 +203,14 @@ export const AssetDialog = ({
return (
-
+
+
+ {formatMessage({
+ id: getTrad('header.actions.add-assets'),
+ defaultMessage: 'Add new assets',
+ })}
+
+
{selectedAssets.length}
-
-
onValidate(selectedAssets)} />
);
diff --git a/packages/core/upload/admin/src/components/AssetDialog/tests/DialogHeader.test.js b/packages/core/upload/admin/src/components/AssetDialog/tests/DialogHeader.test.js
deleted file mode 100644
index 1cb6f66993..0000000000
--- a/packages/core/upload/admin/src/components/AssetDialog/tests/DialogHeader.test.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import React from 'react';
-import { ThemeProvider, lightTheme } from '@strapi/design-system';
-import { IntlProvider } from 'react-intl';
-import { QueryClientProvider, QueryClient } from 'react-query';
-import { fireEvent, render, screen } from '@testing-library/react';
-import { useFolderStructure } from '../../../hooks/useFolderStructure';
-import { DialogHeader } from '../DialogHeader';
-
-jest.mock('../../../hooks/useFolderStructure');
-
-const setup = props => {
- const withDefaults = {
- canRead: true,
- currentFolder: null,
- onChangeFolder: jest.fn(),
- ...props,
- };
-
- const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- retry: false,
- refetchOnWindowFocus: false,
- },
- },
- });
-
- return render(
-
-
-
-
-
-
-
- );
-};
-
-describe('Upload || components || DialogHeader', () => {
- it('should render folder name and back button', () => {
- const handleChangeFolderSpy = jest.fn();
- const { queryByText } = setup({ currentFolder: 2, onChangeFolder: handleChangeFolderSpy });
-
- expect(queryByText('second child')).toBeInTheDocument();
-
- const goBackButton = screen.getByLabelText('Go back');
- expect(goBackButton).toBeInTheDocument();
-
- fireEvent.click(goBackButton);
- expect(handleChangeFolderSpy).toHaveBeenCalled();
- });
-
- it('should truncate long folder name', () => {
- useFolderStructure.mockReturnValueOnce({
- isLoading: false,
- error: null,
- data: [
- {
- value: null,
- label: 'Media Library',
- children: [
- {
- value: 1,
- label: 'This is a really really long folder name that should be truncated',
- children: [],
- },
- ],
- },
- ],
- });
- const { queryByText } = setup({ currentFolder: 1 });
-
- expect(
- queryByText('This is a really really long folder name that should be trun...')
- ).toBeInTheDocument();
- });
-
- it('should not render folder name and back button if the current folder is root', () => {
- const { queryByText } = setup();
-
- expect(queryByText('Cats')).not.toBeInTheDocument();
- expect(screen.queryByLabelText('Go back')).not.toBeInTheDocument();
- });
-
- it('should not attempt to fetch the folder structure, if the user does not have permissions', () => {
- const spy = jest.fn().mockReturnValueOnce({
- isLoading: false,
- error: null,
- });
- useFolderStructure.mockImplementation(spy);
-
- setup({ canRead: false });
-
- expect(spy).toHaveBeenCalledWith({ enabled: false });
- });
-});
diff --git a/packages/core/upload/admin/src/components/Breadcrumbs/Breadcrumbs.js b/packages/core/upload/admin/src/components/Breadcrumbs/Breadcrumbs.js
new file mode 100644
index 0000000000..067ea8e67c
--- /dev/null
+++ b/packages/core/upload/admin/src/components/Breadcrumbs/Breadcrumbs.js
@@ -0,0 +1,71 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { NavLink } from 'react-router-dom';
+import { useIntl } from 'react-intl';
+
+import {
+ Crumb,
+ CrumbLink,
+ Breadcrumbs as BaseBreadcrumbs,
+} from '@strapi/design-system/v2/Breadcrumbs';
+import { CrumbSimpleMenuAsync } from './CrumbSimpleMenuAsync';
+import { BreadcrumbsDefinition } from '../../constants';
+
+export const Breadcrumbs = ({ breadcrumbs, onChangeFolder, currentFolderId, ...props }) => {
+ const { formatMessage } = useIntl();
+
+ return (
+
+ {breadcrumbs.map((crumb, index) => {
+ if (Array.isArray(crumb)) {
+ return (
+ parent.id)}
+ key={`breadcrumb-${crumb?.id ?? 'menu'}`}
+ currentFolderId={currentFolderId}
+ onChangeFolder={onChangeFolder}
+ />
+ );
+ }
+
+ const isCurrentFolderMediaLibrary = crumb.id === null && currentFolderId === undefined;
+
+ if (currentFolderId !== crumb.id && !isCurrentFolderMediaLibrary) {
+ return (
+ onChangeFolder(crumb.id))}
+ >
+ {crumb.label?.id ? formatMessage(crumb.label) : crumb.label}
+
+ );
+ }
+
+ return (
+
+ {crumb.label?.id ? formatMessage(crumb.label) : crumb.label}
+
+ );
+ })}
+
+ );
+};
+
+Breadcrumbs.defaultProps = {
+ currentFolderId: undefined,
+ onChangeFolder: undefined,
+};
+
+Breadcrumbs.propTypes = {
+ breadcrumbs: BreadcrumbsDefinition.isRequired,
+ currentFolderId: PropTypes.number,
+ onChangeFolder: PropTypes.func,
+};
diff --git a/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.js b/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.js
new file mode 100644
index 0000000000..80e5b57d1b
--- /dev/null
+++ b/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.js
@@ -0,0 +1,83 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import { NavLink, useLocation } from 'react-router-dom';
+import { useIntl } from 'react-intl';
+import { useQueryParams } from '@strapi/helper-plugin';
+import { CrumbSimpleMenu } from '@strapi/design-system/v2/Breadcrumbs';
+import { MenuItem } from '@strapi/design-system/v2/SimpleMenu';
+import { Loader } from '@strapi/design-system/Loader';
+import { useFolderStructure } from '../../hooks/useFolderStructure';
+import { getFolderParents, getFolderURL, getTrad } from '../../utils';
+
+export const CrumbSimpleMenuAsync = ({ parentsToOmit, currentFolderId, onChangeFolder }) => {
+ const [shouldFetch, setShouldFetch] = useState(false);
+ const { data, isLoading } = useFolderStructure({ enabled: shouldFetch });
+ const { pathname } = useLocation();
+ const [{ query }] = useQueryParams();
+ const { formatMessage } = useIntl();
+
+ const allAscendants = data && getFolderParents(data, currentFolderId);
+ const filteredAscendants =
+ allAscendants &&
+ allAscendants.filter(
+ ascendant => !parentsToOmit.includes(ascendant.id) && ascendant.id !== null
+ );
+
+ return (
+ setShouldFetch(true)}
+ onClose={() => setShouldFetch(false)}
+ aria-label={formatMessage({
+ id: getTrad('header.breadcrumbs.menu.label'),
+ defaultMessage: 'Get more ascendants folders',
+ })}
+ label="..."
+ >
+ {isLoading && (
+
+ )}
+ {filteredAscendants &&
+ filteredAscendants.map(ascendant => {
+ if (onChangeFolder) {
+ return (
+
+ );
+ }
+
+ const url = getFolderURL(pathname, query, ascendant);
+
+ return (
+
+ );
+ })}
+
+ );
+};
+
+CrumbSimpleMenuAsync.defaultProps = {
+ currentFolderId: undefined,
+ onChangeFolder: undefined,
+ parentsToOmit: [],
+};
+
+CrumbSimpleMenuAsync.propTypes = {
+ currentFolderId: PropTypes.number,
+ onChangeFolder: PropTypes.func,
+ parentsToOmit: PropTypes.arrayOf(PropTypes.number),
+};
diff --git a/packages/core/upload/admin/src/components/Breadcrumbs/index.js b/packages/core/upload/admin/src/components/Breadcrumbs/index.js
new file mode 100644
index 0000000000..28140a257f
--- /dev/null
+++ b/packages/core/upload/admin/src/components/Breadcrumbs/index.js
@@ -0,0 +1 @@
+export { Breadcrumbs } from './Breadcrumbs';
diff --git a/packages/core/upload/admin/src/components/Breadcrumbs/tests/__snapshots__/index.test.js.snap b/packages/core/upload/admin/src/components/Breadcrumbs/tests/__snapshots__/index.test.js.snap
new file mode 100644
index 0000000000..8b937fff61
--- /dev/null
+++ b/packages/core/upload/admin/src/components/Breadcrumbs/tests/__snapshots__/index.test.js.snap
@@ -0,0 +1,393 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Media Library | Breadcrumbs should render and match snapshot 1`] = `
+.c15 {
+ border: 0;
+ -webkit-clip: rect(0 0 0 0);
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+.c5 {
+ padding-right: 4px;
+ padding-left: 4px;
+}
+
+.c12 {
+ padding-left: 8px;
+}
+
+.c14 {
+ padding-top: 4px;
+ padding-right: 8px;
+ padding-bottom: 4px;
+ padding-left: 8px;
+}
+
+.c7 {
+ color: #8e8ea9;
+ font-size: 0.75rem;
+ line-height: 1.33;
+}
+
+.c11 {
+ font-weight: 600;
+ color: #32324d;
+ font-size: 0.75rem;
+ line-height: 1.33;
+}
+
+.c1 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row;
+}
+
+.c3 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-inline-box;
+ display: -webkit-inline-flex;
+ display: -ms-inline-flexbox;
+ display: inline-flex;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row;
+}
+
+.c2:first-child {
+ margin-left: calc(-1*8px);
+}
+
+.c4 {
+ border-radius: 4px;
+ color: #666687;
+ font-size: 0.75rem;
+ line-height: 1.43;
+ padding: 4px 8px;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+}
+
+.c4:hover,
+.c4:focus {
+ background-color: #dcdce4;
+ color: #4a4a6a;
+}
+
+.c8 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ cursor: pointer;
+ padding: 8px;
+ border-radius: 4px;
+ background: #ffffff;
+ border: 1px solid #dcdce4;
+ position: relative;
+ outline: none;
+}
+
+.c8 svg {
+ height: 12px;
+ width: 12px;
+}
+
+.c8 svg > g,
+.c8 svg path {
+ fill: #ffffff;
+}
+
+.c8[aria-disabled='true'] {
+ pointer-events: none;
+}
+
+.c8:after {
+ -webkit-transition-property: all;
+ transition-property: all;
+ -webkit-transition-duration: 0.2s;
+ transition-duration: 0.2s;
+ border-radius: 8px;
+ content: '';
+ position: absolute;
+ top: -4px;
+ bottom: -4px;
+ left: -4px;
+ right: -4px;
+ border: 2px solid transparent;
+}
+
+.c8:focus-visible {
+ outline: none;
+}
+
+.c8:focus-visible:after {
+ border-radius: 8px;
+ content: '';
+ position: absolute;
+ top: -5px;
+ bottom: -5px;
+ left: -5px;
+ right: -5px;
+ border: 2px solid #4945ff;
+}
+
+.c9 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ padding: 8px 16px;
+ background: #4945ff;
+ border: 1px solid #4945ff;
+ border: 1px solid transparent;
+ background: transparent;
+}
+
+.c9 .c0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.c9 .c6 {
+ color: #ffffff;
+}
+
+.c9[aria-disabled='true'] {
+ border: 1px solid #dcdce4;
+ background: #eaeaef;
+}
+
+.c9[aria-disabled='true'] .c6 {
+ color: #666687;
+}
+
+.c9[aria-disabled='true'] svg > g,
+.c9[aria-disabled='true'] svg path {
+ fill: #666687;
+}
+
+.c9[aria-disabled='true']:active {
+ border: 1px solid #dcdce4;
+ background: #eaeaef;
+}
+
+.c9[aria-disabled='true']:active .c6 {
+ color: #666687;
+}
+
+.c9[aria-disabled='true']:active svg > g,
+.c9[aria-disabled='true']:active svg path {
+ fill: #666687;
+}
+
+.c9:hover {
+ background-color: #f6f6f9;
+}
+
+.c9:active {
+ border: 1px solid undefined;
+ background: undefined;
+}
+
+.c9 .c6 {
+ color: #32324d;
+}
+
+.c9 svg > g,
+.c9 svg path {
+ fill: #8e8ea9;
+}
+
+.c13 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.c13 svg {
+ height: 4px;
+ width: 6px;
+}
+
+.c10 {
+ padding: 4px 12px;
+}
+
+.c10:hover,
+.c10:focus {
+ background-color: #dcdce4;
+}
+
+
+`;
diff --git a/packages/core/upload/admin/src/components/Breadcrumbs/tests/index.test.js b/packages/core/upload/admin/src/components/Breadcrumbs/tests/index.test.js
new file mode 100644
index 0000000000..32ce79bfef
--- /dev/null
+++ b/packages/core/upload/admin/src/components/Breadcrumbs/tests/index.test.js
@@ -0,0 +1,71 @@
+import React from 'react';
+import { render as renderTL, screen, fireEvent, waitFor } from '@testing-library/react';
+import { QueryClientProvider, QueryClient } from 'react-query';
+import { MemoryRouter } from 'react-router-dom';
+import { IntlProvider } from 'react-intl';
+
+import { ThemeProvider, lightTheme } from '@strapi/design-system';
+import { Breadcrumbs } from '../index';
+
+jest.mock('../../../hooks/useFolderStructure');
+
+jest.mock('@strapi/helper-plugin', () => ({
+ ...jest.requireActual('@strapi/helper-plugin'),
+ useQueryParams: jest.fn().mockReturnValue([{ query: { folder: 22 } }]),
+}));
+
+const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: false,
+ refetchOnWindowFocus: false,
+ },
+ },
+});
+
+const defaultBreadcrumbs = [
+ {
+ href: '/',
+ id: null,
+ label: 'Media Library',
+ },
+ [],
+ { href: '/', id: 21, label: 'parent folder' },
+ { id: 22, label: 'current folder' },
+];
+
+const setup = props =>
+ renderTL(
+
+
+
+
+
+
+
+
+
+ );
+
+describe('Media Library | Breadcrumbs', () => {
+ test('should render and match snapshot', () => {
+ const { container } = setup({ currentFolderId: 22 });
+
+ expect(container.querySelector('nav')).toBeInTheDocument();
+ expect(screen.getByText('parent folder')).toBeInTheDocument();
+ expect(screen.getByText('current folder')).toBeInTheDocument();
+ expect(screen.getByText('Media Library')).toBeInTheDocument();
+ expect(container).toMatchSnapshot();
+ });
+
+ test('should store other ascendants in simple menu', async () => {
+ const { getByRole } = setup({ currentFolderId: 22 });
+
+ const simpleMenuButton = getByRole('button', { name: /get more ascendants folders/i });
+ fireEvent.mouseDown(simpleMenuButton);
+
+ await waitFor(() => {
+ expect(screen.getByText('second child')).toBeInTheDocument();
+ });
+ });
+});
diff --git a/packages/core/upload/admin/src/components/BulkMoveDialog/BulkMoveDialog.js b/packages/core/upload/admin/src/components/BulkMoveDialog/BulkMoveDialog.js
index 5f8a183f07..223f99e7f8 100644
--- a/packages/core/upload/admin/src/components/BulkMoveDialog/BulkMoveDialog.js
+++ b/packages/core/upload/admin/src/components/BulkMoveDialog/BulkMoveDialog.js
@@ -62,7 +62,7 @@ export const BulkMoveDialog = ({ onClose, selected, currentFolder }) => {
{formatMessage({
- id: getTrad('list.asset.load'),
+ id: getTrad('content.isLoading'),
defaultMessage: 'Content is loading.',
})}
diff --git a/packages/core/upload/admin/src/components/EditAssetDialog/index.js b/packages/core/upload/admin/src/components/EditAssetDialog/index.js
index adf343895e..babb1a8807 100644
--- a/packages/core/upload/admin/src/components/EditAssetDialog/index.js
+++ b/packages/core/upload/admin/src/components/EditAssetDialog/index.js
@@ -146,7 +146,7 @@ export const EditAssetDialog = ({
{formatMessage({
- id: getTrad('list.asset.load'),
+ id: getTrad('content.isLoading'),
defaultMessage: 'Content is loading.',
})}
diff --git a/packages/core/upload/admin/src/components/EditFolderDialog/EditFolderDialog.js b/packages/core/upload/admin/src/components/EditFolderDialog/EditFolderDialog.js
index edacc10c2f..4d7622ca37 100644
--- a/packages/core/upload/admin/src/components/EditFolderDialog/EditFolderDialog.js
+++ b/packages/core/upload/admin/src/components/EditFolderDialog/EditFolderDialog.js
@@ -130,7 +130,7 @@ export const EditFolderDialog = ({ onClose, folder, location, parentFolderId })
{formatMessage({
- id: getTrad('list.asset.load'),
+ id: getTrad('content.isLoading'),
defaultMessage: 'Content is loading.',
})}
diff --git a/packages/core/upload/admin/src/constants.js b/packages/core/upload/admin/src/constants.js
index 175926c550..50e661495b 100644
--- a/packages/core/upload/admin/src/constants.js
+++ b/packages/core/upload/admin/src/constants.js
@@ -21,6 +21,8 @@ const ParentFolderDefinition = PropTypes.shape({
path: PropTypes.string.isRequired,
});
+ParentFolderDefinition.parent = PropTypes.shape(ParentFolderDefinition);
+
export const FolderDefinition = PropTypes.shape({
id: PropTypes.number.isRequired,
children: PropTypes.shape({
@@ -32,7 +34,7 @@ export const FolderDefinition = PropTypes.shape({
count: PropTypes.number.isRequired,
}),
name: PropTypes.string.isRequired,
- parent: PropTypes.oneOf([ParentFolderDefinition, PropTypes.number]),
+ parent: PropTypes.oneOfType([ParentFolderDefinition, PropTypes.number]),
updatedAt: PropTypes.string.isRequired,
updatedBy: PropTypes.shape(),
pathId: PropTypes.number.isRequired,
@@ -72,3 +74,15 @@ export const AssetDefinition = PropTypes.shape({
}),
}),
});
+
+export const CrumbDefinition = PropTypes.shape({
+ id: PropTypes.number,
+ label: PropTypes.string.isRequired,
+ href: PropTypes.string,
+});
+
+export const CrumbMenuDefinition = PropTypes.arrayOf(CrumbDefinition);
+
+export const BreadcrumbsDefinition = PropTypes.arrayOf(
+ PropTypes.oneOfType([CrumbDefinition, CrumbMenuDefinition])
+);
diff --git a/packages/core/upload/admin/src/hooks/__mocks__/useFolderStructure.js b/packages/core/upload/admin/src/hooks/__mocks__/useFolderStructure.js
index b3f60e89c6..3b016ffdf1 100644
--- a/packages/core/upload/admin/src/hooks/__mocks__/useFolderStructure.js
+++ b/packages/core/upload/admin/src/hooks/__mocks__/useFolderStructure.js
@@ -19,7 +19,13 @@ export const useFolderStructure = jest.fn().mockReturnValue({
{
value: 21,
name: 'first child of the second child',
- children: [],
+ children: [
+ {
+ value: 22,
+ name: 'another child',
+ children: [],
+ },
+ ],
},
],
},
diff --git a/packages/core/upload/admin/src/hooks/tests/useFolder.test.js b/packages/core/upload/admin/src/hooks/tests/useFolder.test.js
index 719e092cf3..cf7090c45e 100644
--- a/packages/core/upload/admin/src/hooks/tests/useFolder.test.js
+++ b/packages/core/upload/admin/src/hooks/tests/useFolder.test.js
@@ -81,7 +81,9 @@ describe('useFolder', () => {
await waitFor(() => result.current.isSuccess);
await waitForNextUpdate();
- expect(axiosInstance.get).toBeCalledWith(`/upload/folders/1?populate=parent`);
+ expect(axiosInstance.get).toBeCalledWith(
+ '/upload/folders/1?populate[parent][populate][parent]=*'
+ );
});
test('it does not fetch, if enabled is set to false', async () => {
diff --git a/packages/core/upload/admin/src/hooks/useFolder.js b/packages/core/upload/admin/src/hooks/useFolder.js
index 3cce2b7134..753e408c05 100644
--- a/packages/core/upload/admin/src/hooks/useFolder.js
+++ b/packages/core/upload/admin/src/hooks/useFolder.js
@@ -10,7 +10,9 @@ export const useFolder = (id, { enabled = true }) => {
const fetchFolder = async () => {
try {
- const { data } = await axiosInstance.get(`${dataRequestURL}/${id}?populate=parent`);
+ const { data } = await axiosInstance.get(
+ `${dataRequestURL}/${id}?populate[parent][populate][parent]=*`
+ );
return data.data;
} catch (err) {
diff --git a/packages/core/upload/admin/src/pages/App/MediaLibrary.js b/packages/core/upload/admin/src/pages/App/MediaLibrary.js
index d07a852eab..554aec0cd0 100644
--- a/packages/core/upload/admin/src/pages/App/MediaLibrary.js
+++ b/packages/core/upload/admin/src/pages/App/MediaLibrary.js
@@ -2,7 +2,6 @@ import React, { useState, useRef } from 'react'; // useState
import { useIntl } from 'react-intl';
import styled from 'styled-components';
import { useLocation, useHistory } from 'react-router-dom';
-import { stringify } from 'qs';
import {
LoadingIndicatorPage,
useFocusWhenNavigate,
@@ -31,7 +30,7 @@ import { FolderList } from '../../components/FolderList';
import SortPicker from '../../components/SortPicker';
import { useAssets } from '../../hooks/useAssets';
import { useFolders } from '../../hooks/useFolders';
-import { getTrad, containsAssetFilter } from '../../utils';
+import { getTrad, containsAssetFilter, getBreadcrumbDataML, getFolderURL } from '../../utils';
import { PaginationFooter } from '../../components/PaginationFooter';
import { useMediaLibraryPermissions } from '../../hooks/useMediaLibraryPermissions';
import { useFolder } from '../../hooks/useFolder';
@@ -148,8 +147,9 @@ export const MediaLibrary = () => {
{
0) || !isFiltering) &&
- formatMessage({
- id: getTrad('list.folders.title'),
- defaultMessage: 'Folders',
- })) ||
+ formatMessage(
+ {
+ id: getTrad('list.folders.title'),
+ defaultMessage: 'Folders ({count})',
+ },
+ { count: folderCount }
+ )) ||
''
}
>
@@ -243,13 +246,7 @@ export const MediaLibrary = () => {
currentFolder => currentFolder.id === folder.id
);
- // Search query will always fetch the same results
- // we remove it here to allow navigating in a folder and see the result of this navigation
- const { _q, ...queryParamsWithoutQ } = query;
- const url = `${pathname}?${stringify({
- ...queryParamsWithoutQ,
- folder: folder.id,
- })}`;
+ const url = getFolderURL(pathname, query, folder);
return (
@@ -334,10 +331,13 @@ export const MediaLibrary = () => {
title={
((!isFiltering || (isFiltering && folderCount > 0)) &&
assetsData?.pagination?.page === 1 &&
- formatMessage({
- id: getTrad('list.assets.title'),
- defaultMessage: 'Assets',
- })) ||
+ formatMessage(
+ {
+ id: getTrad('list.assets.title'),
+ defaultMessage: 'Assets ({count})',
+ },
+ { count: assetCount }
+ )) ||
''
}
/>
diff --git a/packages/core/upload/admin/src/pages/App/components/Header.js b/packages/core/upload/admin/src/pages/App/components/Header.js
index 6c975aff69..b1ea8736f3 100644
--- a/packages/core/upload/admin/src/pages/App/components/Header.js
+++ b/packages/core/upload/admin/src/pages/App/components/Header.js
@@ -11,15 +11,15 @@ import { Link } from '@strapi/design-system/Link';
import ArrowLeft from '@strapi/icons/ArrowLeft';
import Plus from '@strapi/icons/Plus';
import { getTrad } from '../../../utils';
-import { FolderDefinition } from '../../../constants';
+import { FolderDefinition, BreadcrumbsDefinition } from '../../../constants';
+import { Breadcrumbs } from '../../../components/Breadcrumbs';
export const Header = ({
+ breadcrumbs,
canCreate,
+ folder,
onToggleEditFolderDialog,
onToggleUploadAssetDialog,
- folder,
- assetCount,
- folderCount,
}) => {
const { formatMessage } = useIntl();
const { pathname } = useLocation();
@@ -28,22 +28,27 @@ export const Header = ({
...query,
folder: folder?.parent?.id ?? undefined,
};
- const name = folder?.name?.length > 30 ? `${folder.name.slice(0, 30)}...` : folder?.name;
return (
+ )
+ }
navigationAction={
folder && (
{
expect(container).toMatchSnapshot();
});
- test('truncates long folder lavels', () => {
- useQueryParams.mockReturnValueOnce([{ rawQuery: '', query: { folder: 2 } }, jest.fn()]);
-
- const { queryByText } = setup({
- folder: { ...FIXTURE_FOLDER, name: 'The length of this label exceeds the maximum length' },
- });
- expect(queryByText('Media Library - The length of this label excee...')).toBeInTheDocument();
- });
-
test('does not render a back button at the root level of the media library', () => {
const { queryByText } = setup({ folder: null });
diff --git a/packages/core/upload/admin/src/pages/App/tests/MediaLibrary.test.js b/packages/core/upload/admin/src/pages/App/tests/MediaLibrary.test.js
index 8b130c205e..e8680e4cc5 100644
--- a/packages/core/upload/admin/src/pages/App/tests/MediaLibrary.test.js
+++ b/packages/core/upload/admin/src/pages/App/tests/MediaLibrary.test.js
@@ -4,12 +4,13 @@ import { QueryClientProvider, QueryClient } from 'react-query';
import { render as renderTL, screen, waitFor, fireEvent } from '@testing-library/react';
import { useSelectionState, useQueryParams, TrackingContext } from '@strapi/helper-plugin';
import { MemoryRouter } from 'react-router-dom';
+import { IntlProvider } from 'react-intl';
import { useMediaLibraryPermissions } from '../../../hooks/useMediaLibraryPermissions';
import { useFolders } from '../../../hooks/useFolders';
import { useAssets } from '../../../hooks/useAssets';
+import { useFolder } from '../../../hooks/useFolder';
import { MediaLibrary } from '../MediaLibrary';
-import en from '../../../translations/en.json';
const FIXTURE_ASSET_PAGINATION = {
pageCount: 1,
@@ -56,7 +57,6 @@ jest.mock('../../../hooks/useMediaLibraryPermissions');
jest.mock('../../../hooks/useFolders');
jest.mock('../../../hooks/useFolder');
jest.mock('../../../hooks/useAssets');
-
jest.mock('@strapi/helper-plugin', () => ({
...jest.requireActual('@strapi/helper-plugin'),
useRBAC: jest.fn(),
@@ -66,17 +66,11 @@ jest.mock('@strapi/helper-plugin', () => ({
.fn()
.mockReturnValue([[], { selectOne: jest.fn(), selectAll: jest.fn() }]),
}));
-
jest.mock('../../../utils', () => ({
...jest.requireActual('../../../utils'),
getTrad: x => x,
}));
-jest.mock('react-intl', () => ({
- FormattedMessage: ({ id }) => id,
- useIntl: () => ({ formatMessage: jest.fn(({ id }) => en[id] || id) }),
-}));
-
const queryClient = new QueryClient({
defaultOptions: {
queries: {
@@ -89,13 +83,15 @@ const queryClient = new QueryClient({
const renderML = () =>
renderTL(
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
);
@@ -107,7 +103,6 @@ describe('Media library homepage', () => {
describe('navigation', () => {
it('focuses the title when mounting the component', () => {
renderML();
-
expect(screen.getByRole('main')).toHaveFocus();
});
});
@@ -119,27 +114,21 @@ describe('Media library homepage', () => {
canCreate: false,
canRead: false,
});
-
renderML();
-
expect(screen.getByRole('main').getAttribute('aria-busy')).toBe('true');
expect(screen.getByText('Loading content.')).toBeInTheDocument();
});
it('shows a loader while resolving assets', () => {
useAssets.mockReturnValueOnce({ isLoading: true });
-
renderML();
-
expect(screen.getByRole('main').getAttribute('aria-busy')).toBe('true');
expect(screen.getByText('Loading content.')).toBeInTheDocument();
});
it('shows a loader while resolving folders', () => {
useFolders.mockReturnValueOnce({ isLoading: true });
-
renderML();
-
expect(screen.getByRole('main').getAttribute('aria-busy')).toBe('true');
expect(screen.getByText('Loading content.')).toBeInTheDocument();
});
@@ -150,7 +139,7 @@ describe('Media library homepage', () => {
it('shows the filters dropdown when the user is allowed to read', () => {
renderML();
- expect(screen.getByText('app.utils.filters')).toBeInTheDocument();
+ expect(screen.getByText('Filters')).toBeInTheDocument();
});
it('hides the filters dropdown when the user is not allowed to read', () => {
@@ -159,9 +148,7 @@ describe('Media library homepage', () => {
canRead: false,
canCreate: false,
});
-
renderML();
-
expect(screen.queryByText('app.utils.filters')).not.toBeInTheDocument();
});
});
@@ -169,7 +156,6 @@ describe('Media library homepage', () => {
describe('sort by', () => {
it('shows the sort by dropdown when the user is allowed to read', () => {
renderML();
-
expect(screen.getByText('Sort by')).toBeInTheDocument();
});
@@ -179,30 +165,28 @@ describe('Media library homepage', () => {
canRead: false,
canCreate: false,
});
-
renderML();
-
expect(screen.queryByText('Sort by')).not.toBeInTheDocument();
});
[
- ['Most recent uploads', 'createdAt:DESC'],
- ['Oldest uploads', 'createdAt:ASC'],
- ['Alphabetical order (A to Z)', 'name:ASC'],
- ['Reverse alphabetical order (Z to A)', 'name:DESC'],
- ['Most recent updates', 'updatedAt:DESC'],
- ['Oldest updates', 'updatedAt:ASC'],
- ].forEach(([label, sortKey]) => {
- it(`modifies the URL with the according params: ${label} ${sortKey}`, async () => {
+ 'createdAt:DESC',
+ 'createdAt:ASC',
+ 'name:ASC',
+ 'name:DESC',
+ 'updatedAt:DESC',
+ 'updatedAt:ASC',
+ ].forEach(sortKey => {
+ it(`modifies the URL with the according params: ${sortKey}`, async () => {
const setQueryMock = jest.fn();
useQueryParams.mockReturnValueOnce([{ rawQuery: '', query: {} }, setQueryMock]);
renderML();
fireEvent.mouseDown(screen.getByText('Sort by'));
- await waitFor(() => expect(screen.getByText(label)).toBeInTheDocument());
- fireEvent.mouseDown(screen.getByText(label));
- await waitFor(() => expect(screen.queryByText(label)).not.toBeInTheDocument());
+ await waitFor(() => expect(screen.getByText(sortKey)).toBeInTheDocument());
+ fireEvent.mouseDown(screen.getByText(sortKey));
+ await waitFor(() => expect(screen.queryByText(sortKey)).not.toBeInTheDocument());
expect(setQueryMock).toBeCalledWith({ sort: sortKey });
});
@@ -210,7 +194,13 @@ describe('Media library homepage', () => {
});
describe('select all', () => {
- it('is not visible if there are not folders and assets', () => {
+ it('shows the select all button when the user is allowed to update', () => {
+ renderML();
+
+ expect(screen.getByLabelText('Select all folders & assets')).toBeInTheDocument();
+ });
+
+ it('hides the select all if there are not folders and assets', () => {
useAssets.mockReturnValueOnce({
isLoading: false,
error: null,
@@ -221,17 +211,10 @@ describe('Media library homepage', () => {
isLoading: false,
error: null,
});
+
renderML();
- expect(
- screen.queryByText('There are no elements with the applied filters')
- ).not.toBeInTheDocument();
- });
-
- it('shows the select all button when the user is allowed to update', () => {
- renderML();
-
- expect(screen.getByLabelText('Select all assets')).toBeInTheDocument();
+ expect(screen.queryByLabelText('Select all assets')).not.toBeInTheDocument();
});
it('hides the select all button when the user is not allowed to update', () => {
@@ -241,9 +224,7 @@ describe('Media library homepage', () => {
canCreate: true,
canUpdate: false,
});
-
renderML();
-
expect(screen.queryByLabelText('Select all assets')).not.toBeInTheDocument();
});
});
@@ -255,9 +236,7 @@ describe('Media library homepage', () => {
canRead: false,
canCreate: false,
});
-
renderML();
-
await waitFor(() => expect(screen.queryByText(`Add new assets`)).not.toBeInTheDocument());
});
@@ -267,9 +246,7 @@ describe('Media library homepage', () => {
canRead: true,
canCreate: true,
});
-
renderML();
-
await waitFor(() => expect(screen.getByText(`Add new assets`)).toBeInTheDocument());
});
});
@@ -277,7 +254,6 @@ describe('Media library homepage', () => {
describe('create folder', () => {
it('shows the create button if the user has create permissions', () => {
renderML();
-
expect(screen.getByText('Add new folder')).toBeInTheDocument();
});
@@ -286,28 +262,39 @@ describe('Media library homepage', () => {
isLoading: false,
canCreate: false,
});
-
renderML();
-
expect(screen.queryByText('Add new folder')).not.toBeInTheDocument();
});
});
});
describe('content', () => {
+ it('should show breadcrumbs navigation', () => {
+ renderML();
+
+ expect(screen.queryByLabelText('Folders navigation')).toBeInTheDocument();
+ });
+
+ it('should hide breadcrumbs navigation if in root folder', () => {
+ useFolder.mockReturnValueOnce({ isLoading: false, data: undefined });
+ renderML();
+
+ expect(screen.queryByLabelText('Folders navigation')).not.toBeInTheDocument();
+ });
+
it('does display empty state upload first assets if no folder or assets', () => {
useFolders.mockReturnValueOnce({
data: [],
isLoading: false,
error: null,
});
+
useAssets.mockReturnValueOnce({
isLoading: false,
error: null,
data: {},
});
renderML();
-
expect(screen.queryByText('Upload your first assets...')).toBeInTheDocument();
});
@@ -324,7 +311,6 @@ describe('Media library homepage', () => {
});
useQueryParams.mockReturnValueOnce([{ rawQuery: '', query: { _q: 'true' } }, jest.fn()]);
renderML();
-
expect(
screen.queryByText('There are no elements with the applied filters')
).toBeInTheDocument();
@@ -338,7 +324,6 @@ describe('Media library homepage', () => {
});
useQueryParams.mockReturnValueOnce([{ rawQuery: '', query: { _q: 'true' } }, jest.fn()]);
renderML();
-
expect(screen.queryByText('Assets')).not.toBeInTheDocument();
});
@@ -350,15 +335,14 @@ describe('Media library homepage', () => {
});
useQueryParams.mockReturnValueOnce([{ rawQuery: '', query: { _q: 'true' } }, jest.fn()]);
renderML();
-
expect(screen.queryByText('Folders')).not.toBeInTheDocument();
});
it('displays folders and folders title', () => {
renderML();
- expect(screen.queryByText('Folders')).toBeInTheDocument();
- expect(screen.getByText('Folder 1')).toBeInTheDocument();
+ expect(screen.getByText('Folders (1)')).toBeInTheDocument();
+ expect(screen.getByText('1 folder, 1 asset')).toBeInTheDocument();
});
it('displays folder with checked checkbox when is selected', () => {
@@ -379,13 +363,11 @@ describe('Media library homepage', () => {
{ selectOne: jest.fn(), selectAll: jest.fn() },
]);
renderML();
-
expect(screen.getByTestId('folder-checkbox-1')).toBeChecked();
});
it('doest not displays folder with checked checkbox when is not selected', () => {
renderML();
-
expect(screen.getByTestId('folder-checkbox-1')).not.toBeChecked();
});
@@ -398,8 +380,8 @@ describe('Media library homepage', () => {
renderML();
- expect(screen.queryByText('list.folders.title')).not.toBeInTheDocument();
- expect(screen.queryByText('Folder 1')).not.toBeInTheDocument();
+ expect(screen.queryByText('1 folder, 1 asset')).not.toBeInTheDocument();
+ expect(screen.queryByText('Folders (1)')).not.toBeInTheDocument();
});
it('does display folders if a search is performed', () => {
@@ -407,17 +389,17 @@ describe('Media library homepage', () => {
renderML();
- expect(screen.queryByText('Folders')).toBeInTheDocument();
- expect(screen.queryByText('Folder 1')).toBeInTheDocument();
+ expect(screen.queryByText('1 folder, 1 asset')).toBeInTheDocument();
+ expect(screen.queryByText('Folders (1)')).toBeInTheDocument();
});
- it('does not display folders if the media library is being filtered', () => {
+ it('does display folders if the media library is being filtered', () => {
useQueryParams.mockReturnValueOnce([{ rawQuery: '', query: { filters: 'true' } }, jest.fn()]);
renderML();
- expect(screen.queryByText('Folders')).toBeInTheDocument();
- expect(screen.queryByText('Folder 1')).toBeInTheDocument();
+ expect(screen.queryByText('1 folder, 1 asset')).toBeInTheDocument();
+ expect(screen.queryByText('Folders (1)')).toBeInTheDocument();
});
it('does not fetch folders if the current page !== 1', () => {
@@ -434,9 +416,7 @@ describe('Media library homepage', () => {
},
});
useQueryParams.mockReturnValueOnce([{ rawQuery: '', query: { _q: 'true' } }, jest.fn()]);
-
renderML();
-
expect(useFolders).toHaveBeenCalledWith(expect.objectContaining({ enabled: false }));
});
@@ -457,15 +437,12 @@ describe('Media library homepage', () => {
{ rawQuery: '', query: { _q: '', filters: { $and: { mime: 'audio' } } } },
jest.fn(),
]);
-
renderML();
-
expect(useFolders).toHaveBeenCalledWith(expect.objectContaining({ enabled: false }));
});
it('displays assets', () => {
renderML();
-
expect(screen.getByText('3874873.jpg')).toBeInTheDocument();
});
@@ -475,9 +452,7 @@ describe('Media library homepage', () => {
canRead: false,
canCreate: false,
});
-
renderML();
-
expect(screen.queryByText('3874873.jpg')).not.toBeInTheDocument();
});
@@ -489,14 +464,11 @@ describe('Media library homepage', () => {
results: [],
},
});
-
useFolders.mockReturnValueOnce({
isLoading: false,
data: [],
});
-
renderML();
-
expect(screen.queryByText('Upload your first assets...')).toBeInTheDocument();
});
@@ -510,15 +482,12 @@ describe('Media library homepage', () => {
results: [],
},
});
-
useFolders.mockReturnValueOnce({
isLoading: false,
error: null,
data: [],
});
-
renderML();
-
expect(
screen.queryByText('There are no elements with the applied filters')
).toBeInTheDocument();
diff --git a/packages/core/upload/admin/src/pages/App/tests/__snapshots__/Header.test.js.snap b/packages/core/upload/admin/src/pages/App/tests/__snapshots__/Header.test.js.snap
index 1d3d517e9a..c61d161f2b 100644
--- a/packages/core/upload/admin/src/pages/App/tests/__snapshots__/Header.test.js.snap
+++ b/packages/core/upload/admin/src/pages/App/tests/__snapshots__/Header.test.js.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Header renders 1`] = `
-.c20 {
+.c19 {
border: 0;
-webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0);
@@ -310,12 +310,6 @@ exports[`Header renders 1`] = `
line-height: 1.25;
}
-.c19 {
- color: #666687;
- font-size: 1rem;
- line-height: 1.5;
-}
-
.c5 {
color: #4945ff;
font-size: 0.75rem;
@@ -435,7 +429,7 @@ exports[`Header renders 1`] = `
- Media Library - Folder 1
+ Media Library