diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js new file mode 100644 index 0000000000..ac8ab76af2 --- /dev/null +++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js @@ -0,0 +1,266 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; + +import { useFormikContext } from 'formik'; +import { useIntl } from 'react-intl'; +import styled from 'styled-components'; +import upperFirst from 'lodash/upperFirst'; +import { FieldLabel, Flex, Typography, BaseCheckbox, Checkbox } from '@strapi/design-system'; + +import { useModels } from '../../../../../../../hooks'; + +export const formatValue = (value) => + value.reduce((acc, curr) => { + const key = curr.split('.')[0]; + + if (!acc[key]) { + acc[key] = []; + } + acc[key].push(curr); + + return acc; + }, {}); + +const StyledTable = styled.table` + td { + height: ${52 / 16}rem; + width: 10%; + vertical-align: middle; + text-align: center; + } + + tbody tr:nth-child(odd) { + background: ${({ theme }) => theme.colors.neutral100}; + } + + tbody tr td:first-child { + padding-left: ${({ theme }) => theme.spaces[7]}; + } +`; + +const getHeaders = (isDraftAndPublish) => { + if (isDraftAndPublish) { + return [ + { id: 'Settings.webhooks.events.create', defaultMessage: 'Create' }, + { id: 'Settings.webhooks.events.update', defaultMessage: 'Update' }, + { id: 'app.utils.delete', defaultMessage: 'Delete' }, + { id: 'app.utils.publish', defaultMessage: 'Publish' }, + { id: 'app.utils.unpublish', defaultMessage: 'Unpublish' }, + ]; + } + + return [ + { id: 'Settings.webhooks.events.create', defaultMessage: 'Create' }, + { id: 'Settings.webhooks.events.update', defaultMessage: 'Update' }, + { id: 'app.utils.delete', defaultMessage: 'Delete' }, + ]; +}; + +const getEvents = (isDraftAndPublish) => { + if (isDraftAndPublish) { + return { + entry: ['entry.create', 'entry.update', 'entry.delete', 'entry.publish', 'entry.unpublish'], + media: ['media.create', 'media.update', 'media.delete'], + }; + } + + return { + entry: ['entry.create', 'entry.update', 'entry.delete'], + media: ['media.create', 'media.update', 'media.delete'], + }; +}; + +const Root = (props) => { + const { formatMessage } = useIntl(); + const { collectionTypes } = useModels(); + + const isDraftAndPublish = React.useMemo( + () => collectionTypes.some((ct) => ct.options.draftAndPublish === true), + [collectionTypes] + ); + + return ( + + + {formatMessage({ + id: 'Settings.webhooks.form.events', + defaultMessage: 'Events', + })} + + + {React.Children.map(props.children, (child) => { + return React.cloneElement(child, { ...props, isDraftAndPublish }); + })} + + + ); +}; + +Root.propTypes = { + children: PropTypes.node.isRequired, +}; + +const Headers = ({ isDraftAndPublish }) => { + const { formatMessage } = useIntl(); + const headers = getHeaders(isDraftAndPublish); + + return ( + + + + {headers.map((header) => { + if (header.id === 'app.utils.publish' || header.id === 'app.utils.unpublish') { + return ( + + + {formatMessage(header)} + + + ); + } + + return ( + + + {formatMessage(header)} + + + ); + })} + + + ); +}; + +Headers.propTypes = { + isDraftAndPublish: PropTypes.bool.isRequired, +}; + +const Body = ({ isDraftAndPublish }) => { + const events = getEvents(isDraftAndPublish); + const { values, handleChange: onChange } = useFormikContext(); + + const inputName = 'events'; + const inputValue = values.events; + const disabledEvents = []; + + const formattedValue = formatValue(inputValue); + + const handleChange = ({ target: { name, value } }) => { + let set = new Set(inputValue); + + if (value) { + set.add(name); + } else { + set.delete(name); + } + onChange({ target: { name: inputName, value: Array.from(set) } }); + }; + + const handleChangeAll = ({ target: { name, value } }) => { + let set = new Set(inputValue); + + if (value) { + events[name].forEach((event) => { + if (!disabledEvents.includes(event)) { + set.add(event); + } + }); + } else { + events[name].forEach((event) => set.delete(event)); + } + onChange({ target: { name: inputName, value: Array.from(set) } }); + }; + + return ( + + {Object.keys(events).map((event) => { + return ( + + ); + })} + + ); +}; + +Body.propTypes = { + isDraftAndPublish: PropTypes.bool.isRequired, +}; + +const EventRow = ({ disabledEvents, name, events, inputValue, handleChange, handleChangeAll }) => { + const enabledCheckboxes = events.filter((event) => !disabledEvents.includes(event)); + + const areAllCheckboxesSelected = inputValue.length === enabledCheckboxes.length; + const hasSomeCheckboxSelected = inputValue.length > 0; + + const onChangeAll = ({ target: { name } }) => { + const valueToSet = !areAllCheckboxesSelected; + + handleChangeAll({ + target: { name, value: valueToSet }, + }); + }; + + return ( + + + + {upperFirst(name)} + + + + {events.map((event) => { + return ( + + handleChange({ target: { name: event, value } })} + /> + + ); + })} + + ); +}; + +EventRow.defaultProps = { + disabledEvents: [], + events: [], + inputValue: [], + handleChange() {}, + handleChangeAll() {}, +}; + +EventRow.propTypes = { + disabledEvents: PropTypes.array, + events: PropTypes.array, + inputValue: PropTypes.array, + handleChange: PropTypes.func, + handleChangeAll: PropTypes.func, + name: PropTypes.string.isRequired, +}; + +export default { Root, Headers, Body, EventRow }; diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/tests/formatValue.test.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/tests/formatValue.test.js new file mode 100644 index 0000000000..45f2e7f798 --- /dev/null +++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/tests/formatValue.test.js @@ -0,0 +1,15 @@ +import { formatValue } from '..'; + +describe('utils | formatValue', () => { + it('should format array to object', () => { + const initialValue = ['entry.create', 'entry.update', 'media.delete']; + const expectedValue = { + entry: ['entry.create', 'entry.update'], + media: ['media.delete'], + }; + + const formattedValue = formatValue(initialValue); + + expect(formattedValue).toEqual(expectedValue); + }); +}); diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/index.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/index.js index 0153c6a883..8eb7ef2110 100644 --- a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/index.js +++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/index.js @@ -1,8 +1,3 @@ -/** - * - * EditView - * - */ import * as React from 'react'; import { LoadingIndicatorPage, @@ -27,7 +22,7 @@ const EditView = () => { const { lockApp, unlockApp } = useOverlayBlocker(); const toggleNotification = useNotification(); const queryClient = useQueryClient(); - const { isLoading: isLoadingForModels, collectionTypes } = useModels(); + const { isLoading: isLoadingForModels } = useModels(); const { put, get, post } = useFetchClient(); const isCreating = id === 'create'; @@ -123,11 +118,6 @@ const EditView = () => { } }; - const isDraftAndPublishEvents = React.useMemo( - () => collectionTypes.some((ct) => ct.options.draftAndPublish === true), - [collectionTypes] - ); - if (isLoading || isLoadingForModels) { return ; } @@ -144,7 +134,6 @@ const EditView = () => { isTriggering, isTriggerIdle, triggerResponse: triggerResponse?.data.data, - isDraftAndPublishEvents, }} />