diff --git a/packages/core/admin/admin/src/hooks/marketplace/constants.js b/packages/core/admin/admin/src/hooks/marketplace/constants.js index d2a017b8d0..26252d3d22 100644 --- a/packages/core/admin/admin/src/hooks/marketplace/constants.js +++ b/packages/core/admin/admin/src/hooks/marketplace/constants.js @@ -1 +1 @@ -export const MARKETPLACE_API_URL = 'https://market-api.strapi.io'; \ No newline at end of file +export const MARKETPLACE_API_URL = 'https://market-api.strapi.io'; diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js index b60c4b1db9..86cc72cc59 100644 --- a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js +++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js @@ -5,7 +5,18 @@ import { useFormikContext } from 'formik'; import { useIntl } from 'react-intl'; import styled from 'styled-components'; import EventRow from './EventRow'; -import formatValue from './utils/formatValue'; + +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 { diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/tests/formatValue.test.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/tests/formatValue.test.js index d622adb149..45f2e7f798 100644 --- a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/tests/formatValue.test.js +++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/tests/formatValue.test.js @@ -1,4 +1,4 @@ -import formatValue from '../utils/formatValue'; +import { formatValue } from '..'; describe('utils | formatValue', () => { it('should format array to object', () => { diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/utils/formatValue.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/utils/formatValue.js deleted file mode 100644 index 85f7641ab5..0000000000 --- a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/utils/formatValue.js +++ /dev/null @@ -1,13 +0,0 @@ -const formatValue = (value) => - value.reduce((acc, curr) => { - const key = curr.split('.')[0]; - - if (!acc[key]) { - acc[key] = []; - } - acc[key].push(curr); - - return acc; - }, {}); - -export default formatValue; diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/ListView/index.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/ListView/index.js index f4eedd593e..4f9ec37202 100644 --- a/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/ListView/index.js +++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/Webhooks/ListView/index.js @@ -1,13 +1,9 @@ /* eslint-disable no-nested-ternary */ -/** - * - * ListView - * - */ - -import React, { useEffect, useReducer, useRef, useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { useIntl } from 'react-intl'; +import { useQuery, useMutation } from 'react-query'; + import { useFetchClient, useRBAC, @@ -19,6 +15,7 @@ import { onRowClick, stopPropagation, LinkButton, + useAPIErrorHandler, } from '@strapi/helper-plugin'; import { HeaderLayout, @@ -45,212 +42,124 @@ import { VisuallyHidden, } from '@strapi/design-system'; import { Plus, Pencil, Trash, EmptyDocuments } from '@strapi/icons'; -import reducer, { initialState } from './reducer'; import adminPermissions from '../../../../../permissions'; const ListView = () => { - const { - isLoading, - allowedActions: { canCreate, canRead, canUpdate, canDelete }, - } = useRBAC(adminPermissions.settings.webhooks); - const toggleNotification = useNotification(); - const isMounted = useRef(true); - const { formatMessage } = useIntl(); const [showModal, setShowModal] = useState(false); - const [{ webhooks, webhooksToDelete, webhookToDelete, loadingWebhooks }, dispatch] = useReducer( - reducer, - initialState - ); - const { notifyStatus } = useNotifyAT(); - - const { get, del, post, put } = useFetchClient(); + const [webhooksToDelete, setWebhooksToDelete] = useState([]); + const { formatMessage } = useIntl(); + const { formatAPIError } = useAPIErrorHandler(); + const toggleNotification = useNotification(); useFocusWhenNavigate(); const { push } = useHistory(); const { pathname } = useLocation(); - const rowsCount = webhooks.length; - const webhooksToDeleteLength = webhooksToDelete.length; - const getWebhookIndex = (id) => webhooks.findIndex((webhook) => webhook.id === id); + + const { + isLoading: isRBACLoading, + allowedActions: { canCreate, canUpdate, canDelete }, + } = useRBAC(adminPermissions.settings.webhooks); + const { get, post, put } = useFetchClient(); + const { notifyStatus } = useNotifyAT(); + + const QUERY_KEY = 'webhooks'; + const { + isLoading: isWebhooksLoading, + data: webhooks, + error: webhooksError, + refetch: refetchWebhooks, + } = useQuery(QUERY_KEY, async () => { + const { + data: { data }, + } = await get('/admin/webhooks'); + + return data; + }); useEffect(() => { - isMounted.current = true; - - return () => { - isMounted.current = false; - }; - }, []); - - /** - * TODO: refactor this, but actually refactor - * the whole component. Needs some love. - */ - useEffect(() => { - const fetchWebHooks = async () => { - try { - const { - data: { data }, - } = await get('/admin/webhooks'); - - if (isMounted.current) { - dispatch({ - type: 'GET_DATA_SUCCEEDED', - data, - }); - notifyStatus('webhooks have been loaded'); - } - } catch (err) { - console.log(err); - - if (isMounted.current) { - if (err.code !== 20) { - toggleNotification({ - type: 'warning', - message: { id: 'notification.error' }, - }); - } - dispatch({ - type: 'TOGGLE_LOADING', - }); - } - } - }; - - if (canRead) { - fetchWebHooks(); - } - }, [canRead, get, notifyStatus, toggleNotification]); - - const handleToggleModal = () => { - setShowModal((prev) => !prev); - }; - - const handleConfirmDelete = () => { - if (webhookToDelete) { - handleConfirmDeleteOne(); - } else { - handleConfirmDeleteAll(); - } - }; - - const handleConfirmDeleteOne = async () => { - try { - await del(`/admin/webhooks/${webhookToDelete}`); - - dispatch({ - type: 'WEBHOOK_DELETED', - index: getWebhookIndex(webhookToDelete), + if (webhooksError) { + toggleNotification({ + type: 'warning', + message: formatAPIError(webhooksError), }); - } catch (err) { - /** - * TODO: especially this. - */ - if (err.code !== 20) { + + return; + } + if (webhooks) { + notifyStatus( + formatMessage({ + id: 'Settings.webhooks.list.loading.success', + defaultMessage: 'Webhooks have been loaded', + }) + ); + } + }, [webhooks, webhooksError, toggleNotification, formatMessage, notifyStatus, formatAPIError]); + + const deleteMutation = useMutation( + async () => { + await post('/admin/webhooks/batch-delete', { + ids: webhooksToDelete, + }); + }, + { + onError(error) { toggleNotification({ type: 'warning', - message: { id: 'notification.error' }, + message: formatAPIError(error), }); - } + setShowModal(false); + }, + onSuccess() { + setWebhooksToDelete([]); + setShowModal(false); + refetchWebhooks(); + }, } - setShowModal(false); - }; + ); - const handleConfirmDeleteAll = async () => { - const body = { - ids: webhooksToDelete, - }; - - try { - await post('/admin/webhooks/batch-delete', body); - - if (isMounted.current) { - dispatch({ - type: 'WEBHOOKS_DELETED', - }); - } - } catch (err) { - if (isMounted.current) { - if (err.code !== 20) { - toggleNotification({ - type: 'warning', - message: { id: 'notification.error' }, - }); - } - } - } - setShowModal(false); - }; - - const handleDeleteClick = (id) => { - setShowModal(true); - - if (id !== 'all') { - dispatch({ - type: 'SET_WEBHOOK_TO_DELETE', - id, - }); - } - }; - - const handleEnabledChange = async (value, id) => { - const webhookIndex = getWebhookIndex(id); - const initialWebhookProps = webhooks[webhookIndex]; - const keys = [webhookIndex, 'isEnabled']; - - const body = { - ...initialWebhookProps, - isEnabled: value, - }; - - delete body.id; - - try { - dispatch({ - type: 'SET_WEBHOOK_ENABLED', - keys, - value, - }); + const enabledMutation = useMutation( + async ({ isEnabled, id }) => { + const { id: _, ...webhook } = webhooks.find((webhook) => webhook.id === id) ?? {}; + const body = { + ...webhook, + isEnabled, + }; await put(`/admin/webhooks/${id}`, body); - } catch (err) { - if (isMounted.current) { - dispatch({ - type: 'SET_WEBHOOK_ENABLED', - keys, - value: !value, + }, + { + onError(error) { + toggleNotification({ + type: 'warning', + message: formatAPIError(error), }); - - if (err.code !== 20) { - toggleNotification({ - type: 'warning', - message: { id: 'notification.error' }, - }); - } - } + }, + onSuccess() { + refetchWebhooks(); + }, } - }; + ); - const handleSelectAllCheckbox = () => { - dispatch({ - type: 'SET_ALL_WEBHOOKS_TO_DELETE', - }); - }; + const confirmDelete = () => deleteMutation.mutate(); - const handleSelectOneCheckbox = (value, id) => { - dispatch({ - type: 'SET_WEBHOOKS_TO_DELETE', - value, - id, - }); - }; + const selectAllCheckbox = (selected) => + selected ? setWebhooksToDelete(webhooks.map((webhook) => webhook.id)) : setWebhooksToDelete([]); - const handleGoTo = (to) => { - push(`${pathname}/${to}`); - }; + const selectOneCheckbox = (selected, id) => + selected + ? setWebhooksToDelete((prev) => [...prev, id]) + : setWebhooksToDelete((prev) => prev.filter((webhookId) => webhookId !== id)); + + const goTo = (to) => push(`${pathname}/${to}`); + + const isLoading = isRBACLoading || isWebhooksLoading; + const numberOfWebhooks = webhooks?.length ?? 0; + const webhooksToDeleteLength = webhooksToDelete.length; return ( -
+
{ })} primaryAction={ canCreate && - !loadingWebhooks && ( + !isLoading && ( } variant="default" to={`${pathname}/create`} size="S"> {formatMessage({ id: 'Settings.webhooks.list.button.add', @@ -278,13 +187,13 @@ const ListView = () => { { id: 'Settings.webhooks.to.delete', defaultMessage: - '{webhooksToDeleteLength, plural, one {# asset} other {# assets}} selected', + '{webhooksToDeleteLength, plural, one {# webhook} other {# webhooks}} selected', }, { webhooksToDeleteLength } )}