[Bugfix] Bulk publish/unpublish for non-default locale entities (#17941)

* pass the locale to the publish and draft relations calls

* fix the problem for entities without internationalization and add unit tests
This commit is contained in:
Simone 2023-09-12 10:40:51 +02:00 committed by GitHub
parent c03a0a4a28
commit e3a5416487
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 86 additions and 7 deletions

View File

@ -6,6 +6,7 @@ import {
useFetchClient, useFetchClient,
useNotification, useNotification,
useAPIErrorHandler, useAPIErrorHandler,
useQueryParams,
} from '@strapi/helper-plugin'; } from '@strapi/helper-plugin';
import { Check, ExclamationMarkCircle } from '@strapi/icons'; import { Check, ExclamationMarkCircle } from '@strapi/icons';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -82,6 +83,7 @@ const ConfirmDialogPublishAll = ({ isOpen, onToggleDialog, isConfirmButtonLoadin
const { const {
contentType: { uid: slug }, contentType: { uid: slug },
} = useSelector(listViewDomain()); } = useSelector(listViewDomain());
const [{ query }] = useQueryParams();
const { const {
data: countDraftRelations, data: countDraftRelations,
@ -97,6 +99,7 @@ const ConfirmDialogPublishAll = ({ isOpen, onToggleDialog, isConfirmButtonLoadin
{ {
params: { params: {
ids: selectedEntries, ids: selectedEntries,
locale: query?.plugins?.i18n?.locale,
}, },
} }
); );

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { lightTheme, ThemeProvider } from '@strapi/design-system'; import { lightTheme, ThemeProvider } from '@strapi/design-system';
import { Table } from '@strapi/helper-plugin'; import { Table, useQueryParams } from '@strapi/helper-plugin';
import { render as renderRTL, screen, waitFor, within } from '@testing-library/react'; import { render as renderRTL, screen, waitFor, within } from '@testing-library/react';
import { rest } from 'msw'; import { rest } from 'msw';
import { setupServer } from 'msw/node'; import { setupServer } from 'msw/node';
@ -34,6 +34,17 @@ jest.mock('@strapi/helper-plugin', () => ({
useNotification: jest.fn(() => { useNotification: jest.fn(() => {
return toggleNotification; return toggleNotification;
}), }),
useQueryParams: jest.fn(() => [
{
query: {
plugins: {
i18n: {
locale: 'en',
},
},
},
},
]),
})); }));
const handlers = [ const handlers = [
@ -215,4 +226,35 @@ describe('ConfirmDialogPublishAll', () => {
); );
expect(await screen.getByRole('alert')).toBeInTheDocument(); expect(await screen.getByRole('alert')).toBeInTheDocument();
}); });
it('should show the warning message with 2 draft relations and 2 entries even if the locale param is not passed', async () => {
useQueryParams.mockImplementation(() => [
{
query: {
page: 1,
pageSize: 10,
sort: 'name:ASC',
},
},
]);
server.use(
rest.get('*/countManyEntriesDraftRelations', (req, res, ctx) => {
return res.once(
ctx.status(200),
ctx.json({
data: 2,
})
);
})
);
render();
await waitFor(() => {
const publishDialog = screen.getByRole('dialog');
expect(publishDialog).toBeInTheDocument();
within(publishDialog).getByText(/2 relations out of 2 entries are/i);
});
});
}); });

View File

