From 86ee4bc3bbdb723021199076162b115374d177c4 Mon Sep 17 00:00:00 2001 From: Punit Sethi Date: Wed, 28 Jun 2023 11:23:25 +0530 Subject: [PATCH 01/15] Fixed the logic to show indicator till fetching data --- .../core/admin/admin/src/components/AuthenticatedApp/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/admin/admin/src/components/AuthenticatedApp/index.js b/packages/core/admin/admin/src/components/AuthenticatedApp/index.js index a0bb170e27..c6209f87aa 100644 --- a/packages/core/admin/admin/src/components/AuthenticatedApp/index.js +++ b/packages/core/admin/admin/src/components/AuthenticatedApp/index.js @@ -86,7 +86,7 @@ const AuthenticatedApp = () => { // We don't need to wait for the release query to be fetched before rendering the plugins // however, we need the appInfos and the permissions const shouldShowNotDependentQueriesLoader = - (isFetching && isFetched) || status === 'loading' || fetchPermissionsStatus === 'loading'; + isFetching || status === 'loading' || fetchPermissionsStatus === 'loading'; const shouldShowLoader = isLoading || shouldShowNotDependentQueriesLoader; From fe87a895a5b59ca0e0ceaaa6b9ccac1d71b2ef76 Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Wed, 28 Jun 2023 12:35:03 +0200 Subject: [PATCH 02/15] add transformParamsToQuery back --- .../plugins/i18n/server/services/entity-service-decorator.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 8664e6b868..25bffeac43 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -2,6 +2,7 @@ const { has, get, omit, isArray } = require('lodash/fp'); const { ApplicationError } = require('@strapi/utils').errors; +const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams; const { getService } = require('../utils'); @@ -170,7 +171,8 @@ const decorator = (service) => ({ if (opts[LOCALE_QUERY_FILTER] === 'all') { // TODO Fix so this won't break lower lying find many wrappers const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); - return strapi.db.query(uid).findMany(wrappedParams); + const query = transformParamsToQuery(uid, wrappedParams); + return strapi.db.query(uid).findMany(query); } // This one gets transformed into a findOne on a lower layer From 6f7076ae37de45725258f3f5e14fd7c3ab1f9586 Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Wed, 28 Jun 2023 15:17:51 +0200 Subject: [PATCH 03/15] Fix missing review workflows column --- .../src/content-manager/pages/ListView/index.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/core/admin/admin/src/content-manager/pages/ListView/index.js b/packages/core/admin/admin/src/content-manager/pages/ListView/index.js index a4d0c6f3ee..1eca5b378a 100644 --- a/packages/core/admin/admin/src/content-manager/pages/ListView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/ListView/index.js @@ -33,6 +33,7 @@ import { } from '@strapi/helper-plugin'; import { ArrowLeft, Cog, Plus } from '@strapi/icons'; import axios from 'axios'; +import getReviewWorkflowsColumn from 'ee_else_ce/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn'; import isEqual from 'lodash/isEqual'; import PropTypes from 'prop-types'; import { stringify } from 'qs'; @@ -391,6 +392,17 @@ function ListView({ return formattedHeaders; } + // this should not exist. Ideally we would use registerHook() similar to what has been done + // in the i18n plugin. In order to do that review-workflows should have been a plugin. In + // a future iteration we need to find a better pattern. + + // In CE this will return null - in EE a column definition including the custom formatting component. + const reviewWorkflowColumn = getReviewWorkflowsColumn(layout); + + if (reviewWorkflowColumn) { + formattedHeaders.push(reviewWorkflowColumn); + } + return [ ...formattedHeaders, { From a860e1f205682333bf9b7bae7e9020216a941296 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 29 Jun 2023 10:29:50 +0200 Subject: [PATCH 04/15] doc: improve async --- docs/docs/docs/01-core/utils/async.md | 65 ++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/docs/docs/docs/01-core/utils/async.md b/docs/docs/docs/01-core/utils/async.md index 7779f58ad1..285df739f8 100644 --- a/docs/docs/docs/01-core/utils/async.md +++ b/docs/docs/docs/01-core/utils/async.md @@ -12,17 +12,64 @@ Async utils are grouping all function that interact with async stuff like Promis ## Detailed design -Available functions: +### mapAsync -- pipeAsync -- mapAsync -- reduceAsync +The `mapAsync` function is an asynchronous version of the `Array.prototype.map` method. -[See API reference](../../../api/api.mdx) (TODO) +Example usage: + +```js +const input = [1, 2, 3]; + +const output = await mapAsync(input, async (item) => { + return item * 2; +}); + +console.log(output); // [2, 4, 6] +``` + +### reduceAsync + +The `reduceAsync` function is an asynchronous version of the `Array.prototype.reduce` method. + +Example usage: + +```js +const input = [1, 2, 3]; + +const reducer = reduceAsync(input); +const output = await reducer(async (accumulator, item) => { + return accumulator + item; +}, 0); + +console.log(output); // 6 +``` + +### pipeAsync + +The `pipeAsync` function is a utility function for composing asynchronous functions. It takes a list of functions as input, and returns a new function that applies each function in turn to the input. + +Example usage: + +```js +async function addOne(input: number): Promise { + return input + 1; +} + +async function double(input: number): Promise { + return input * 2; +} + +const addOneAndDouble = pipeAsync(addOne, double); + +const output = await addOneAndDouble(3); + +console.log(output); // 8 +``` ### When to use -Everytime the code has to act with promises and iterate other them, an async utils function should be used. +Every time the code has to act with promises and iterate other them, an async utils function should be used. ### Should I add my function here ? @@ -32,6 +79,12 @@ Please consider the next point if a lots of functions are available in the async ## Potential improvements +Some ideas of functions that could be added: + +- Other `Array.prototype` methods: `filterAsync`, `someAsync`, `everyAsync`, `findAsync`, `findIndexAsync`, `flatMapAsync`. +- `retryAsync`: A function that retries an asynchronous operation a specified number of times if it fails. It takes an asynchronous operation and a number of retries as input, and returns the result of the operation if it succeeds within the specified number of retries, or throws an error if it fails after all retries. +- `timeoutAsync`: A function that adds a timeout to an asynchronous operation. It takes an asynchronous operation and a timeout duration as input, and returns the result of the operation if it completes within the specified timeout, or throws an error if it takes longer than the timeout. + If we begin to use lots of async utils function, we may consider to migrate to a specialized library like [asyncjs](http://caolan.github.io/async/v3/) ## Resources From ce7b590822e10c359fa797af9d4589a32384bcdc Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Thu, 29 Jun 2023 11:46:13 +0200 Subject: [PATCH 05/15] fix error --- .../plugins/i18n/server/services/entity-service-decorator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 25bffeac43..0f4745f138 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -156,7 +156,7 @@ const decorator = (service) => ({ * @param {string} uid - Model uid * @param {object} opts - Query options object (params, data, files, populate) */ - async findMany(uid, opts) { + async findMany(uid, opts = {}) { const model = strapi.getModel(uid); const { isLocalizedContentType } = getService('content-types'); From b29e20c7b541219eed1ff2813c0374107f7e744e Mon Sep 17 00:00:00 2001 From: Boegie19 Date: Thu, 29 Jun 2023 12:35:21 +0200 Subject: [PATCH 06/15] fix testing error --- .../i18n/server/services/entity-service-decorator.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/plugins/i18n/server/services/entity-service-decorator.js b/packages/plugins/i18n/server/services/entity-service-decorator.js index 0f4745f138..eef1ba461f 100644 --- a/packages/plugins/i18n/server/services/entity-service-decorator.js +++ b/packages/plugins/i18n/server/services/entity-service-decorator.js @@ -156,7 +156,7 @@ const decorator = (service) => ({ * @param {string} uid - Model uid * @param {object} opts - Query options object (params, data, files, populate) */ - async findMany(uid, opts = {}) { + async findMany(uid, opts) { const model = strapi.getModel(uid); const { isLocalizedContentType } = getService('content-types'); @@ -165,13 +165,13 @@ const decorator = (service) => ({ return service.findMany.call(this, uid, opts); } - const { kind } = strapi.getModel(uid); + const { kind } = model; if (kind === 'singleType') { if (opts[LOCALE_QUERY_FILTER] === 'all') { // TODO Fix so this won't break lower lying find many wrappers - const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }); - const query = transformParamsToQuery(uid, wrappedParams); + const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' }) || {}; + const query = transformParamsToQuery(model, wrappedParams); return strapi.db.query(uid).findMany(query); } From 483180b05d3ce5e84a11e7feba16ad91550f18c4 Mon Sep 17 00:00:00 2001 From: Nitin Date: Thu, 29 Jun 2023 18:00:21 +0530 Subject: [PATCH 07/15] fix bug on saving user details --- .../src/pages/SettingsPage/pages/Users/EditPage/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js index dbfec9e2f5..c859aeb1be 100644 --- a/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js @@ -183,13 +183,13 @@ const EditPage = ({ canUpdate }) => { validateOnChange={false} validationSchema={editValidation} > - {({ errors, values, handleChange, isSubmitting }) => { + {({ errors, values, handleChange, isSubmitting, dirty }) => { return (
} loading={isSubmitting} type="submit" From 133ddc2de4e58dc1eb476fda8e0a67b0f1ee6e74 Mon Sep 17 00:00:00 2001 From: Marc-Roig Date: Thu, 29 Jun 2023 17:02:53 +0200 Subject: [PATCH 08/15] fix: do not sign files if using baseUrl --- packages/providers/upload-aws-s3/README.md | 6 ++-- .../src/__tests__/is-url-from-bucket.test.ts | 2 +- .../src/__tests__/upload-aws-s3.test.ts | 32 +++++++++++++++++++ packages/providers/upload-aws-s3/src/index.ts | 8 ----- packages/providers/upload-aws-s3/src/utils.ts | 9 +++--- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/packages/providers/upload-aws-s3/README.md b/packages/providers/upload-aws-s3/README.md index 7011062110..b707b81bf1 100644 --- a/packages/providers/upload-aws-s3/README.md +++ b/packages/providers/upload-aws-s3/README.md @@ -70,9 +70,11 @@ module.exports = ({ env }) => ({ }); ``` -### Configuration for a private S3 bucket +### Configuration for a private S3 bucket and signed URLs -If your bucket is configured to be private, you will need to set the `ACL` option to `private` in the `params` object. This will ensure that the signed URL is generated with the correct permissions. +If your bucket is configured to be private, you will need to set the `ACL` option to `private` in the `params` object. This will ensure file URLs are signed. + +**Note:** If you are using a CDN, the URLs will not be signed. You can also define the expiration time of the signed URL by setting the `signedUrlExpires` option in the `params` object. The default value is 15 minutes. diff --git a/packages/providers/upload-aws-s3/src/__tests__/is-url-from-bucket.test.ts b/packages/providers/upload-aws-s3/src/__tests__/is-url-from-bucket.test.ts index a979e163a3..98d14e3065 100644 --- a/packages/providers/upload-aws-s3/src/__tests__/is-url-from-bucket.test.ts +++ b/packages/providers/upload-aws-s3/src/__tests__/is-url-from-bucket.test.ts @@ -73,6 +73,6 @@ describe('Test for URLs', () => { test('CDN', async () => { const url = 'https://cdn.example.com/v1/img.png'; const isFromBucket = isUrlFromBucket(url, 'bucket', 'https://cdn.example.com/v1/'); - expect(isFromBucket).toEqual(true); + expect(isFromBucket).toEqual(false); }); }); diff --git a/packages/providers/upload-aws-s3/src/__tests__/upload-aws-s3.test.ts b/packages/providers/upload-aws-s3/src/__tests__/upload-aws-s3.test.ts index 2f3cc5f839..3c948eeadd 100644 --- a/packages/providers/upload-aws-s3/src/__tests__/upload-aws-s3.test.ts +++ b/packages/providers/upload-aws-s3/src/__tests__/upload-aws-s3.test.ts @@ -143,4 +143,36 @@ describe('AWS-S3 provider', () => { expect(file.url).toEqual('https://cdn.test/dir/dir2/tmp/test/test.json'); }); }); + + describe('isPrivate', () => { + test('Should sign files if ACL is private', async () => { + const providerInstance = awsProvider.init({ + s3Options: { + params: { + Bucket: 'test', + ACL: 'private', + }, + }, + }); + + const isPrivate = providerInstance.isPrivate(); + + expect(isPrivate).toBe(true); + }); + + test('Should not sign files if ACL is public', async () => { + const providerInstance = awsProvider.init({ + s3Options: { + params: { + Bucket: 'test', + ACL: 'public', + }, + }, + }); + + const isPrivate = providerInstance.isPrivate(); + + expect(isPrivate).toBe(false); + }); + }); }); diff --git a/packages/providers/upload-aws-s3/src/index.ts b/packages/providers/upload-aws-s3/src/index.ts index 1f0cf3f465..d37fd04afb 100644 --- a/packages/providers/upload-aws-s3/src/index.ts +++ b/packages/providers/upload-aws-s3/src/index.ts @@ -69,14 +69,6 @@ export = { const ACL = getOr('public-read', ['params', 'ACL'], config); - // if ACL is private and baseUrl is set, we need to warn the user - // signed url's will not have the baseUrl prefix - if (ACL === 'private' && baseUrl) { - process.emitWarning( - 'You are using a private ACL with a baseUrl. This is not recommended as the files will be accessible without the baseUrl prefix.' - ); - } - const upload = (file: File, customParams = {}): Promise => new Promise((resolve, reject) => { const fileKey = getFileKey(file); diff --git a/packages/providers/upload-aws-s3/src/utils.ts b/packages/providers/upload-aws-s3/src/utils.ts index 4b21129a48..56c4319c5d 100644 --- a/packages/providers/upload-aws-s3/src/utils.ts +++ b/packages/providers/upload-aws-s3/src/utils.ts @@ -5,14 +5,13 @@ interface BucketInfo { err?: string; } -export function isUrlFromBucket(fileUrl: string, bucketName: string, bucketBaseUrl = ''): boolean { +export function isUrlFromBucket(fileUrl: string, bucketName: string, baseUrl = ''): boolean { const url = new URL(fileUrl); // Check if the file URL is using a base URL (e.g. a CDN). - // In this case, check if the file URL starts with the same base URL as the bucket URL. - if (bucketBaseUrl) { - const baseUrl = new URL(bucketBaseUrl); - return url.href.startsWith(baseUrl.href); + // In this case do not sign the URL. + if (baseUrl) { + return false; } const { bucket } = getBucketFromAwsUrl(fileUrl); From 239d83245713c7b0b2ae88a616ad163d03f58581 Mon Sep 17 00:00:00 2001 From: Josh <37798644+joshuaellis@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:45:49 +0100 Subject: [PATCH 09/15] refactor: useAsset query to use folderPath --- .../Breadcrumbs/CrumbSimpleMenuAsync.js | 5 +- .../admin/src/hooks/tests/useAssets.test.js | 24 +++-- .../core/upload/admin/src/hooks/useAssets.js | 92 ++++++++++--------- .../App/MediaLibrary/components/Header.js | 1 + .../tests/__snapshots__/Header.test.js.snap | 2 +- .../admin/src/pages/App/MediaLibrary/index.js | 5 +- .../admin/src/utils/getBreadcrumbDataML.js | 5 +- .../upload/admin/src/utils/getFolderURL.js | 13 ++- .../src/utils/tests/getFolderURL.test.js | 36 ++++++-- 9 files changed, 109 insertions(+), 74 deletions(-) diff --git a/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.js b/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.js index 5b93d1b9ff..1eaf42d9ce 100644 --- a/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.js +++ b/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.js @@ -59,7 +59,10 @@ export const CrumbSimpleMenuAsync = ({ parentsToOmit, currentFolderId, onChangeF ); } - const url = getFolderURL(pathname, query, ascendant?.id); + const url = getFolderURL(pathname, query, { + folder: ascendant?.id, + folderPath: ascendant?.path, + }); return ( diff --git a/packages/core/upload/admin/src/hooks/tests/useAssets.test.js b/packages/core/upload/admin/src/hooks/tests/useAssets.test.js index 0096235e2f..6102fdafdd 100644 --- a/packages/core/upload/admin/src/hooks/tests/useAssets.test.js +++ b/packages/core/upload/admin/src/hooks/tests/useAssets.test.js @@ -82,10 +82,8 @@ describe('useAssets', () => { filters: { $and: [ { - folder: { - id: { - $null: true, - }, + folderPath: { + $eq: '/', }, }, ], @@ -100,7 +98,7 @@ describe('useAssets', () => { }); test('fetches data from the right URL if a query was set', async () => { - const { result } = await setup({ query: { folder: 1 } }); + const { result } = await setup({ query: { folderPath: '/1/2' } }); await waitFor(() => result.current.isSuccess); const { get } = useFetchClient(); @@ -109,8 +107,8 @@ describe('useAssets', () => { filters: { $and: [ { - folder: { - id: 1, + folderPath: { + $eq: '/1/2', }, }, ], @@ -126,7 +124,7 @@ describe('useAssets', () => { test('allows to merge filter query params using filters.$and', async () => { const { result } = await setup({ - query: { folder: 5, filters: { $and: [{ something: 'true' }] } }, + query: { folderPath: '/1/2', filters: { $and: [{ something: 'true' }] } }, }); await waitFor(() => result.current.isSuccess); @@ -139,8 +137,8 @@ describe('useAssets', () => { something: true, }, { - folder: { - id: 5, + folderPath: { + $eq: '/1/2', }, }, ], @@ -154,9 +152,9 @@ describe('useAssets', () => { ); }); - test('does not use folder filter in params if _q', async () => { + test('does not use folderPath filter in params if _q', async () => { const { result } = await setup({ - query: { folder: 5, _q: 'something', filters: { $and: [{ something: 'true' }] } }, + query: { folderPath: '/1/2', _q: 'something', filters: { $and: [{ something: 'true' }] } }, }); await waitFor(() => result.current.isSuccess); @@ -183,7 +181,7 @@ describe('useAssets', () => { test('correctly encodes the search query _q', async () => { const _q = 'something&else'; const { result } = await setup({ - query: { folder: 5, _q, filters: { $and: [{ something: 'true' }] } }, + query: { folderPath: '/1/2', _q, filters: { $and: [{ something: 'true' }] } }, }); await waitFor(() => result.current.isSuccess); diff --git a/packages/core/upload/admin/src/hooks/useAssets.js b/packages/core/upload/admin/src/hooks/useAssets.js index dd42149b54..dc5fe70ee9 100644 --- a/packages/core/upload/admin/src/hooks/useAssets.js +++ b/packages/core/upload/admin/src/hooks/useAssets.js @@ -1,3 +1,5 @@ +import { useEffect } from 'react'; + import { useNotifyAT } from '@strapi/design-system'; import { useFetchClient, useNotification } from '@strapi/helper-plugin'; import { stringify } from 'qs'; @@ -13,7 +15,7 @@ export const useAssets = ({ skipWhen = false, query = {} } = {}) => { const { notifyStatus } = useNotifyAT(); const { get } = useFetchClient(); const dataRequestURL = getRequestUrl('files'); - const { folder, _q, ...paramsExceptFolderAndQ } = query; + const { folderPath, _q, ...paramsExceptFolderAndQ } = query; let params; @@ -29,19 +31,16 @@ export const useAssets = ({ skipWhen = false, query = {} } = {}) => { $and: [ ...(paramsExceptFolderAndQ?.filters?.$and ?? []), { - folder: { - id: folder ?? { - $null: true, - }, - }, + folderPath: { $eq: folderPath ?? '/' }, }, ], }, }; } - const getAssets = async () => { - try { + const { data, error, isLoading } = useQuery( + [pluginId, 'assets', stringify(params)], + async () => { const { data } = await get( `${dataRequestURL}${stringify(params, { encode: false, @@ -49,54 +48,59 @@ export const useAssets = ({ skipWhen = false, query = {} } = {}) => { })}` ); + return data; + }, + { + enabled: !skipWhen, + staleTime: 0, + cacheTime: 0, + select(data) { + if (data?.results && Array.isArray(data.results)) { + return { + ...data, + results: data.results + /** + * Filter out assets that don't have a name. + * So we don't try to render them as assets + * and get errors. + */ + .filter((asset) => asset.name) + .map((asset) => ({ + ...asset, + /** + * Mime and ext cannot be null in the front-end because + * we expect them to be strings and use the `includes` method. + */ + mime: asset.mime ?? '', + ext: asset.ext ?? '', + })), + }; + } + + return data; + }, + } + ); + + useEffect(() => { + if (data) { notifyStatus( formatMessage({ id: 'list.asset.at.finished', defaultMessage: 'The assets have finished loading.', }) ); + } + }, [data, formatMessage, notifyStatus]); - return data; - } catch (err) { + useEffect(() => { + if (error) { toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); - - throw err; } - }; - - const { data, error, isLoading } = useQuery([pluginId, 'assets', stringify(params)], getAssets, { - enabled: !skipWhen, - staleTime: 0, - cacheTime: 0, - select(data) { - if (data?.results && Array.isArray(data.results)) { - return { - ...data, - results: data.results - /** - * Filter out assets that don't have a name. - * So we don't try to render them as assets - * and get errors. - */ - .filter((asset) => asset.name) - .map((asset) => ({ - ...asset, - /** - * Mime and ext cannot be null in the front-end because - * we expect them to be strings and use the `includes` method. - */ - mime: asset.mime ?? '', - ext: asset.ext ?? '', - })), - }; - } - - return data; - }, - }); + }, [error, toggleNotification]); return { data, error, isLoading }; }; diff --git a/packages/core/upload/admin/src/pages/App/MediaLibrary/components/Header.js b/packages/core/upload/admin/src/pages/App/MediaLibrary/components/Header.js index e54b1f920d..893c50c692 100644 --- a/packages/core/upload/admin/src/pages/App/MediaLibrary/components/Header.js +++ b/packages/core/upload/admin/src/pages/App/MediaLibrary/components/Header.js @@ -25,6 +25,7 @@ export const Header = ({ const backQuery = { ...query, folder: folder?.parent?.id ?? undefined, + folderPath: folder?.parent?.path ?? undefined, }; return ( diff --git a/packages/core/upload/admin/src/pages/App/MediaLibrary/components/tests/__snapshots__/Header.test.js.snap b/packages/core/upload/admin/src/pages/App/MediaLibrary/components/tests/__snapshots__/Header.test.js.snap index 9701b63fa7..da36b0b80a 100644 --- a/packages/core/upload/admin/src/pages/App/MediaLibrary/components/tests/__snapshots__/Header.test.js.snap +++ b/packages/core/upload/admin/src/pages/App/MediaLibrary/components/tests/__snapshots__/Header.test.js.snap @@ -366,7 +366,7 @@ exports[`Header renders 1`] = `