Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publish multiple locales #20258

Merged
merged 47 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
d7df668
fix: date comparison
Marc-Roig Mar 15, 2024
07cbc85
Merge branch 'v5/main' into v5/modified-date-comparison
Marc-Roig Mar 18, 2024
42b14e3
Merge branch 'v5/main' into v5/modified-date-comparison
Marc-Roig Mar 22, 2024
7a1af3e
feat(core): document service publish multiple locales (#20046)
jhoward1994 May 3, 2024
636c12f
Merge remote-tracking branch 'origin/v5/main' into feat/bulk-locale-p…
jhoward1994 May 3, 2024
318ffe7
fix(i18n): disable publish button after bulk locale publish
jhoward1994 May 3, 2024
c11cdf0
Merge remote-tracking branch 'origin/v5/main' into feat/bulk-locale-p…
jhoward1994 May 7, 2024
3d74be8
Merge remote-tracking branch 'origin/v5/main' into feat/bulk-locale-p…
jhoward1994 May 7, 2024
2e49ae8
fix(content-manager): ce e2e fix
jhoward1994 May 7, 2024
f993044
Merge remote-tracking branch 'origin/v5/main' into feat/bulk-locale-p…
jhoward1994 May 7, 2024
720a3b7
chore: typography
jhoward1994 May 7, 2024
ccc1284
fix(i18n): e2e edit view test
jhoward1994 May 7, 2024
4daeb8b
fix: wip date comparison
jhoward1994 May 7, 2024
da42f0a
Merge remote-tracking branch 'origin/v5/main' into feat/bulk-locale-p…
jhoward1994 May 8, 2024
1c83516
Merge remote-tracking branch 'origin/v5/modified-date-comparison' int…
jhoward1994 May 8, 2024
62100b2
fix: wip date comparison
jhoward1994 May 8, 2024
75684ac
fix(content-manager): simplify date comparison
jhoward1994 May 8, 2024
34fc28b
Merge remote-tracking branch 'origin/v5/main' into v5/modified-date-c…
jhoward1994 May 8, 2024
575b2a3
fix: clean up metadata api test
jhoward1994 May 8, 2024
a92d6ab
Merge remote-tracking branch 'origin/v5/modified-date-comparison' int…
jhoward1994 May 8, 2024
227bcb8
chore: update api tests
jhoward1994 May 8, 2024
b8e94ca
fix: draft versions must be ahead of published to be considered modified
jhoward1994 May 8, 2024
fcb4ff3
Merge remote-tracking branch 'origin/v5/modified-date-comparison' int…
jhoward1994 May 8, 2024
bd482a7
fix: published modified calculation
jhoward1994 May 8, 2024
84aa3b6
Merge remote-tracking branch 'origin/v5/modified-date-comparison' int…
jhoward1994 May 8, 2024
a6c4f4b
fix: clean up
jhoward1994 May 8, 2024
f4e3eb1
fix: simplify draft and publish comparison
jhoward1994 May 8, 2024
95c018d
Merge remote-tracking branch 'origin/v5/main' into v5/modified-date-c…
jhoward1994 May 8, 2024
7175749
Merge remote-tracking branch 'origin/v5/modified-date-comparison' int…
jhoward1994 May 8, 2024
4a71a9f
chore: clean up
jhoward1994 May 9, 2024
17c8f06
fix: flaky fe tests
jhoward1994 May 9, 2024
c748572
Merge remote-tracking branch 'origin/fix/flaky-fe-tests' into v5/modi…
jhoward1994 May 9, 2024
ae62477
Merge remote-tracking branch 'origin/v5/main' into v5/modified-date-c…
jhoward1994 May 9, 2024
a4dea43
fix: pr feedback
jhoward1994 May 9, 2024
9e081e5
Merge remote-tracking branch 'origin/v5/main' into feat/bulk-locale-p…
jhoward1994 May 9, 2024
5a31d9c
Merge remote-tracking branch 'origin/v5/main' into v5/modified-date-c…
jhoward1994 May 9, 2024
48b5756
Merge remote-tracking branch 'origin/v5/modified-date-comparison' int…
jhoward1994 May 9, 2024
37c6f02
Merge remote-tracking branch 'origin/v5/main' into feat/bulk-locale-p…
jhoward1994 May 9, 2024
4837913
Merge remote-tracking branch 'origin/v5/main' into feat/bulk-locale-p…
jhoward1994 May 9, 2024
c8e3445
fix(i18n): error message extraction in bulk locale modal
jhoward1994 May 10, 2024
1fc9670
chore: remove old publish action
jhoward1994 May 10, 2024
f4e57ad
chore: pr feedback
jhoward1994 May 10, 2024
20e066c
chore: refactor error types & validation messages
joshuaellis May 10, 2024
d3533ae
chore: use anchor link for locale changes
jhoward1994 May 10, 2024
b30d472
chore: fix releases
joshuaellis May 10, 2024
9f3da84
fix: clean up
jhoward1994 May 10, 2024
90359f0
chore: snapshot
jhoward1994 May 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 28 additions & 13 deletions packages/core/admin/admin/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -228,18 +228,7 @@ const Form = React.forwardRef<HTMLFormElement, FormProps>(
return { data };
} catch (err) {
if (isErrorYupValidationError(err)) {
let errors: FormErrors = {};

if (err.inner) {
if (err.inner.length === 0) {
return setIn(errors, err.path!, err.message);
}
for (const error of err.inner) {
if (!getIn(errors, error.path!)) {
errors = setIn(errors, error.path!, error.message);
}
}
}
const errors = getYupValidationErrors(err);

if (shouldSetErrors) {
setErrors(errors);
Expand Down Expand Up @@ -470,6 +459,31 @@ const isErrorYupValidationError = (err: any): err is Yup.ValidationError =>
typeof err.name === 'string' &&
err.name === 'ValidationError';

/* -------------------------------------------------------------------------------------------------
* getYupValidationErrors
* -----------------------------------------------------------------------------------------------*/

/**
* @description handy utility to convert a yup validation error into a form
* error object. To be used elsewhere.
*/
const getYupValidationErrors = (err: Yup.ValidationError): FormErrors => {
let errors: FormErrors = {};

if (err.inner) {
if (err.inner.length === 0) {
return setIn(errors, err.path!, err.message);
}
for (const error of err.inner) {
if (!getIn(errors, error.path!)) {
errors = setIn(errors, error.path!, error.message);
}
}
}

return errors;
};

/* -------------------------------------------------------------------------------------------------
* reducer
* -----------------------------------------------------------------------------------------------*/
Expand Down Expand Up @@ -777,8 +791,9 @@ const Blocker = ({ onProceed = () => {}, onCancel = () => {} }: BlockerProps) =>
return null;
};

export { Form, Blocker, useField, useForm };
export { Form, Blocker, useField, useForm, getYupValidationErrors };
export type {
FormErrors,
FormHelpers,
FormProps,
FormValues,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ const GridLayout = ({ size, children }: GridLayoutProps) => {
};

export { GridLayout };
export type { GridColSize };
export type { GridLayoutProps, GridColSize };
4 changes: 2 additions & 2 deletions packages/core/admin/admin/src/components/Layouts/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { styled } from 'styled-components';

import { ActionLayout } from './ActionLayout';
import { ContentLayout } from './ContentLayout';
import { GridLayout } from './GridLayout';
import { GridLayout, GridLayoutProps } from './GridLayout';
import { HeaderLayout, BaseHeaderLayout } from './HeaderLayout';

interface LayoutProps {
Expand Down Expand Up @@ -40,4 +40,4 @@ const Layouts = {
Content: ContentLayout,
};

export { Layouts, type LayoutProps };
export { Layouts, type LayoutProps, type GridLayoutProps };
1 change: 1 addition & 0 deletions packages/core/admin/admin/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@
"app.utils.unpublish": "Unpublish",
"app.utils.published": "Published",
"app.utils.ready-to-publish": "Ready to publish",
"app.utils.ready-to-publish-changes": "Ready to publish changes",
"app.confirm.body": "Are you sure?",
"clearLabel": "Clear",
"coming.soon": "This content is currently under construction and will be back in a few weeks!",
Expand Down
2 changes: 2 additions & 0 deletions packages/core/content-manager/admin/src/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* but should still export the same things.
*/

export { buildValidParams } from './utils/api';

export { useDocument as unstable_useDocument } from './hooks/useDocument';
export { useDocumentActions as unstable_useDocumentActions } from './hooks/useDocumentActions';
export { useDocumentLayout as unstable_useDocumentLayout } from './hooks/useDocumentLayout';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,7 @@ describe('useDocument', () => {
})
).toMatchInlineSnapshot(`
{
"postal_code": {
"defaultMessage": "postal_code must be a \`string\` type, but the final value was: \`12\`.",
"id": "postal_code must be a \`string\` type, but the final value was: \`12\`.",
"values": {
"typeError": undefined,
},
},
"postal_code": "postal_code must be a \`string\` type, but the final value was: \`12\`.",
}
`);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('useDocumentActions', () => {

expect(result.current).toEqual({
autoClone: expect.any(Function),
publishMany: expect.any(Function),
clone: expect.any(Function),
create: expect.any(Function),
discard: expect.any(Function),
Expand Down
21 changes: 12 additions & 9 deletions packages/core/content-manager/admin/src/hooks/useDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,26 @@

import * as React from 'react';

import { useNotification, useAPIErrorHandler, useQueryParams } from '@strapi/admin/strapi-admin';
import {
useNotification,
useAPIErrorHandler,
useQueryParams,
FormErrors,
getYupValidationErrors,
} from '@strapi/admin/strapi-admin';
import { Modules } from '@strapi/types';
import { useParams } from 'react-router-dom';
import { ValidationError } from 'yup';

import { SINGLE_TYPES } from '../constants/collections';
import { useGetDocumentQuery } from '../services/documents';
import { buildValidParams } from '../utils/api';
import { createYupSchema, getInnerErrors } from '../utils/validation';
import { createYupSchema } from '../utils/validation';

import { useContentTypeSchema, ComponentsDictionary } from './useContentTypeSchema';

import type { FindOne } from '../../../shared/contracts/collection-types';
import type { ContentType } from '../../../shared/contracts/content-types';
import type { MessageDescriptor, PrimitiveType } from 'react-intl';

interface UseDocumentArgs {
collectionType: string;
Expand Down Expand Up @@ -50,9 +56,7 @@ type UseDocument = (
* This is the schema of the content type, it is not the same as the layout.
*/
schema?: Schema;
validate: (
document: Document
) => null | Record<string, MessageDescriptor & { values?: Record<string, PrimitiveType> }>;
validate: (document: Document) => null | FormErrors;
};

/* -------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -117,7 +121,7 @@ const useDocument: UseDocument = (args, opts) => {
}, [schema, components]);

const validate = React.useCallback(
(document: Document) => {
(document: Modules.Documents.AnyDocument): FormErrors | null => {
if (!validationSchema) {
throw new Error(
'There is no validation schema generated, this is likely due to the schema not being loaded yet.'
Expand All @@ -126,11 +130,10 @@ const useDocument: UseDocument = (args, opts) => {

try {
validationSchema.validateSync(document, { abortEarly: false, strict: true });

return null;
} catch (error) {
if (error instanceof ValidationError) {
return getInnerErrors(error);
return getYupValidationErrors(error);
}

throw error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
useDiscardDocumentMutation,
useLazyGetDocumentQuery,
usePublishDocumentMutation,
usePublishManyDocumentsMutation,
useUnpublishDocumentMutation,
useUnpublishManyDocumentsMutation,
useUpdateDocumentMutation,
Expand All @@ -37,6 +38,7 @@ import type {
Publish,
Update,
Unpublish,
BulkPublish,
BulkUnpublish,
} from '../../../shared/contracts/collection-types';

Expand All @@ -45,7 +47,8 @@ const DEFAULT_UNEXPECTED_ERROR_MSG = {
defaultMessage: 'An error occurred, please try again',
} satisfies MessageDescriptor;

type OperationResponse<TResponse extends { data: any; meta: any; error?: any }> =
type OperationResponse<TResponse extends { data: any; meta?: any; error?: any }> =
| Pick<TResponse, 'data'>
| Pick<TResponse, 'data' | 'meta'>
| { error: BaseQueryError | SerializedError };

Expand Down Expand Up @@ -124,6 +127,11 @@ type UseDocumentActions = () => {
},
document: Partial<Document>
) => Promise<OperationResponse<Publish.Response>>;
publishMany: (args: {
model: string;
documentIds: string[];
params?: object;
}) => Promise<BulkOperationResponse<BulkPublish.Response>>;
update: (
args: {
collectionType: string;
Expand Down Expand Up @@ -361,6 +369,48 @@ const useDocumentActions: UseDocumentActions = () => {
[trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
);

const [publishManyDocuments] = usePublishManyDocumentsMutation();
const publishMany: IUseDocumentActs['publishMany'] = React.useCallback(
async ({ model, documentIds, params }) => {
try {
// TODO Confirm tracking events for bulk publish?

const res = await publishManyDocuments({
model,
documentIds,
params,
});
if ('error' in res) {
toggleNotification({ type: 'danger', message: formatAPIError(res.error) });
return { error: res.error };
}

toggleNotification({
type: 'success',
message: formatMessage({
id: getTranslation('success.record.publish'),
defaultMessage: 'Published document',
}),
});

return res.data;
} catch (err) {
toggleNotification({
type: 'danger',
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG),
});
throw err;
}
},
[
// trackUsage,
publishManyDocuments,
toggleNotification,
formatMessage,
formatAPIError,
]
);

const [updateDocument] = useUpdateDocumentMutation();
const update: IUseDocumentActs['update'] = React.useCallback(
async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
Expand Down Expand Up @@ -644,6 +694,7 @@ const useDocumentActions: UseDocumentActions = () => {
discard,
getDocument,
publish,
publishMany,
unpublish,
unpublishMany,
update,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ interface NotificationOptions {
interface ModalOptions {
type: 'modal';
title: string;
content: React.ReactNode;
content: React.ComponentType<{ onClose: () => void }> | React.ReactNode;
footer: React.ComponentType<{ onClose: () => void }> | React.ReactNode;
onClose?: () => void;
}
Expand Down Expand Up @@ -438,7 +438,7 @@ const DocumentActionModal = ({
title,
onClose,
footer: Footer,
content,
content: Content,
onModalClose,
}: DocumentActionModalProps) => {
const id = React.useId();
Expand All @@ -462,7 +462,9 @@ const DocumentActionModal = ({
{title}
</Typography>
</ModalHeader>
<ModalBody>{content}</ModalBody>
<ModalBody>
{typeof Content === 'function' ? <Content onClose={handleClose} /> : Content}
</ModalBody>
<Box
paddingTop={4}
paddingBottom={4}
Expand Down