@ -445,7 +445,7 @@ const SelectedEntriesModal = ({ onToggle }) => {
// We want to keep the selected entries order same as the list view // We want to keep the selected entries order same as the list view
const [ const [
{ {
query: { sort }, query: { sort, plugins },
}, },
] = useQueryParams(); ] = useQueryParams();
@ -458,6 +458,7 @@ const SelectedEntriesModal = ({ onToggle }) => {
$in: entriesToFetch, $in: entriesToFetch,
}, },
}, },
locale: plugins?.i18n?.locale,
}; };
const { get } = useFetchClient(); const { get } = useFetchClient();

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { lightTheme, ThemeProvider } from '@strapi/design-system'; import { lightTheme, ThemeProvider } from '@strapi/design-system';
import { Table } from '@strapi/helper-plugin'; import { Table, useQueryParams } from '@strapi/helper-plugin';
import { import {
render as renderRTL, render as renderRTL,
screen, screen,
@ -31,6 +31,11 @@ jest.mock('@strapi/helper-plugin', () => ({
{ {
query: { query: {
sort: 'name:DESC', sort: 'name:DESC',
plugins: {
i18n: {
locale: 'en',
},
},
}, },
}, },
]), ]),
@ -159,6 +164,32 @@ describe('Bulk publish selected entries modal', () => {
expect(screen.queryByText('Entry 4')).not.toBeInTheDocument(); expect(screen.queryByText('Entry 4')).not.toBeInTheDocument();
}); });
it('renders the selected items in the modal even if the locale param is not passed', async () => {
useQueryParams.mockImplementation(() => [
{
query: {
page: 1,
pageSize: 10,
sort: 'name:DESC',
},
},
]);
const { queryByText } = render(
<Table.Root defaultSelectedEntries={[1, 2, 3]} colCount={4}>
<SelectedEntriesModal onToggle={jest.fn()} />
</Table.Root>
);
await waitForElementToBeRemoved(() => queryByText('Loading content'));
expect(screen.getByText(/publish entries/i)).toBeInTheDocument();
// Nested table should render the selected items from the parent table
expect(screen.queryByText('Entry 1')).toBeInTheDocument();
expect(screen.queryByText('Entry 4')).not.toBeInTheDocument();
});
it('reacts to selection updates', async () => { it('reacts to selection updates', async () => {
const { queryByText } = render( const { queryByText } = render(
<Table.Root defaultSelectedEntries={[1, 2, 3]} colCount={4}> <Table.Root defaultSelectedEntries={[1, 2, 3]} colCount={4}>

View File

@ -445,6 +445,7 @@ module.exports = {
async countManyEntriesDraftRelations(ctx) { async countManyEntriesDraftRelations(ctx) {
const { userAbility } = ctx.state; const { userAbility } = ctx.state;
const ids = ctx.request.query.ids; const ids = ctx.request.query.ids;
const locale = ctx.request.query.locale;
const { model } = ctx.params; const { model } = ctx.params;
const entityManager = getService('entity-manager'); const entityManager = getService('entity-manager');
@ -454,13 +455,13 @@ module.exports = {
return ctx.forbidden(); return ctx.forbidden();
} }
const entities = await entityManager.find(ids, model); const entities = await entityManager.find({ ids, locale }, model);
if (!entities) { if (!entities) {
return ctx.notFound(); return ctx.notFound();
} }
const number = await entityManager.countManyEntriesDraftRelations(ids, model); const number = await entityManager.countManyEntriesDraftRelations(ids, model, locale);
return { return {
data: number, data: number,

View File

@ -11,7 +11,7 @@ interface EntityManager {
publish(): any; publish(): any;
unpublish(): any; unpublish(): any;
countDraftRelations(id: string, uid: string): number; countDraftRelations(id: string, uid: string): number;
countManyEntriesDraftRelations(ids: number[], uid: string): number; countManyEntriesDraftRelations(ids: number[], uid: string, locale?: string): number;
} }
export default function (opts: { strapi: Strapi }): EntityManager; export default function (opts: { strapi: Strapi }): EntityManager;

View File

@ -301,7 +301,7 @@ module.exports = ({ strapi }) => ({
return sumDraftCounts(entity, uid); return sumDraftCounts(entity, uid);
}, },
async countManyEntriesDraftRelations(ids, uid) { async countManyEntriesDraftRelations(ids, uid, locale = 'en') {
const { populate, hasRelations } = getDeepPopulateDraftCount(uid); const { populate, hasRelations } = getDeepPopulateDraftCount(uid);
if (!hasRelations) { if (!hasRelations) {
@ -311,6 +311,7 @@ module.exports = ({ strapi }) => ({
const entities = await strapi.entityService.findMany(uid, { const entities = await strapi.entityService.findMany(uid, {
populate, populate,
filters: { id: { $in: ids } }, filters: { id: { $in: ids } },
locale,
}); });
const totalNumberDraftRelations = entities.reduce( const totalNumberDraftRelations = entities.reduce(