From 7f686adbbb1d4a1b69864f0917535ec027c94a28 Mon Sep 17 00:00:00 2001 From: Wouter Konecny Date: Tue, 7 Jul 2026 15:01:19 +0200 Subject: [PATCH 1/2] feat: rework menu management UI with overview and detail pages Replace the navigation dropdown and Manage modal with a CMS-style overview page listing all navigations in a table (create, edit, delete, cache purge), and turn the item editor into a URL-driven detail page with a back link. - add OverviewPage as the plugin landing route, DetailPage at /:documentId - rename pages/HomePage to pages/DetailPage - move shared API/permission hooks to admin/src/hooks - remove the NavigationManager modal, reuse its form in the overview modal - add pages.overview translations to all locales, drop obsolete manager keys --- admin/src/hooks/index.ts | 2 + .../src/{pages/HomePage => }/hooks/useAPI.ts | 6 +- .../hooks/useSettingsPermissions.ts | 2 +- admin/src/pages/App.tsx | 21 +- .../components/ChangeLanguageDialog/index.tsx | 0 .../components/CollapseButton/index.tsx | 0 .../components/ControllableCombobox/index.tsx | 0 .../components/DragButton/index.tsx | 0 .../I18nCopyNavigationItems/index.tsx | 0 .../ManageNavigationItems/index.tsx | 0 .../NavigationContentHeader/Search/index.tsx | 0 .../NavigationContentHeader/index.tsx | 0 .../components/NavigationEmptyState/index.tsx | 2 +- .../components/NavigationHeader/index.tsx | 120 ++++++ .../components/NavigationHeader/styles.ts | 0 .../AdditionalFieldInput/index.tsx | 0 .../AdditionalFields/AudienceField/index.tsx | 0 .../CustomFieldsField/index.tsx | 0 .../components/AdditionalFields/index.tsx | 0 .../components/AttachToMenuField/index.tsx | 0 .../components/CopyFromLocales/index.tsx | 0 .../components/ManualPathField/index.tsx | 0 .../NavigationItemTypeField/index.tsx | 0 .../components/PathField/index.tsx | 0 .../ReadFieldsFromRelatedField/index.tsx | 0 .../components/RelatedEntityField/hooks.ts | 0 .../components/RelatedEntityField/index.tsx | 0 .../components/RelatedTypeField/index.tsx | 0 .../components/TitleField/index.tsx | 0 .../context/NavigationItemFormContext.ts | 0 .../components/NavigationItemForm/index.tsx | 0 .../components/NavigationItemForm/types.ts | 0 .../NavigationItemForm/utils/form.ts | 0 .../NavigationItemForm/utils/hooks.ts | 0 .../NavigationItemForm/utils/properties.ts | 2 +- .../components/NavigationItemList/Wrapper.ts | 0 .../components/NavigationItemList/index.tsx | 0 .../ItemCardBadge/index.ts | 0 .../ItemCardHeader/Wrapper.tsx | 0 .../ItemCardHeader/icons.tsx | 0 .../ItemCardHeader/index.tsx | 0 .../ItemCardRemovedOverlay/index.ts | 0 .../NavigationItemListItem/Wrapper.ts | 0 .../NavigationItemListItem/index.tsx | 0 .../NavigationItemPopupFooter.tsx | 0 .../NavigationItemPopupHeader.tsx | 0 .../components/NavigationItemPopup/index.tsx | 0 .../components/index.ts | 0 .../{HomePage => DetailPage}/hooks/index.tsx | 3 +- .../hooks/useI18nCopyNavigationItemsModal.tsx | 0 .../hooks/useInvalidateQueries.ts | 0 .../hooks/useLocales.ts | 0 .../hooks/useNavigationItemPopup.ts | 0 .../hooks/usePluginMediaQuery.tsx | 0 .../hooks/useSearch.ts | 0 .../pages/{HomePage => DetailPage}/index.tsx | 63 ++- .../{HomePage => DetailPage}/utils/index.ts | 0 .../{HomePage => DetailPage}/utils/parsers.ts | 0 .../components/NavigationHeader/hooks.tsx | 25 -- .../components/NavigationHeader/index.tsx | 238 ----------- .../AllNavigations/icons.tsx | 6 - .../AllNavigations/index.tsx | 263 ------------- .../DeletionConfirm/index.tsx | 53 --- .../NavigationManager/ErrorDetails/index.tsx | 48 --- .../NavigationManager/Footer/index.tsx | 44 --- .../NavigationUpdate/index.tsx | 63 --- .../NavigationManager/NewNavigation/index.tsx | 59 --- .../PurgeCacheConfirm/index.tsx | 53 --- .../components/NavigationManager/index.tsx | 319 --------------- .../components/NavigationManager/types.ts | 68 ---- .../components/NavigationForm}/hooks.ts | 0 .../components/NavigationForm}/index.tsx | 10 +- .../components/NavigationFormModal/index.tsx | 77 ++++ admin/src/pages/OverviewPage/index.tsx | 369 ++++++++++++++++++ admin/src/pages/OverviewPage/types.ts | 8 + admin/src/translations/ca.ts | 108 ++--- admin/src/translations/de.ts | 108 ++--- admin/src/translations/en.ts | 108 ++--- admin/src/translations/es.ts | 109 +++--- admin/src/translations/fr.ts | 108 ++--- admin/src/translations/tr.ts | 108 ++--- .../HomePage => }/utils/appendViewId.ts | 2 +- 82 files changed, 1004 insertions(+), 1571 deletions(-) create mode 100644 admin/src/hooks/index.ts rename admin/src/{pages/HomePage => }/hooks/useAPI.ts (97%) rename admin/src/{pages/HomePage => }/hooks/useSettingsPermissions.ts (89%) rename admin/src/pages/{HomePage => DetailPage}/components/ChangeLanguageDialog/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/CollapseButton/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/ControllableCombobox/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/DragButton/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/I18nCopyNavigationItems/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationContentHeader/ManageNavigationItems/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationContentHeader/Search/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationContentHeader/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationEmptyState/index.tsx (98%) create mode 100644 admin/src/pages/DetailPage/components/NavigationHeader/index.tsx rename admin/src/pages/{HomePage => DetailPage}/components/NavigationHeader/styles.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/AdditionalFields/AdditionalFieldInput/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/AdditionalFields/AudienceField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/AdditionalFields/CustomFieldsField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/AdditionalFields/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/AttachToMenuField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/CopyFromLocales/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/ManualPathField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/NavigationItemTypeField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/PathField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/ReadFieldsFromRelatedField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/RelatedEntityField/hooks.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/RelatedEntityField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/RelatedTypeField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/components/TitleField/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/context/NavigationItemFormContext.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/types.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/utils/form.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/utils/hooks.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemForm/utils/properties.ts (97%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemList/Wrapper.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemList/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemListItem/ItemCardBadge/index.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemListItem/ItemCardHeader/Wrapper.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemListItem/ItemCardHeader/icons.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemListItem/ItemCardHeader/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemListItem/ItemCardRemovedOverlay/index.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemListItem/Wrapper.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemListItem/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemPopup/NavigationItemPopupFooter.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemPopup/NavigationItemPopupHeader.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/NavigationItemPopup/index.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/components/index.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/hooks/index.tsx (77%) rename admin/src/pages/{HomePage => DetailPage}/hooks/useI18nCopyNavigationItemsModal.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/hooks/useInvalidateQueries.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/hooks/useLocales.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/hooks/useNavigationItemPopup.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/hooks/usePluginMediaQuery.tsx (100%) rename admin/src/pages/{HomePage => DetailPage}/hooks/useSearch.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/index.tsx (85%) rename admin/src/pages/{HomePage => DetailPage}/utils/index.ts (100%) rename admin/src/pages/{HomePage => DetailPage}/utils/parsers.ts (100%) delete mode 100644 admin/src/pages/HomePage/components/NavigationHeader/hooks.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationHeader/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/AllNavigations/icons.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/AllNavigations/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/DeletionConfirm/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/ErrorDetails/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/Footer/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/NavigationUpdate/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/NewNavigation/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/PurgeCacheConfirm/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/index.tsx delete mode 100644 admin/src/pages/HomePage/components/NavigationManager/types.ts rename admin/src/pages/{HomePage/components/NavigationManager/Form => OverviewPage/components/NavigationForm}/hooks.ts (100%) rename admin/src/pages/{HomePage/components/NavigationManager/Form => OverviewPage/components/NavigationForm}/index.tsx (96%) create mode 100644 admin/src/pages/OverviewPage/components/NavigationFormModal/index.tsx create mode 100644 admin/src/pages/OverviewPage/index.tsx create mode 100644 admin/src/pages/OverviewPage/types.ts rename admin/src/{pages/HomePage => }/utils/appendViewId.ts (76%) diff --git a/admin/src/hooks/index.ts b/admin/src/hooks/index.ts new file mode 100644 index 00000000..b01e8b8e --- /dev/null +++ b/admin/src/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './useAPI'; +export * from './useSettingsPermissions'; diff --git a/admin/src/pages/HomePage/hooks/useAPI.ts b/admin/src/hooks/useAPI.ts similarity index 97% rename from admin/src/pages/HomePage/hooks/useAPI.ts rename to admin/src/hooks/useAPI.ts index 8ef07de8..d64afdd5 100644 --- a/admin/src/pages/HomePage/hooks/useAPI.ts +++ b/admin/src/hooks/useAPI.ts @@ -2,9 +2,9 @@ import { getFetchClient } from '@strapi/strapi/admin'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useCallback } from 'react'; -import { getApiClient } from '../../../api'; -import { NavigationSchema } from '../../../api/validators'; -import { Effect } from '../../../types'; +import { getApiClient } from '../api'; +import { NavigationSchema } from '../api/validators'; +import { Effect } from '../types'; import { appendViewId } from '../utils/appendViewId'; export const useLocale = () => { diff --git a/admin/src/pages/HomePage/hooks/useSettingsPermissions.ts b/admin/src/hooks/useSettingsPermissions.ts similarity index 89% rename from admin/src/pages/HomePage/hooks/useSettingsPermissions.ts rename to admin/src/hooks/useSettingsPermissions.ts index 38ec20ff..214bbba4 100644 --- a/admin/src/pages/HomePage/hooks/useSettingsPermissions.ts +++ b/admin/src/hooks/useSettingsPermissions.ts @@ -2,7 +2,7 @@ import { useMemo } from 'react'; import { useRBAC } from '@strapi/strapi/admin'; -import pluginPermissions from '../../../utils/permissions'; +import pluginPermissions from '../utils/permissions'; export const useSettingsPermissions = () => { const viewPermissions = useMemo( diff --git a/admin/src/pages/App.tsx b/admin/src/pages/App.tsx index 79994162..002a900e 100644 --- a/admin/src/pages/App.tsx +++ b/admin/src/pages/App.tsx @@ -1,18 +1,25 @@ import { Page } from '@strapi/strapi/admin'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import { Route, Routes } from 'react-router-dom'; -import { HomePage } from './HomePage'; +import { DetailPage } from './DetailPage'; +import { OverviewPage } from './OverviewPage'; + +const queryClient = new QueryClient(); const App = () => { return ( - - - - - - + + + + + + + + + ); }; diff --git a/admin/src/pages/HomePage/components/ChangeLanguageDialog/index.tsx b/admin/src/pages/DetailPage/components/ChangeLanguageDialog/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/ChangeLanguageDialog/index.tsx rename to admin/src/pages/DetailPage/components/ChangeLanguageDialog/index.tsx diff --git a/admin/src/pages/HomePage/components/CollapseButton/index.tsx b/admin/src/pages/DetailPage/components/CollapseButton/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/CollapseButton/index.tsx rename to admin/src/pages/DetailPage/components/CollapseButton/index.tsx diff --git a/admin/src/pages/HomePage/components/ControllableCombobox/index.tsx b/admin/src/pages/DetailPage/components/ControllableCombobox/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/ControllableCombobox/index.tsx rename to admin/src/pages/DetailPage/components/ControllableCombobox/index.tsx diff --git a/admin/src/pages/HomePage/components/DragButton/index.tsx b/admin/src/pages/DetailPage/components/DragButton/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/DragButton/index.tsx rename to admin/src/pages/DetailPage/components/DragButton/index.tsx diff --git a/admin/src/pages/HomePage/components/I18nCopyNavigationItems/index.tsx b/admin/src/pages/DetailPage/components/I18nCopyNavigationItems/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/I18nCopyNavigationItems/index.tsx rename to admin/src/pages/DetailPage/components/I18nCopyNavigationItems/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationContentHeader/ManageNavigationItems/index.tsx b/admin/src/pages/DetailPage/components/NavigationContentHeader/ManageNavigationItems/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationContentHeader/ManageNavigationItems/index.tsx rename to admin/src/pages/DetailPage/components/NavigationContentHeader/ManageNavigationItems/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationContentHeader/Search/index.tsx b/admin/src/pages/DetailPage/components/NavigationContentHeader/Search/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationContentHeader/Search/index.tsx rename to admin/src/pages/DetailPage/components/NavigationContentHeader/Search/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationContentHeader/index.tsx b/admin/src/pages/DetailPage/components/NavigationContentHeader/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationContentHeader/index.tsx rename to admin/src/pages/DetailPage/components/NavigationContentHeader/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationEmptyState/index.tsx b/admin/src/pages/DetailPage/components/NavigationEmptyState/index.tsx similarity index 98% rename from admin/src/pages/HomePage/components/NavigationEmptyState/index.tsx rename to admin/src/pages/DetailPage/components/NavigationEmptyState/index.tsx index f5de2ae9..9cd90423 100644 --- a/admin/src/pages/HomePage/components/NavigationEmptyState/index.tsx +++ b/admin/src/pages/DetailPage/components/NavigationEmptyState/index.tsx @@ -19,7 +19,7 @@ import { useResetNavigations, } from '../../hooks'; import { NavigationSchema } from '../../../../api/validators'; -import { appendViewId } from '../../utils/appendViewId'; +import { appendViewId } from '../../../../utils/appendViewId'; type NavigationEmptyStateProps = { canUpdate: boolean; diff --git a/admin/src/pages/DetailPage/components/NavigationHeader/index.tsx b/admin/src/pages/DetailPage/components/NavigationHeader/index.tsx new file mode 100644 index 00000000..b6e9fc0f --- /dev/null +++ b/admin/src/pages/DetailPage/components/NavigationHeader/index.tsx @@ -0,0 +1,120 @@ +import { Button, Flex, Link, SingleSelect, SingleSelectOption, Tag } from '@strapi/design-system'; +import { ArrowLeft, Check, Feather, Information } from '@strapi/icons'; +import { Layouts } from '@strapi/strapi/admin'; +import React from 'react'; +import { useIntl } from 'react-intl'; +import { NavLink } from 'react-router-dom'; +import { NavigationSchema } from '../../../../api/validators'; +import { PLUGIN_ID } from '../../../../pluginId'; +import { getTrad } from '../../../../translations'; +import { Effect } from '../../../../types'; +import { useConfig, usePluginMediaQuery } from '../../hooks'; + +const submitIcon = ; + +interface Props { + activeNavigation?: NavigationSchema; + structureHasErrors?: boolean; + structureHasChanged?: boolean; + isSaving?: boolean; + handleLocalizationSelection: Effect; + handleSave: Effect; + handleCachePurge: Effect; + permissions: { canUpdate?: boolean }; + locale: { + defaultLocale: string; + restLocale: string[]; + }; + currentLocale?: string; +} + +export const NavigationHeader: React.FC = ({ + activeNavigation, + structureHasErrors, + structureHasChanged, + isSaving, + handleLocalizationSelection, + handleSave, + handleCachePurge, + permissions = {}, + locale, + currentLocale, +}) => { + const { formatMessage } = useIntl(); + + const configQuery = useConfig(); + + const hasLocalizations = !!locale.restLocale?.length; + const hasCache = !!configQuery.data?.isCacheEnabled; + + const { canUpdate } = permissions; + + const { isMobile } = usePluginMediaQuery(); + + return ( + } to={`/plugins/${PLUGIN_ID}`}> + {formatMessage(getTrad('header.action.back'))} + + } + title={activeNavigation?.name ?? formatMessage(getTrad('header.title', 'UI Navigation'))} + subtitle={formatMessage(getTrad('header.description'))} + primaryAction={ + + {hasLocalizations && ( + + {[locale.defaultLocale, ...locale.restLocale].map((code) => ( + + {code} + + ))} + + )} + {canUpdate && hasCache && ( + + )} + {canUpdate && ( + + )} + + } + secondaryAction={ + !isMobile && + activeNavigation && ( + }> + {formatMessage(getTrad('header.meta'), { + id: activeNavigation.documentId, + key: activeNavigation.slug, + })} + + ) + } + /> + ); +}; diff --git a/admin/src/pages/HomePage/components/NavigationHeader/styles.ts b/admin/src/pages/DetailPage/components/NavigationHeader/styles.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationHeader/styles.ts rename to admin/src/pages/DetailPage/components/NavigationHeader/styles.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/AdditionalFieldInput/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/AdditionalFields/AdditionalFieldInput/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/AdditionalFieldInput/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/AdditionalFields/AdditionalFieldInput/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/AudienceField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/AdditionalFields/AudienceField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/AudienceField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/AdditionalFields/AudienceField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/CustomFieldsField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/AdditionalFields/CustomFieldsField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/CustomFieldsField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/AdditionalFields/CustomFieldsField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/AdditionalFields/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/AdditionalFields/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/AttachToMenuField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/AttachToMenuField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/AttachToMenuField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/AttachToMenuField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/CopyFromLocales/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/CopyFromLocales/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/CopyFromLocales/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/CopyFromLocales/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/ManualPathField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/ManualPathField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/ManualPathField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/ManualPathField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/NavigationItemTypeField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/NavigationItemTypeField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/NavigationItemTypeField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/NavigationItemTypeField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/PathField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/PathField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/PathField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/PathField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/ReadFieldsFromRelatedField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/ReadFieldsFromRelatedField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/ReadFieldsFromRelatedField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/ReadFieldsFromRelatedField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/RelatedEntityField/hooks.ts b/admin/src/pages/DetailPage/components/NavigationItemForm/components/RelatedEntityField/hooks.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/RelatedEntityField/hooks.ts rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/RelatedEntityField/hooks.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/RelatedEntityField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/RelatedEntityField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/RelatedEntityField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/RelatedEntityField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/RelatedTypeField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/RelatedTypeField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/RelatedTypeField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/RelatedTypeField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/components/TitleField/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/components/TitleField/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/components/TitleField/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/components/TitleField/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/context/NavigationItemFormContext.ts b/admin/src/pages/DetailPage/components/NavigationItemForm/context/NavigationItemFormContext.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/context/NavigationItemFormContext.ts rename to admin/src/pages/DetailPage/components/NavigationItemForm/context/NavigationItemFormContext.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemForm/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemForm/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/types.ts b/admin/src/pages/DetailPage/components/NavigationItemForm/types.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/types.ts rename to admin/src/pages/DetailPage/components/NavigationItemForm/types.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/utils/form.ts b/admin/src/pages/DetailPage/components/NavigationItemForm/utils/form.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/utils/form.ts rename to admin/src/pages/DetailPage/components/NavigationItemForm/utils/form.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/utils/hooks.ts b/admin/src/pages/DetailPage/components/NavigationItemForm/utils/hooks.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemForm/utils/hooks.ts rename to admin/src/pages/DetailPage/components/NavigationItemForm/utils/hooks.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemForm/utils/properties.ts b/admin/src/pages/DetailPage/components/NavigationItemForm/utils/properties.ts similarity index 97% rename from admin/src/pages/HomePage/components/NavigationItemForm/utils/properties.ts rename to admin/src/pages/DetailPage/components/NavigationItemForm/utils/properties.ts index 2d1cc52e..97f9805f 100644 --- a/admin/src/pages/HomePage/components/NavigationItemForm/utils/properties.ts +++ b/admin/src/pages/DetailPage/components/NavigationItemForm/utils/properties.ts @@ -5,7 +5,7 @@ import { NavigationItemTypeSchema, StrapiContentTypeItemSchema, } from '../../../../../api/validators'; -import { extractRelatedItemLabel } from '../../../../HomePage/utils'; +import { extractRelatedItemLabel } from '../../../utils'; import { type NavigationItemFormSchema } from './form'; interface GenerateUiRouterKeyInput { diff --git a/admin/src/pages/HomePage/components/NavigationItemList/Wrapper.ts b/admin/src/pages/DetailPage/components/NavigationItemList/Wrapper.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemList/Wrapper.ts rename to admin/src/pages/DetailPage/components/NavigationItemList/Wrapper.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemList/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemList/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemList/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemList/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardBadge/index.ts b/admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardBadge/index.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardBadge/index.ts rename to admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardBadge/index.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardHeader/Wrapper.tsx b/admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardHeader/Wrapper.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardHeader/Wrapper.tsx rename to admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardHeader/Wrapper.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardHeader/icons.tsx b/admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardHeader/icons.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardHeader/icons.tsx rename to admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardHeader/icons.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardHeader/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardHeader/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardHeader/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardHeader/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardRemovedOverlay/index.ts b/admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardRemovedOverlay/index.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemListItem/ItemCardRemovedOverlay/index.ts rename to admin/src/pages/DetailPage/components/NavigationItemListItem/ItemCardRemovedOverlay/index.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemListItem/Wrapper.ts b/admin/src/pages/DetailPage/components/NavigationItemListItem/Wrapper.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemListItem/Wrapper.ts rename to admin/src/pages/DetailPage/components/NavigationItemListItem/Wrapper.ts diff --git a/admin/src/pages/HomePage/components/NavigationItemListItem/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemListItem/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemListItem/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemListItem/index.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemPopup/NavigationItemPopupFooter.tsx b/admin/src/pages/DetailPage/components/NavigationItemPopup/NavigationItemPopupFooter.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemPopup/NavigationItemPopupFooter.tsx rename to admin/src/pages/DetailPage/components/NavigationItemPopup/NavigationItemPopupFooter.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemPopup/NavigationItemPopupHeader.tsx b/admin/src/pages/DetailPage/components/NavigationItemPopup/NavigationItemPopupHeader.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemPopup/NavigationItemPopupHeader.tsx rename to admin/src/pages/DetailPage/components/NavigationItemPopup/NavigationItemPopupHeader.tsx diff --git a/admin/src/pages/HomePage/components/NavigationItemPopup/index.tsx b/admin/src/pages/DetailPage/components/NavigationItemPopup/index.tsx similarity index 100% rename from admin/src/pages/HomePage/components/NavigationItemPopup/index.tsx rename to admin/src/pages/DetailPage/components/NavigationItemPopup/index.tsx diff --git a/admin/src/pages/HomePage/components/index.ts b/admin/src/pages/DetailPage/components/index.ts similarity index 100% rename from admin/src/pages/HomePage/components/index.ts rename to admin/src/pages/DetailPage/components/index.ts diff --git a/admin/src/pages/HomePage/hooks/index.tsx b/admin/src/pages/DetailPage/hooks/index.tsx similarity index 77% rename from admin/src/pages/HomePage/hooks/index.tsx rename to admin/src/pages/DetailPage/hooks/index.tsx index 89e9b419..7c054dce 100644 --- a/admin/src/pages/HomePage/hooks/index.tsx +++ b/admin/src/pages/DetailPage/hooks/index.tsx @@ -1,8 +1,7 @@ -export * from './useAPI'; +export * from '../../../hooks'; export * from './useI18nCopyNavigationItemsModal'; export * from './useInvalidateQueries'; export * from './useLocales'; export * from './useNavigationItemPopup'; export * from './useSearch'; -export * from './useSettingsPermissions'; export * from './usePluginMediaQuery'; diff --git a/admin/src/pages/HomePage/hooks/useI18nCopyNavigationItemsModal.tsx b/admin/src/pages/DetailPage/hooks/useI18nCopyNavigationItemsModal.tsx similarity index 100% rename from admin/src/pages/HomePage/hooks/useI18nCopyNavigationItemsModal.tsx rename to admin/src/pages/DetailPage/hooks/useI18nCopyNavigationItemsModal.tsx diff --git a/admin/src/pages/HomePage/hooks/useInvalidateQueries.ts b/admin/src/pages/DetailPage/hooks/useInvalidateQueries.ts similarity index 100% rename from admin/src/pages/HomePage/hooks/useInvalidateQueries.ts rename to admin/src/pages/DetailPage/hooks/useInvalidateQueries.ts diff --git a/admin/src/pages/HomePage/hooks/useLocales.ts b/admin/src/pages/DetailPage/hooks/useLocales.ts similarity index 100% rename from admin/src/pages/HomePage/hooks/useLocales.ts rename to admin/src/pages/DetailPage/hooks/useLocales.ts diff --git a/admin/src/pages/HomePage/hooks/useNavigationItemPopup.ts b/admin/src/pages/DetailPage/hooks/useNavigationItemPopup.ts similarity index 100% rename from admin/src/pages/HomePage/hooks/useNavigationItemPopup.ts rename to admin/src/pages/DetailPage/hooks/useNavigationItemPopup.ts diff --git a/admin/src/pages/HomePage/hooks/usePluginMediaQuery.tsx b/admin/src/pages/DetailPage/hooks/usePluginMediaQuery.tsx similarity index 100% rename from admin/src/pages/HomePage/hooks/usePluginMediaQuery.tsx rename to admin/src/pages/DetailPage/hooks/usePluginMediaQuery.tsx diff --git a/admin/src/pages/HomePage/hooks/useSearch.ts b/admin/src/pages/DetailPage/hooks/useSearch.ts similarity index 100% rename from admin/src/pages/HomePage/hooks/useSearch.ts rename to admin/src/pages/DetailPage/hooks/useSearch.ts diff --git a/admin/src/pages/HomePage/index.tsx b/admin/src/pages/DetailPage/index.tsx similarity index 85% rename from admin/src/pages/HomePage/index.tsx rename to admin/src/pages/DetailPage/index.tsx index 6df2148f..ba5b9c77 100644 --- a/admin/src/pages/HomePage/index.tsx +++ b/admin/src/pages/DetailPage/index.tsx @@ -1,12 +1,12 @@ -import { Data } from '@strapi/strapi'; import { Layouts, Page, useNotification } from '@strapi/strapi/admin'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { first } from 'lodash'; import { SyntheticEvent, useEffect, useState } from 'react'; import { useIntl } from 'react-intl'; +import { useNavigate, useParams } from 'react-router-dom'; import { NavigationSchema } from '../../api/validators'; +import { PLUGIN_ID } from '../../pluginId'; import { getTrad } from '../../translations'; +import { appendViewId } from '../../utils/appendViewId'; import { NavigationHeader } from './components'; import { ChangeLanguageDialog } from './components/ChangeLanguageDialog'; import { NavigationContentHeader } from './components/NavigationContentHeader'; @@ -27,13 +27,12 @@ import { import { getPendingAction, transformItemToViewPayload } from './utils'; import { ManageNavigationItems } from './components/NavigationContentHeader/ManageNavigationItems'; import { NavigationEmptyState } from './components/NavigationEmptyState'; -import { appendViewId } from './utils/appendViewId'; import { type NavigationItemFormSchema } from './components/NavigationItemForm'; -const queryClient = new QueryClient(); - -const Inner = () => { +const DetailPage = () => { const { formatMessage } = useIntl(); + const { documentId } = useParams<{ documentId: string }>(); + const navigate = useNavigate(); const navigationsQuery = useNavigations(); const configQuery = useConfig(); @@ -41,7 +40,6 @@ const Inner = () => { const { toggleNotification } = useNotification(); - const [recentNavigation, setRecentNavigation] = useState<{ documentId?: string; id?: Data.ID }>(); const [currentNavigation, setCurrentNavigation] = useState(); const [structureChanged, setStructureChanged] = useState(false); @@ -85,11 +83,6 @@ const Inner = () => { items: next.items.map(appendViewId), }); - setRecentNavigation({ - documentId: next.documentId, - id: next.id, - }); - setStructureChanged(false); }, }); @@ -136,23 +129,29 @@ const Inner = () => { const listItems = isSearchEmpty ? (currentNavigation?.items ?? []) : filteredList; useEffect(() => { - if (!currentNavigation && navigationsQuery.data?.[0]) { - let navigation; - if (recentNavigation?.documentId) { - navigation = navigationsQuery.data.find( - (nav) => nav.documentId === recentNavigation.documentId && nav.id === recentNavigation.id - ); - } + if (!navigationsQuery.data) { + return; + } + + const localeVersions = navigationsQuery.data.filter( + (navigation) => navigation.documentId === documentId + ); - setRecentNavigation(undefined); - setCurrentNavigation(navigation ? navigation : first(navigationsQuery.data)); + if (!localeVersions.length) { + navigate(`/plugins/${PLUGIN_ID}`); + return; } - }, [navigationsQuery.data, currentNavigation]); + + if (!currentNavigation || currentNavigation.documentId !== documentId) { + setCurrentNavigation( + localeVersions.find((navigation) => navigation.locale === currentLocale) ?? + localeVersions[0] + ); + } + }, [navigationsQuery.data, currentNavigation, documentId, currentLocale, navigate]); useEffect(() => { if (currentNavigation && currentLocale !== currentNavigation.locale) { - setRecentNavigation(undefined); - const nextNavigation = navigationsQuery.data?.find( (navigation) => navigation.documentId === currentNavigation.documentId && @@ -180,10 +179,8 @@ const Inner = () => { purgeMutation.mutate(undefined)} - handleChangeSelection={setCurrentNavigation} + handleCachePurge={() => purgeMutation.mutate(documentId ? [documentId] : undefined)} handleLocalizationSelection={ structureChanged ? changeCurrentLocaleAction.trigger : changeCurrentLocaleAction.perform } @@ -256,12 +253,4 @@ const Inner = () => { ); }; -export default function HomePage() { - return ( - - - - ); -} - -export { HomePage }; +export { DetailPage }; diff --git a/admin/src/pages/HomePage/utils/index.ts b/admin/src/pages/DetailPage/utils/index.ts similarity index 100% rename from admin/src/pages/HomePage/utils/index.ts rename to admin/src/pages/DetailPage/utils/index.ts diff --git a/admin/src/pages/HomePage/utils/parsers.ts b/admin/src/pages/DetailPage/utils/parsers.ts similarity index 100% rename from admin/src/pages/HomePage/utils/parsers.ts rename to admin/src/pages/DetailPage/utils/parsers.ts diff --git a/admin/src/pages/HomePage/components/NavigationHeader/hooks.tsx b/admin/src/pages/HomePage/components/NavigationHeader/hooks.tsx deleted file mode 100644 index 8ed5ee11..00000000 --- a/admin/src/pages/HomePage/components/NavigationHeader/hooks.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useCallback, useMemo, useState } from 'react'; -import { NavigationManager } from '../NavigationManager'; - -export const useNavigationManager = () => { - const [isOpened, setIsOpened] = useState(false); - const open = useCallback(() => setIsOpened(true), [setIsOpened]); - const close = useCallback(() => setIsOpened(false), [setIsOpened]); - - const modal = useMemo( - () => - isOpened ? ( - - ) : null, - [isOpened, close] - ); - - return useMemo( - () => ({ - navigationManagerModal: modal, - openNavigationManagerModal: open, - closeNavigationManagerModal: close, - }), - [modal, open, close] - ); -}; diff --git a/admin/src/pages/HomePage/components/NavigationHeader/index.tsx b/admin/src/pages/HomePage/components/NavigationHeader/index.tsx deleted file mode 100644 index 0623aaf0..00000000 --- a/admin/src/pages/HomePage/components/NavigationHeader/index.tsx +++ /dev/null @@ -1,238 +0,0 @@ -import { - Box, - Button, - Field, - Flex, - Grid, - SingleSelect, - SingleSelectOption, - Tag, -} from '@strapi/design-system'; -import { Check, Information } from '@strapi/icons'; -import { Layouts } from '@strapi/strapi/admin'; -import React from 'react'; -import { useIntl } from 'react-intl'; -import styled from 'styled-components'; -import { NavigationSchema } from '../../../../api/validators'; -import { getTrad } from '../../../../translations'; -import { Effect } from '../../../../types'; -import { useConfig, usePluginMediaQuery } from '../../hooks'; -import { useNavigationManager } from './hooks'; - -const StyledGridItem = styled(Grid.Item)<{ - orderInitial?: number; - orderSmall?: number; - orderMedium?: number; -}>` - order: ${({ orderInitial }) => orderInitial ?? 'unset'}; - - @media (min-width: 520px) { - order: ${({ orderSmall }) => orderSmall ?? 'unset'}; - } - - @media (min-width: 768px) { - order: ${({ orderMedium }) => orderMedium ?? 'unset'}; - } -`; - -const submitIcon = ; - -interface Props { - activeNavigation?: NavigationSchema; - availableNavigations: NavigationSchema[]; - structureHasErrors?: boolean; - structureHasChanged?: boolean; - isSaving?: boolean; - handleChangeSelection: Effect; - handleLocalizationSelection: Effect; - handleSave: Effect; - handleCachePurge: Effect; - permissions: { canUpdate?: boolean }; - locale: { - defaultLocale: string; - restLocale: string[]; - }; - currentLocale?: string; -} - -export const NavigationHeader: React.FC = ({ - activeNavigation, - availableNavigations, - structureHasErrors, - structureHasChanged, - isSaving, - handleChangeSelection, - handleLocalizationSelection, - handleSave, - handleCachePurge, - permissions = {}, - locale, - currentLocale, -}) => { - const { formatMessage } = useIntl(); - const { openNavigationManagerModal, navigationManagerModal } = useNavigationManager(); - - const configQuery = useConfig(); - - const hasLocalizations = !!locale.restLocale?.length; - const hasCache = configQuery.data?.isCacheEnabled; - - const { canUpdate } = permissions; - - const { isDesktop, isMobile, isLargeDesktop } = usePluginMediaQuery(); - - return ( - <> - - - - {!hasLocalizations && isLargeDesktop ? : null} - {canUpdate && ( - - - - )} - - - { - const nextNavigation = availableNavigations.find( - ({ documentId }) => nextDocumentId === documentId - ); - - if (nextNavigation) { - handleChangeSelection(nextNavigation); - } - }} - value={activeNavigation?.documentId} - size="S" - style={null} - > - {availableNavigations - .filter(({ locale }) => locale === currentLocale) - .map(({ documentId, name }) => ( - - {name} - - ))} - - - - {hasLocalizations ? ( - - - - {[locale.defaultLocale, ...locale.restLocale].map((code) => ( - - {code} - - ))} - - - - ) : null} - {canUpdate && ( - - - - )} - {hasCache && ( - <> - {isDesktop && ( - - )} - - - - - )} - - - {canUpdate && navigationManagerModal} - - } - secondaryAction={ - !isMobile && ( - }> - {activeNavigation - ? formatMessage(getTrad('header.meta'), { - id: activeNavigation?.documentId, - key: activeNavigation?.slug, - }) - : null} - - ) - } - /> - - ); -}; diff --git a/admin/src/pages/HomePage/components/NavigationManager/AllNavigations/icons.tsx b/admin/src/pages/HomePage/components/NavigationManager/AllNavigations/icons.tsx deleted file mode 100644 index 9d650ddb..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/AllNavigations/icons.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import { Pencil, Trash, Feather } from '@strapi/icons'; - -export const edit = ; -export const deleteIcon = ; -export const featherIcon = ; diff --git a/admin/src/pages/HomePage/components/NavigationManager/AllNavigations/index.tsx b/admin/src/pages/HomePage/components/NavigationManager/AllNavigations/index.tsx deleted file mode 100644 index b2d717a9..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/AllNavigations/index.tsx +++ /dev/null @@ -1,263 +0,0 @@ -import { - Box, - Button, - Checkbox, - Flex, - Grid, - IconButton, - Table, - Tbody, - Td, - Th, - Thead, - Tr, - Typography, -} from '@strapi/design-system'; -import { prop } from 'lodash/fp'; -import { useCallback, useMemo } from 'react'; -import { useIntl } from 'react-intl'; - -import { getTrad } from '../../../../../translations'; -import { useConfig, useLocale } from '../../../hooks'; -import { Footer, FooterBase } from '../Footer'; -import { INITIAL_NAVIGATION } from '../NewNavigation'; -import { CommonProps, ListState, Navigation } from '../types'; -import * as icons from './icons'; - -interface Props extends ListState, CommonProps {} - -export const AllNavigations = ({ navigations, selected, setState }: Props) => { - const configQuery = useConfig(); - - const hasAnySelected = !!selected.length; - - const { formatMessage } = useIntl(); - - const localeQuery = useLocale(); - - const toggleSelected = useCallback( - () => - setState({ - navigations, - selected: hasAnySelected ? [] : navigations.map((n) => n), - view: 'LIST', - }), - [setState, navigations, hasAnySelected] - ); - - const currentlySelectedSet = useMemo(() => new Set(selected.map(prop('documentId'))), [selected]); - - const handleSelect = (navigation: Navigation, isSelected: boolean) => () => { - setState({ - navigations, - selected: isSelected - ? selected.filter(({ documentId }) => documentId !== navigation.documentId) - : selected.concat([navigation]), - view: 'LIST', - }); - }; - - const edit = (navigation: Navigation) => () => { - setState({ - view: 'EDIT', - current: navigation, - navigation, - alreadyUsedNames: navigations.reduce( - (acc, { name }) => (name !== navigation.name ? acc.concat([name]) : acc), - [] - ), - }); - }; - - const _delete = (navigations: Array) => () => { - setState({ - view: 'DELETE', - navigations, - }); - }; - - const purgeCache = (navigations: Array) => () => { - setState({ - view: 'CACHE_PURGE', - navigations, - }); - }; - - const deleteSelected = useCallback(_delete(selected), [_delete]); - - const purgeSelected = useCallback(purgeCache(selected), [purgeCache]); - - const getLocalizations = (focused: Navigation) => - [focused].concat( - navigations.filter( - (navigation) => - navigation.documentId === focused.documentId && navigation.locale !== focused.locale - ) - ); - - return ( - <> - - - {hasAnySelected ? ( - - - {formatMessage(getTrad('popup.navigation.manage.table.hasSelected'), { - count: selected.length, - })} - - - {configQuery.data?.isCacheEnabled ? ( - - ) : null} - - ) : null} - - - - - - - - - - - - - - - {navigations - .filter(({ locale }) => locale === localeQuery.data?.defaultLocale) - .map((navigation) => ( - - - - - - - - - ))} - -
- - - - {formatMessage(getTrad('popup.navigation.manage.table.id'))} - - - - {formatMessage(getTrad('popup.navigation.manage.table.name'))} - - - - {formatMessage(getTrad('popup.navigation.manage.table.locale'))} - - - - {formatMessage(getTrad('popup.navigation.manage.table.visibility'))} - - - {configQuery.data?.isCacheEnabled ? ( - - - - - - ) : null} -
- - - {navigation.documentId} - - {navigation.name} - - - {getLocalizations(navigation).map(prop('locale')).join(', ')} - - - - {navigation.visible - ? formatMessage(getTrad('popup.navigation.manage.navigation.visible')) - : formatMessage(getTrad('popup.navigation.manage.navigation.hidden'))} - - - - - - - - - - {configQuery.data?.isCacheEnabled ? ( - - - - ) : null} - -
- - ); -}; - -export const AllNavigationsFooter: Footer = ({ - onClose, - state, - setState, - navigations, - isLoading, -}) => { - const { formatMessage } = useIntl(); - - return ( - - setState({ - view: 'CREATE', - alreadyUsedNames: navigations.map(({ name }) => name), - current: INITIAL_NAVIGATION, - }), - variant: 'default', - disabled: isLoading, - children: formatMessage(getTrad('popup.navigation.manage.button.create')), - }} - /> - ); -}; diff --git a/admin/src/pages/HomePage/components/NavigationManager/DeletionConfirm/index.tsx b/admin/src/pages/HomePage/components/NavigationManager/DeletionConfirm/index.tsx deleted file mode 100644 index ccac3278..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/DeletionConfirm/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Flex, Grid, Typography } from '@strapi/design-system'; -import { prop } from 'lodash/fp'; -import { useIntl } from 'react-intl'; - -import { getTrad } from '../../../../../translations'; -import { Footer, FooterBase } from '../Footer'; -import { CommonProps, DeleteState, Navigation } from '../types'; - -interface Props extends DeleteState, CommonProps {} - -export const DeletionConfirm = ({ navigations }: Props) => { - const { formatMessage } = useIntl(); - - return ( - - - - - {formatMessage(getTrad('popup.navigation.manage.delete.header'))} - - - - - - {renderItems(navigations)} - - - - ); -}; - -export const DeleteConfirmFooter: Footer = ({ state, onSubmit, onReset, isLoading }) => { - const { formatMessage } = useIntl(); - - return ( - - ); -}; - -const renderItems = (navigations: Array) => navigations.map(prop('name')).join(', '); diff --git a/admin/src/pages/HomePage/components/NavigationManager/ErrorDetails/index.tsx b/admin/src/pages/HomePage/components/NavigationManager/ErrorDetails/index.tsx deleted file mode 100644 index 39ae9359..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/ErrorDetails/index.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Grid } from '@strapi/design-system'; -import { useNotification } from '@strapi/strapi/admin'; -import { useEffect } from 'react'; -import { useIntl } from 'react-intl'; - -import { getTrad } from '../../../../../translations'; -import { Footer, FooterBase } from '../Footer'; -import { CommonProps, ErrorState } from '../types'; - -interface Props extends ErrorState, CommonProps {} - -export const ErrorDetails = ({ errors }: Props) => { - const { formatMessage } = useIntl(); - - const { toggleNotification } = useNotification(); - - useEffect(() => { - errors.map((error) => { - toggleNotification({ - type: 'warning', - message: formatMessage({ id: '', defaultMessage: error.message }), - }); - console.error(error); - }); - }, []); - - return ( - - - {formatMessage(getTrad('popup.navigation.manage.error.message'))} - - - ); -}; - -export const ErrorDetailsFooter: Footer = ({ onReset }) => { - const { formatMessage } = useIntl(); - - return ( - - ); -}; diff --git a/admin/src/pages/HomePage/components/NavigationManager/Footer/index.tsx b/admin/src/pages/HomePage/components/NavigationManager/Footer/index.tsx deleted file mode 100644 index e3b51085..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/Footer/index.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Button, Modal } from '@strapi/design-system'; - -import { NavigationSchema } from '../../../../../api/validators'; -import { VoidEffect } from '../../../../../types'; -import { SetState, State } from '../types'; - -interface FooterBaseProps { - end?: ActionProps; - start?: ActionProps; -} - -export type Footer = React.FC<{ - navigations: Array; - onClose?: VoidEffect; - onReset: VoidEffect; - onSubmit: VoidEffect; - setState: SetState; - state: State; - disabled?: boolean; - isLoading: boolean; -}>; - -interface ActionProps { - children: React.ReactNode; - disabled?: boolean; - onClick?: VoidEffect; - variant: 'danger' | 'secondary' | 'tertiary' | 'default'; -} - -export const FooterBase: React.FC = ({ start, end }) => { - return ( - - {renderActions(start)} - {renderActions(end)} - - ); -}; - -const renderActions = (actions: ActionProps | undefined): React.ReactNode => - actions ? ( - - ) : null; diff --git a/admin/src/pages/HomePage/components/NavigationManager/NavigationUpdate/index.tsx b/admin/src/pages/HomePage/components/NavigationManager/NavigationUpdate/index.tsx deleted file mode 100644 index 732caf83..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/NavigationUpdate/index.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { useCallback, useMemo } from 'react'; -import { useIntl } from 'react-intl'; - -import { getTrad } from '../../../../../translations'; -import { Effect } from '../../../../../types'; -import { Footer, FooterBase } from '../Footer'; -import { Form } from '../Form'; -import { CommonProps, EditState, Navigation } from '../types'; - -interface Props extends EditState, CommonProps {} - -export const NavigationUpdate = ({ - alreadyUsedNames, - current, - isLoading, - navigation: initialValue, - setState, -}: Props) => { - const navigation: Navigation = useMemo(() => current ?? initialValue, [current]); - - const onChange: Effect = useCallback( - ({ disabled, ...updated }: Navigation & { disabled?: boolean }) => { - setState({ - view: 'EDIT', - alreadyUsedNames, - current: updated, - disabled, - navigation: initialValue, - }); - }, - [setState, initialValue, alreadyUsedNames] - ); - - return ( - - navigation={navigation} - onChange={onChange} - isLoading={isLoading} - alreadyUsedNames={alreadyUsedNames} - /> - ); -}; - -export const NavigationUpdateFooter: Footer = ({ onSubmit, onReset, disabled, isLoading }) => { - const { formatMessage } = useIntl(); - - return ( - - ); -}; diff --git a/admin/src/pages/HomePage/components/NavigationManager/NewNavigation/index.tsx b/admin/src/pages/HomePage/components/NavigationManager/NewNavigation/index.tsx deleted file mode 100644 index 2a139291..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/NewNavigation/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { useCallback } from 'react'; -import { useIntl } from 'react-intl'; - -import { getTrad } from '../../../../../translations'; -import { Footer, FooterBase } from '../Footer'; -import { Form } from '../Form'; -import { CommonProps, CreateState, Navigation, NewNavigation as NewNavigationType } from '../types'; - -interface Props extends CreateState, CommonProps {} - -export const INITIAL_NAVIGATION = { - name: '', - items: [], - visible: false, -} as unknown as Navigation; - -export const NewNavigation = ({ setState, current, isLoading, alreadyUsedNames }: Props) => { - const onSubmit = useCallback( - ({ disabled, ...updated }: NewNavigationType & { disabled?: boolean }) => { - setState({ - view: 'CREATE', - current: updated, - alreadyUsedNames, - disabled, - }); - }, - [setState] - ); - - return ( - - alreadyUsedNames={alreadyUsedNames} - navigation={current} - onChange={onSubmit} - isLoading={isLoading} - /> - ); -}; - -export const NewNavigationFooter: Footer = ({ onSubmit, onReset, disabled, isLoading }) => { - const { formatMessage } = useIntl(); - - return ( - - ); -}; diff --git a/admin/src/pages/HomePage/components/NavigationManager/PurgeCacheConfirm/index.tsx b/admin/src/pages/HomePage/components/NavigationManager/PurgeCacheConfirm/index.tsx deleted file mode 100644 index eaa03b8e..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/PurgeCacheConfirm/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Flex, Grid, Typography } from '@strapi/design-system'; -import { prop } from 'lodash/fp'; -import { useIntl } from 'react-intl'; -import { getTrad } from '../../../../../translations'; - -import { Footer, FooterBase } from '../Footer'; -import { CommonProps, Navigation, PurgeCacheState } from '../types'; - -interface Props extends PurgeCacheState, CommonProps {} - -export const PurgeCacheConfirm = ({ navigations }: Props) => { - const { formatMessage } = useIntl(); - - return ( - - - - - {formatMessage(getTrad('popup.navigation.manage.purge.header'))} - - - - - - {renderItems(navigations)} - - - - ); -}; - -export const PurgeCacheConfirmFooter: Footer = ({ onSubmit, onReset, isLoading }) => { - const { formatMessage } = useIntl(); - - return ( - - ); -}; - -const renderItems = (navigations: Array) => navigations.map(prop('name')).join(', '); diff --git a/admin/src/pages/HomePage/components/NavigationManager/index.tsx b/admin/src/pages/HomePage/components/NavigationManager/index.tsx deleted file mode 100644 index c895c936..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/index.tsx +++ /dev/null @@ -1,319 +0,0 @@ -import { Flex, Loader, Modal } from '@strapi/design-system'; -import { useNotification } from '@strapi/strapi/admin'; -import { sortBy } from 'lodash'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { useIntl } from 'react-intl'; -import { getTrad } from '../../../../translations'; -import { VoidEffect } from '../../../../types'; -import { - useCreateNavigation, - useDeleteNavigations, - useHardReset, - useLocale, - useNavigations, - usePurgeNavigation, - useUpdateNavigation, -} from '../../hooks'; -import { getPendingAction } from '../../utils'; -import { AllNavigations, AllNavigationsFooter } from './AllNavigations'; -import { DeleteConfirmFooter, DeletionConfirm } from './DeletionConfirm'; -import { ErrorDetails, ErrorDetailsFooter } from './ErrorDetails'; -import { Footer } from './Footer'; -import { NavigationUpdate, NavigationUpdateFooter } from './NavigationUpdate'; -import { NewNavigation, NewNavigationFooter } from './NewNavigation'; -import { PurgeCacheConfirm, PurgeCacheConfirmFooter } from './PurgeCacheConfirm'; -import { SetState, State } from './types'; -import { Typography } from '@strapi/design-system'; - -interface Props { - initialState: State; - isOpened?: boolean; - onClose?: VoidEffect; -} - -export const NavigationManager = ({ initialState, isOpened, onClose }: Props) => { - const { formatMessage } = useIntl(); - const [state, setState] = useState(initialState); - - const { toggleNotification } = useNotification(); - - const hardReset = useHardReset(); - - const deleteNavigationsMutation = useDeleteNavigations(); - - const createNavigationMutation = useCreateNavigation(); - - const updateNavigationMutation = useUpdateNavigation({}); - - const purgeNavigationsMutation = usePurgeNavigation(); - - const navigationsQuery = useNavigations(); - - const localeQuery = useLocale(); - - const navigations = useMemo( - () => sortBy(navigationsQuery.data ?? [], 'id'), - [navigationsQuery.data] - ); - - const pending = getPendingAction([ - deleteNavigationsMutation, - navigationsQuery, - createNavigationMutation, - updateNavigationMutation, - purgeNavigationsMutation, - localeQuery, - ]); - - const onReset = useCallback(() => setState({ view: 'INITIAL' }), [setState]); - - const onSubmit = useCallback(async () => { - const performAction = - state.view === 'DELETE' - ? () => { - deleteNavigationsMutation.mutate( - state.navigations.reduce((acc, navigation) => { - if (navigation.documentId) { - acc.push(navigation.documentId); - } - - return acc; - }, []), - { - onSuccess: hardReset, - } - ); - } - : state.view === 'EDIT' - ? () => { - updateNavigationMutation.mutate(state.current, { - onSuccess() { - hardReset(); - toggleNotification({ - type: 'success', - message: formatMessage(getTrad('notification.navigation.submit')), - }); - }, - onError(error) { - // TODO: handle errors - console.warn(error); - - toggleNotification({ - type: 'warning', - message: formatMessage(getTrad('notification.navigation.error'), { - errorTitles: '', - }), - }); - }, - }); - } - : state.view === 'CREATE' && state.current - ? () => { - createNavigationMutation.mutate(state.current, { - onSuccess() { - hardReset(); - toggleNotification({ - type: 'success', - message: formatMessage(getTrad('notification.navigation.submit')), - }); - }, - onError(error) { - // TODO: handle errors - console.warn(error); - - toggleNotification({ - type: 'warning', - message: formatMessage(getTrad('notification.navigation.error'), { - errorTitles: '', - }), - }); - }, - }); - } - : state.view === 'CACHE_PURGE' - ? () => { - purgeNavigationsMutation.mutate( - state.navigations.reduce((acc, navigation) => { - if (navigation.documentId) { - acc.push(navigation.documentId); - } - - return acc; - }, []), - { - onSuccess: hardReset, - } - ); - } - : () => {}; - - try { - performAction(); - setState({ view: 'INITIAL' }); - } catch (error) { - setState({ - view: 'ERROR', - errors: error instanceof Error ? [error] : [], - }); - } - }, [ - state, - setState, - hardReset, - createNavigationMutation, - purgeNavigationsMutation, - updateNavigationMutation, - deleteNavigationsMutation, - toggleNotification, - formatMessage, - getTrad, - ]); - - useEffect(() => { - if (state.view === 'INITIAL' || state.view === 'LIST') { - setState({ - view: 'LIST', - navigations, - selected: [], - }); - } - }, [state.view, navigations]); - - const header = renderHeader(state, formatMessage, !!pending); - const content = renderContent(state, setState, !!pending); - const footer = renderFooter({ - state, - setState, - onClose, - onSubmit, - onReset, - navigations, - isLoading: !!pending, - }); - - return ( - { - if (!isOpen) { - onClose?.(); - } - }} - open={isOpened} - > - - - - {header} - - - {content} - {footer} - - - ); -}; - -const renderHeader = ( - state: State, - formatMessage: ReturnType['formatMessage'], - isLoading: boolean -) => { - switch (state.view) { - case 'LIST': - case 'CREATE': - case 'ERROR': - case 'CACHE_PURGE': - case 'DELETE': { - return ( - - {isLoading ? : null} - {formatMessage(getTrad(`popup.navigation.manage.header.${state.view}`))} - - ); - } - case 'EDIT': { - return ( - - {isLoading ? : null} - - {formatMessage(getTrad('popup.navigation.manage.header.EDIT'), { - name: state.navigation.name, - })} - - ); - } - case 'INITIAL': { - return null; - } - default: - return handleUnknownState(state); - } -}; - -const renderContent = (state: State, setState: SetState, isLoading: boolean) => { - const commonProps = { - setState, - isLoading, - }; - - switch (state.view) { - case 'LIST': { - return ; - } - case 'EDIT': { - return ; - } - case 'CREATE': { - return ; - } - case 'DELETE': { - return ; - } - case 'CACHE_PURGE': { - return ; - } - case 'INITIAL': { - return ; - } - case 'ERROR': { - return ; - } - default: - return handleUnknownState(state); - } -}; - -const renderFooter: Footer = (props) => { - switch (props.state.view) { - case 'LIST': { - return ; - } - case 'CREATE': { - return ; - } - case 'EDIT': { - return ; - } - case 'DELETE': { - return ; - } - case 'CACHE_PURGE': { - return ; - } - case 'ERROR': { - return ; - } - case 'INITIAL': { - return null; - } - default: - return handleUnknownState(props.state); - } -}; - -const handleUnknownState = (state: undefined | { view: string }) => { - console.warn(`Unknown state "${state?.view}". (${JSON.stringify(state)})`); - - return null; -}; diff --git a/admin/src/pages/HomePage/components/NavigationManager/types.ts b/admin/src/pages/HomePage/components/NavigationManager/types.ts deleted file mode 100644 index 0a383cd0..00000000 --- a/admin/src/pages/HomePage/components/NavigationManager/types.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Dispatch, SetStateAction } from 'react'; - -import { NavigationSchema } from '../../../../api/validators'; - -export type Navigation = Pick< - NavigationSchema, - 'id' | 'items' | 'name' | 'locale' | 'visible' | 'documentId' | 'slug' ->; - -export type NewNavigation = Omit; - -export type State = - | InitialState - | ListState - | EditState - | CreateState - | DeleteState - | PurgeCacheState - | ErrorState; - -export type SetState = Dispatch>; - -interface CommonState {} - -export interface CommonProps { - setState: SetState; - isLoading: boolean; -} - -export interface InitialState extends CommonState { - view: 'INITIAL'; -} - -export interface ListState extends CommonState { - view: 'LIST'; - navigations: Array; - selected: Array; -} - -export interface EditState extends CommonState { - view: 'EDIT'; - navigation: Navigation; - current: Navigation; - disabled?: boolean; - alreadyUsedNames: Array; -} - -export interface CreateState extends CommonState { - view: 'CREATE'; - current: NewNavigation; - disabled?: boolean; - alreadyUsedNames: Array; -} - -export interface DeleteState extends CommonState { - view: 'DELETE'; - navigations: Array; -} - -export interface PurgeCacheState extends CommonState { - view: 'CACHE_PURGE'; - navigations: Array; -} - -export interface ErrorState extends CommonState { - view: 'ERROR'; - errors: Array; -} diff --git a/admin/src/pages/HomePage/components/NavigationManager/Form/hooks.ts b/admin/src/pages/OverviewPage/components/NavigationForm/hooks.ts similarity index 100% rename from admin/src/pages/HomePage/components/NavigationManager/Form/hooks.ts rename to admin/src/pages/OverviewPage/components/NavigationForm/hooks.ts diff --git a/admin/src/pages/HomePage/components/NavigationManager/Form/index.tsx b/admin/src/pages/OverviewPage/components/NavigationForm/index.tsx similarity index 96% rename from admin/src/pages/HomePage/components/NavigationManager/Form/index.tsx rename to admin/src/pages/OverviewPage/components/NavigationForm/index.tsx index 13ed4de8..69f70a3f 100644 --- a/admin/src/pages/HomePage/components/NavigationManager/Form/index.tsx +++ b/admin/src/pages/OverviewPage/components/NavigationForm/index.tsx @@ -5,9 +5,9 @@ import { useEffect, useState } from 'react'; import { useIntl } from 'react-intl'; import { Field } from '@sensinum/strapi-utils'; -import { getTrad } from '../../../../../translations'; -import { Effect, FormChangeEvent, FormItemErrorSchema } from '../../../../../types'; -import { Navigation } from '../types'; +import { getTrad } from '../../../../translations'; +import { Effect, FormChangeEvent, FormItemErrorSchema } from '../../../../types'; +import { Navigation } from '../../types'; import { formSchema } from './hooks'; interface Props> { @@ -95,6 +95,10 @@ export const Form = >({ }, []); useEffect(() => { + if (name === undefined && visible === undefined) { + return; + } + if (`${name}-${visible}` !== `${navigation.name}-${navigation.visible}`) { const { error } = formSchema({ alreadyUsedNames }).safeParse(formValue); diff --git a/admin/src/pages/OverviewPage/components/NavigationFormModal/index.tsx b/admin/src/pages/OverviewPage/components/NavigationFormModal/index.tsx new file mode 100644 index 00000000..5e01ce92 --- /dev/null +++ b/admin/src/pages/OverviewPage/components/NavigationFormModal/index.tsx @@ -0,0 +1,77 @@ +import { Button, Modal } from '@strapi/design-system'; +import { useState } from 'react'; +import { useIntl } from 'react-intl'; + +import { getTrad } from '../../../../translations'; +import { Effect, VoidEffect } from '../../../../types'; +import { Navigation } from '../../types'; +import { Form } from '../NavigationForm'; + +interface Props { + navigation: Partial; + alreadyUsedNames: Array; + isLoading?: boolean; + onClose: VoidEffect; + onSubmit: Effect>; +} + +export const NavigationFormModal = ({ + navigation, + alreadyUsedNames, + isLoading, + onClose, + onSubmit, +}: Props) => { + const { formatMessage } = useIntl(); + + const [current, setCurrent] = useState(navigation); + const [isDisabled, setIsDisabled] = useState(false); + + const isEdit = !!navigation.documentId; + + const handleChange = ({ disabled, ...updated }: Partial & { disabled?: boolean }) => { + setCurrent(updated); + setIsDisabled(!!disabled); + }; + + return ( + { + if (!isOpen) { + onClose(); + } + }} + > + + + + {isEdit + ? formatMessage(getTrad('pages.overview.modal.edit.header'), { + name: navigation.name, + }) + : formatMessage(getTrad('pages.overview.modal.create.header'))} + + + +
+ + + + + + + + + + ); +}; diff --git a/admin/src/pages/OverviewPage/index.tsx b/admin/src/pages/OverviewPage/index.tsx new file mode 100644 index 00000000..9400e71d --- /dev/null +++ b/admin/src/pages/OverviewPage/index.tsx @@ -0,0 +1,369 @@ +import { + Button, + EmptyStateLayout, + Flex, + IconButton, + Status, + Table, + Tbody, + Td, + Th, + Thead, + Tr, + Typography, + VisuallyHidden, +} from '@strapi/design-system'; +import { Feather, Pencil, Plus, Trash } from '@strapi/icons'; +import { EmptyDocuments } from '@strapi/icons/symbols'; +import { Layouts, Page, useNotification } from '@strapi/strapi/admin'; +import { sortBy } from 'lodash'; +import { useMemo, useState } from 'react'; +import { useIntl } from 'react-intl'; +import { useNavigate } from 'react-router-dom'; + +import { ConfirmationDialog } from '../../components/ConfirmationDialog'; +import { + useConfig, + useCreateNavigation, + useDeleteNavigations, + useHardReset, + useLocale, + useNavigations, + usePurgeNavigation, + useSettingsPermissions, + useUpdateNavigation, +} from '../../hooks'; +import { PLUGIN_ID } from '../../pluginId'; +import { getTrad } from '../../translations'; +import { NavigationFormModal } from './components/NavigationFormModal'; +import { Navigation } from './types'; + +const INITIAL_NAVIGATION: Partial = { + name: '', + items: [], + visible: false, +}; + +type OverlayState = + | { type: 'create' } + | { type: 'edit'; navigation: Navigation } + | { type: 'delete'; navigation: Navigation } + | { type: 'purge'; navigation?: Navigation } + | null; + +const OverviewPage = () => { + const { formatMessage } = useIntl(); + const navigate = useNavigate(); + const { toggleNotification } = useNotification(); + + const navigationsQuery = useNavigations(); + const localeQuery = useLocale(); + const configQuery = useConfig(); + const { canUpdate, isLoadingForPermissions } = useSettingsPermissions(); + + const createNavigationMutation = useCreateNavigation(); + const updateNavigationMutation = useUpdateNavigation({}); + const deleteNavigationsMutation = useDeleteNavigations(); + const purgeNavigationsMutation = usePurgeNavigation(); + const hardReset = useHardReset(); + + const [overlay, setOverlay] = useState(null); + + const navigations = useMemo( + () => sortBy(navigationsQuery.data ?? [], 'id'), + [navigationsQuery.data] + ); + + const defaultLocaleNavigations = useMemo( + () => navigations.filter(({ locale }) => locale === localeQuery.data?.defaultLocale), + [navigations, localeQuery.data?.defaultLocale] + ); + + const hasCache = !!configQuery.data?.isCacheEnabled; + + const isMutating = + createNavigationMutation.isPending || + updateNavigationMutation.isPending || + deleteNavigationsMutation.isPending || + purgeNavigationsMutation.isPending; + + const getLocaleVersions = (focused: Navigation) => + [focused].concat( + navigations.filter( + (navigation) => + navigation.documentId === focused.documentId && navigation.locale !== focused.locale + ) + ); + + const goToDetails = (navigation: Navigation) => { + navigate(`/plugins/${PLUGIN_ID}/${navigation.documentId}`); + }; + + const handleFormSubmit = (updated: Partial) => { + const options = { + onSuccess() { + hardReset(); + setOverlay(null); + toggleNotification({ + type: 'success', + message: formatMessage(getTrad('notification.navigation.submit')), + }); + }, + onError(error: unknown) { + console.warn(error); + toggleNotification({ + type: 'warning', + message: formatMessage(getTrad('pages.overview.notification.error')), + }); + }, + }; + + if (overlay?.type === 'edit') { + updateNavigationMutation.mutate(updated as Navigation, options); + } else { + createNavigationMutation.mutate(updated as Navigation, options); + } + }; + + const handleDelete = () => { + if (overlay?.type !== 'delete') { + return; + } + + deleteNavigationsMutation.mutate([overlay.navigation.documentId], { + onSuccess() { + hardReset(); + setOverlay(null); + }, + }); + }; + + const handlePurge = () => { + if (overlay?.type !== 'purge') { + return; + } + + purgeNavigationsMutation.mutate( + overlay.navigation ? [overlay.navigation.documentId] : undefined, + { + onSuccess() { + hardReset(); + setOverlay(null); + }, + } + ); + }; + + if ( + navigationsQuery.isPending || + localeQuery.isPending || + configQuery.isPending || + isLoadingForPermissions + ) { + return ; + } + + return ( + + + + + {hasCache && ( + + )} + + + ) + } + /> + + {defaultLocaleNavigations.length === 0 ? ( + } + content={formatMessage(getTrad('pages.overview.empty.description'))} + action={ + canUpdate && ( + + ) + } + /> + ) : ( + + + + + + + + + + + + {defaultLocaleNavigations.map((navigation) => ( + goToDetails(navigation)} + style={{ cursor: 'pointer' }} + > + + + + + + + ))} + +
+ + {formatMessage(getTrad('pages.overview.table.header.name'))} + + + + {formatMessage(getTrad('pages.overview.table.header.locales'))} + + + + {formatMessage(getTrad('pages.overview.table.header.visibility'))} + + + + {formatMessage(getTrad('pages.overview.table.header.items'))} + + + + {formatMessage(getTrad('pages.overview.table.header.actions'))} + +
+ + {navigation.name} + + + + {getLocaleVersions(navigation) + .map(({ locale }) => locale) + .join(', ')} + + + + + {navigation.visible + ? formatMessage(getTrad('pages.overview.table.visibility.visible')) + : formatMessage(getTrad('pages.overview.table.visibility.hidden'))} + + + + {navigation.items.length} + event.stopPropagation()}> + + {canUpdate && ( + setOverlay({ type: 'edit', navigation })} + label={formatMessage(getTrad('pages.overview.table.action.edit'))} + variant="ghost" + > + + + )} + {canUpdate && ( + setOverlay({ type: 'delete', navigation })} + label={formatMessage(getTrad('pages.overview.table.action.delete'))} + variant="ghost" + > + + + )} + {canUpdate && hasCache && ( + setOverlay({ type: 'purge', navigation })} + label={formatMessage(getTrad('pages.overview.table.action.purge'))} + variant="ghost" + > + + + )} + +
+ )} + + {(overlay?.type === 'create' || overlay?.type === 'edit') && ( + >( + (acc, { name }) => + overlay.type === 'edit' && name === overlay.navigation.name + ? acc + : acc.concat([name]), + [] + )} + isLoading={isMutating} + onClose={() => setOverlay(null)} + onSubmit={handleFormSubmit} + /> + )} + + {overlay?.type === 'delete' && ( + } + onConfirm={handleDelete} + onCancel={() => setOverlay(null)} + > + {formatMessage(getTrad('pages.overview.dialog.delete.description'), { + name: overlay.navigation.name, + })} + + )} + + {overlay?.type === 'purge' && ( + } + onConfirm={handlePurge} + onCancel={() => setOverlay(null)} + > + {overlay.navigation + ? formatMessage(getTrad('pages.overview.dialog.purge.description'), { + name: overlay.navigation.name, + }) + : formatMessage(getTrad('pages.overview.dialog.purge.descriptionAll'))} + + )} +
+
+
+ ); +}; + +export { OverviewPage }; diff --git a/admin/src/pages/OverviewPage/types.ts b/admin/src/pages/OverviewPage/types.ts new file mode 100644 index 00000000..d2d08c31 --- /dev/null +++ b/admin/src/pages/OverviewPage/types.ts @@ -0,0 +1,8 @@ +import { NavigationSchema } from '../../api/validators'; + +export type Navigation = Pick< + NavigationSchema, + 'id' | 'items' | 'name' | 'locale' | 'visible' | 'documentId' | 'slug' +>; + +export type NewNavigation = Omit; diff --git a/admin/src/translations/ca.ts b/admin/src/translations/ca.ts index 5947288f..441f1e98 100644 --- a/admin/src/translations/ca.ts +++ b/admin/src/translations/ca.ts @@ -12,7 +12,7 @@ const ca = { meta: 'ID: { id }, slug: { key }', action: { newItem: 'Nouvel élément', - manage: 'Gérer', + back: 'Retour', collapseAll: 'Tout réduire', expandAll: 'Tout développer', }, @@ -32,51 +32,6 @@ const ca = { }, popup: { navigation: { - manage: { - header: { - LIST: 'Toutes les navigations', - CREATE: 'Nouvelle navigation', - DELETE: 'Suppression', - ERROR: 'Erreur', - EDIT: 'Édition de "{name}"', - }, - button: { - cancel: 'Annuler', - delete: 'Supprimer', - save: 'Enregistrer', - edit: 'Modifier', - create: 'Créer', - goBack: 'Retourner', - purge: 'Effacer le cache de lecture', - }, - table: { - id: 'Id', - name: 'Nom', - locale: 'Versions locales', - visibility: 'Visibilité', - hasSelected: '{count} entrées sélectionnées', - }, - footer: { - button: { - purge: 'Effacer', - }, - }, - purge: { - header: - "Cette action effacera le cache de lecture de l'API. Cela entraînera un ralentissement temporaire des lectures pour les navigations ci-dessous.", - }, - delete: { - header: 'Les navigations suivantes seront supprimées :', - }, - error: { - header: 'Une erreur est survenue :(', - message: 'Une erreur est survenue lors du traitement de la demande.', - }, - navigation: { - visible: 'visible', - hidden: 'caché', - }, - }, form: { name: { label: 'Nom', @@ -229,6 +184,67 @@ const ca = { allowed: "Oups ! Il semble que vous n'ayez pas accès à cette page...", }, }, + overview: { + header: { + subtitle: '{count, plural, one {# navigation trouvée} other {# navigations trouvées}}', + }, + action: { + create: 'Nouvelle navigation', + purgeAll: 'Effacer le cache de lecture', + }, + table: { + header: { + name: 'Nom', + locales: 'Versions locales', + visibility: 'Visibilité', + items: 'Éléments', + actions: 'Actions', + }, + action: { + edit: 'Modifier la navigation', + delete: 'Supprimer la navigation', + purge: 'Effacer le cache de lecture de la navigation', + }, + visibility: { + visible: 'Visible', + hidden: 'Masquée', + }, + }, + empty: { + description: "Vous n'avez pas encore de navigation", + }, + modal: { + create: { + header: 'Nouvelle navigation', + }, + edit: { + header: 'Édition de "{name}"', + }, + button: { + cancel: 'Annuler', + save: 'Enregistrer', + }, + }, + dialog: { + delete: { + header: 'Supprimer la navigation', + description: + 'Voulez-vous vraiment supprimer "{name}" ? Tous ses éléments et versions locales seront supprimés.', + confirm: 'Supprimer', + }, + purge: { + header: 'Effacer le cache de lecture', + description: + 'Cette action effacera le cache de lecture de l\'API pour "{name}". Cela entraînera un ralentissement temporaire des lectures.', + descriptionAll: + "Cette action effacera le cache de lecture de l'API pour toutes les navigations. Cela entraînera un ralentissement temporaire des lectures.", + confirm: 'Effacer le cache', + }, + }, + notification: { + error: "Une erreur est survenue lors de l'enregistrement de la navigation", + }, + }, main: { search: { placeholder: 'Tapez pour commencer à rechercher...', diff --git a/admin/src/translations/de.ts b/admin/src/translations/de.ts index 9f57ed18..be5de408 100644 --- a/admin/src/translations/de.ts +++ b/admin/src/translations/de.ts @@ -12,7 +12,7 @@ const de = { meta: 'ID: { id }, Slug: { key }', action: { newItem: 'Neuer Eintrag', - manage: 'Verwalten', + back: 'Zurück', collapseAll: 'Alle einklappen', expandAll: 'Alle ausklappen', }, @@ -32,51 +32,6 @@ const de = { }, popup: { navigation: { - manage: { - header: { - LIST: 'Alle Navigationen', - CREATE: 'Neue Navigation', - DELETE: 'Löschen', - ERROR: 'Fehler', - EDIT: '"{name}" bearbeiten', - }, - button: { - cancel: 'Abbrechen', - delete: 'Löschen', - save: 'Speichern', - edit: 'Bearbeiten', - create: 'Erstellen', - goBack: 'Zurück', - purge: 'Lese-Cache leeren', - }, - table: { - id: 'ID', - name: 'Name', - locale: 'Sprachversionen', - visibility: 'Sichtbarkeit', - hasSelected: '{count} Einträge ausgewählt', - }, - footer: { - button: { - purge: 'Leeren', - }, - }, - purge: { - header: - 'Diese Aktion leert den API-Lese-Cache. Dadurch können die untenstehenden Navigationen kurzzeitig langsamer gelesen werden.', - }, - delete: { - header: 'Die folgenden Navigationen werden entfernt:', - }, - error: { - header: 'Ein Fehler ist aufgetreten :(', - message: 'Beim Verarbeiten der Anfrage ist ein Fehler aufgetreten.', - }, - navigation: { - visible: 'sichtbar', - hidden: 'ausgeblendet', - }, - }, form: { name: { label: 'Name', @@ -234,6 +189,67 @@ const de = { allowed: 'Sie haben offenbar keinen Zugriff auf diese Seite...', }, }, + overview: { + header: { + subtitle: '{count, plural, one {# Navigation gefunden} other {# Navigationen gefunden}}', + }, + action: { + create: 'Neue Navigation', + purgeAll: 'Lese-Cache leeren', + }, + table: { + header: { + name: 'Name', + locales: 'Sprachversionen', + visibility: 'Sichtbarkeit', + items: 'Einträge', + actions: 'Aktionen', + }, + action: { + edit: 'Navigation bearbeiten', + delete: 'Navigation löschen', + purge: 'Lese-Cache der Navigation leeren', + }, + visibility: { + visible: 'Sichtbar', + hidden: 'Ausgeblendet', + }, + }, + empty: { + description: 'Sie haben noch keine Navigationen', + }, + modal: { + create: { + header: 'Neue Navigation', + }, + edit: { + header: '"{name}" bearbeiten', + }, + button: { + cancel: 'Abbrechen', + save: 'Speichern', + }, + }, + dialog: { + delete: { + header: 'Navigation löschen', + description: + 'Möchten Sie "{name}" wirklich löschen? Alle Einträge und Sprachversionen werden entfernt.', + confirm: 'Löschen', + }, + purge: { + header: 'Lese-Cache leeren', + description: + 'Diese Aktion leert den API-Lese-Cache für "{name}". Dadurch können Lesevorgänge kurzzeitig langsamer sein.', + descriptionAll: + 'Diese Aktion leert den API-Lese-Cache für alle Navigationen. Dadurch können Lesevorgänge kurzzeitig langsamer sein.', + confirm: 'Cache leeren', + }, + }, + notification: { + error: 'Beim Speichern der Navigation ist ein Fehler aufgetreten', + }, + }, main: { search: { placeholder: 'Tippen, um die Suche zu starten...', diff --git a/admin/src/translations/en.ts b/admin/src/translations/en.ts index 17b00b5c..8b879414 100644 --- a/admin/src/translations/en.ts +++ b/admin/src/translations/en.ts @@ -12,7 +12,7 @@ const en = { meta: 'ID: { id }, slug: { key }', action: { newItem: 'New Item', - manage: 'Manage', + back: 'Back', collapseAll: 'Collapse All', expandAll: 'Expand All', }, @@ -32,51 +32,6 @@ const en = { }, popup: { navigation: { - manage: { - header: { - LIST: 'All navigations', - CREATE: 'New navigation', - DELETE: 'Deleting', - ERROR: 'Error', - EDIT: 'Editing "{name}"', - }, - button: { - cancel: 'Cancel', - delete: 'Delete', - save: 'Save', - edit: 'Edit', - create: 'Create', - goBack: 'Go back', - purge: 'Clear read cache', - }, - table: { - id: 'Id', - name: 'Name', - locale: 'Locale versions', - visibility: 'Visibility', - hasSelected: '{count} entries selected', - }, - footer: { - button: { - purge: 'Clear', - }, - }, - purge: { - header: - 'This action will clear API read cache. This will result in brief slowdown of reads for navigations below.', - }, - delete: { - header: 'Following navigations will be removed:', - }, - error: { - header: 'An error happened :(', - message: 'An error happened while processing request.', - }, - navigation: { - visible: 'visible', - hidden: 'hidden', - }, - }, form: { name: { label: 'Name', @@ -232,6 +187,67 @@ const en = { allowed: 'Oops! It seems like You do not have access to this page...', }, }, + overview: { + header: { + subtitle: '{count, plural, one {# navigation} other {# navigations}} found', + }, + action: { + create: 'New navigation', + purgeAll: 'Clear read cache', + }, + table: { + header: { + name: 'Name', + locales: 'Locale versions', + visibility: 'Visibility', + items: 'Items', + actions: 'Actions', + }, + action: { + edit: 'Edit navigation', + delete: 'Delete navigation', + purge: 'Clear navigation read cache', + }, + visibility: { + visible: 'Visible', + hidden: 'Hidden', + }, + }, + empty: { + description: 'You don’t have any navigations yet', + }, + modal: { + create: { + header: 'New navigation', + }, + edit: { + header: 'Editing "{name}"', + }, + button: { + cancel: 'Cancel', + save: 'Save', + }, + }, + dialog: { + delete: { + header: 'Delete navigation', + description: + 'Are you sure you want to delete "{name}"? All of its items and locale versions will be removed.', + confirm: 'Delete', + }, + purge: { + header: 'Clear read cache', + description: + 'This action will clear the API read cache for "{name}". This will result in a brief slowdown of reads.', + descriptionAll: + 'This action will clear the API read cache for all navigations. This will result in a brief slowdown of reads.', + confirm: 'Clear cache', + }, + }, + notification: { + error: 'An error occurred while saving the navigation', + }, + }, main: { search: { placeholder: 'Type to start searching...', diff --git a/admin/src/translations/es.ts b/admin/src/translations/es.ts index 81157794..ff1c1767 100644 --- a/admin/src/translations/es.ts +++ b/admin/src/translations/es.ts @@ -12,7 +12,7 @@ const en = { meta: 'ID: { id }, slug: { key }', action: { newItem: 'Nuevo ítem', - manage: 'Gestionar', + back: 'Volver', collapseAll: 'Colapsar todo', expandAll: 'Expandir todo', }, @@ -32,51 +32,6 @@ const en = { }, popup: { navigation: { - manage: { - header: { - LIST: 'Todas las navegaciones', - CREATE: 'Nueva navegación', - DELETE: 'Eliminando', - ERROR: 'Error', - EDIT: 'Editando "{name}"', - }, - button: { - cancel: 'Cancelar', - delete: 'Eliminar', - save: 'Guardar', - edit: 'Edit', - create: 'Create', - goBack: 'Volver', - purge: 'Borrar caché de lectura', - }, - table: { - id: 'Id', - name: 'Nombre', - locale: 'Versiones de idioma', - visibility: 'Visibilidad', - hasSelected: '{count} entradas seleccionadas', - }, - footer: { - button: { - purge: 'Clear', - }, - }, - purge: { - header: - 'Esta acción limpiará la caché de lectura de la API. Esto puede causar una breve ralentización en las lecturas de las navegaciones siguientes.', - }, - delete: { - header: 'Las siguientes navegaciones serán eliminadas:', - }, - error: { - header: 'Ocurrió un error :(', - message: 'Ocurrió un error al procesar la solicitud.', - }, - navigation: { - visible: 'visible', - hidden: 'oculto', - }, - }, form: { name: { label: 'Nombre', @@ -233,6 +188,68 @@ const en = { allowed: '¡Ups! Parece que no tienes acceso a esta página...', }, }, + overview: { + header: { + subtitle: + '{count, plural, one {# navegación encontrada} other {# navegaciones encontradas}}', + }, + action: { + create: 'Nueva navegación', + purgeAll: 'Borrar caché de lectura', + }, + table: { + header: { + name: 'Nombre', + locales: 'Versiones de idioma', + visibility: 'Visibilidad', + items: 'Ítems', + actions: 'Acciones', + }, + action: { + edit: 'Editar navegación', + delete: 'Eliminar navegación', + purge: 'Borrar caché de lectura de la navegación', + }, + visibility: { + visible: 'Visible', + hidden: 'Oculta', + }, + }, + empty: { + description: 'Todavía no tienes ninguna navegación', + }, + modal: { + create: { + header: 'Nueva navegación', + }, + edit: { + header: 'Editando "{name}"', + }, + button: { + cancel: 'Cancelar', + save: 'Guardar', + }, + }, + dialog: { + delete: { + header: 'Eliminar navegación', + description: + '¿Seguro que quieres eliminar "{name}"? Se eliminarán todos sus ítems y versiones de idioma.', + confirm: 'Eliminar', + }, + purge: { + header: 'Borrar caché de lectura', + description: + 'Esta acción limpiará la caché de lectura de la API para "{name}". Esto puede causar una breve ralentización en las lecturas.', + descriptionAll: + 'Esta acción limpiará la caché de lectura de la API para todas las navegaciones. Esto puede causar una breve ralentización en las lecturas.', + confirm: 'Borrar caché', + }, + }, + notification: { + error: 'Ocurrió un error al guardar la navegación', + }, + }, main: { search: { placeholder: 'Escribe para comenzar la búsqueda...', diff --git a/admin/src/translations/fr.ts b/admin/src/translations/fr.ts index 7513c38b..4ec3e625 100644 --- a/admin/src/translations/fr.ts +++ b/admin/src/translations/fr.ts @@ -12,7 +12,7 @@ const fr = { meta: 'ID : { id }, slug : { key }', action: { newItem: 'Nouvel élément', - manage: 'Gérer', + back: 'Retour', collapseAll: 'Tout réduire', expandAll: 'Tout développer', }, @@ -32,51 +32,6 @@ const fr = { }, popup: { navigation: { - manage: { - header: { - LIST: 'Toutes les navigations', - CREATE: 'Nouvelle navigation', - DELETE: 'Suppression', - ERROR: 'Erreur', - EDIT: 'Édition de « {name} »', - }, - button: { - cancel: 'Annuler', - delete: 'Supprimer', - save: 'Enregistrer', - edit: 'Modifier', - create: 'Créer', - goBack: 'Retour', - purge: 'Effacer le cache de lecture', - }, - table: { - id: 'Id', - name: 'Nom', - locale: 'Versions locales', - visibility: 'Visibilité', - hasSelected: '{count} entrées sélectionnées', - }, - footer: { - button: { - purge: 'Effacer', - }, - }, - purge: { - header: - "Cette action effacera le cache de lecture de l'API. Cela entraînera un ralentissement temporaire des lectures pour les navigations ci-dessous.", - }, - delete: { - header: 'Les navigations suivantes seront supprimées :', - }, - error: { - header: 'Une erreur est survenue :(', - message: 'Une erreur est survenue lors du traitement de la demande.', - }, - navigation: { - visible: 'visible', - hidden: 'masqué', - }, - }, form: { name: { label: 'Nom', @@ -233,6 +188,67 @@ const fr = { allowed: "Oups ! Il semble que vous n'ayez pas accès à cette page…", }, }, + overview: { + header: { + subtitle: '{count, plural, one {# navigation trouvée} other {# navigations trouvées}}', + }, + action: { + create: 'Nouvelle navigation', + purgeAll: 'Effacer le cache de lecture', + }, + table: { + header: { + name: 'Nom', + locales: 'Versions locales', + visibility: 'Visibilité', + items: 'Éléments', + actions: 'Actions', + }, + action: { + edit: 'Modifier la navigation', + delete: 'Supprimer la navigation', + purge: 'Effacer le cache de lecture de la navigation', + }, + visibility: { + visible: 'Visible', + hidden: 'Masquée', + }, + }, + empty: { + description: "Vous n'avez pas encore de navigation", + }, + modal: { + create: { + header: 'Nouvelle navigation', + }, + edit: { + header: 'Édition de « {name} »', + }, + button: { + cancel: 'Annuler', + save: 'Enregistrer', + }, + }, + dialog: { + delete: { + header: 'Supprimer la navigation', + description: + 'Voulez-vous vraiment supprimer « {name} » ? Tous ses éléments et versions locales seront supprimés.', + confirm: 'Supprimer', + }, + purge: { + header: 'Effacer le cache de lecture', + description: + "Cette action effacera le cache de lecture de l'API pour « {name} ». Cela entraînera un ralentissement temporaire des lectures.", + descriptionAll: + "Cette action effacera le cache de lecture de l'API pour toutes les navigations. Cela entraînera un ralentissement temporaire des lectures.", + confirm: 'Effacer le cache', + }, + }, + notification: { + error: "Une erreur est survenue lors de l'enregistrement de la navigation", + }, + }, main: { search: { placeholder: 'Tapez pour commencer à rechercher…', diff --git a/admin/src/translations/tr.ts b/admin/src/translations/tr.ts index 2fdb2286..bcf4f2a1 100644 --- a/admin/src/translations/tr.ts +++ b/admin/src/translations/tr.ts @@ -12,7 +12,7 @@ const tr = { meta: 'ID: { id }, slug: { key }', action: { newItem: 'Yeni Öğe', - manage: 'Yönet', + back: 'Geri', collapseAll: 'Tümünü Daralt', expandAll: 'Tümünü Genişlet', }, @@ -32,51 +32,6 @@ const tr = { }, popup: { navigation: { - manage: { - header: { - LIST: 'Tüm navigasyonlar', - CREATE: 'Yeni navigasyon', - DELETE: 'Silme işlemi', - ERROR: 'Hata', - EDIT: '"{name}" düzenleniyor', - }, - button: { - cancel: 'İptal', - delete: 'Sil', - save: 'Kaydet', - edit: 'Düzenle', - create: 'Oluştur', - goBack: 'Geri dön', - purge: 'Önbelleği temizle', - }, - table: { - id: 'Id', - name: 'Ad', - locale: 'Dil versiyonları', - visibility: 'Görünürlük', - hasSelected: '{count} öğe seçildi', - }, - footer: { - button: { - purge: 'Temizle', - }, - }, - purge: { - header: - 'Bu işlem API okuma önbelleğini temizleyecektir. Aşağıdaki navigasyonlar için kısa bir yavaşlama yaşanacaktır.', - }, - delete: { - header: 'Aşağıdaki navigasyonlar kaldırılacaktır:', - }, - error: { - header: 'Bir hata oluştu :(', - message: 'İstek işlenirken bir hata oluştu.', - }, - navigation: { - visible: 'görünür', - hidden: 'gizli', - }, - }, form: { name: { label: 'Ad', @@ -232,6 +187,67 @@ const tr = { allowed: 'Üzgünüz! Bu sayfaya erişim yetkiniz yok gibi görünüyor...', }, }, + overview: { + header: { + subtitle: '{count, plural, one {# navigasyon bulundu} other {# navigasyon bulundu}}', + }, + action: { + create: 'Yeni navigasyon', + purgeAll: 'Önbelleği temizle', + }, + table: { + header: { + name: 'Ad', + locales: 'Dil versiyonları', + visibility: 'Görünürlük', + items: 'Öğeler', + actions: 'İşlemler', + }, + action: { + edit: 'Navigasyonu düzenle', + delete: 'Navigasyonu sil', + purge: 'Navigasyonun okuma önbelleğini temizle', + }, + visibility: { + visible: 'Görünür', + hidden: 'Gizli', + }, + }, + empty: { + description: 'Henüz bir navigasyonunuz yok', + }, + modal: { + create: { + header: 'Yeni navigasyon', + }, + edit: { + header: '"{name}" düzenleniyor', + }, + button: { + cancel: 'İptal', + save: 'Kaydet', + }, + }, + dialog: { + delete: { + header: 'Navigasyonu sil', + description: + '"{name}" navigasyonunu silmek istediğinizden emin misiniz? Tüm öğeleri ve dil versiyonları kaldırılacaktır.', + confirm: 'Sil', + }, + purge: { + header: 'Önbelleği temizle', + description: + 'Bu işlem "{name}" için API okuma önbelleğini temizleyecektir. Okumalarda kısa bir yavaşlama yaşanacaktır.', + descriptionAll: + 'Bu işlem tüm navigasyonlar için API okuma önbelleğini temizleyecektir. Okumalarda kısa bir yavaşlama yaşanacaktır.', + confirm: 'Önbelleği temizle', + }, + }, + notification: { + error: 'Navigasyon kaydedilirken bir hata oluştu', + }, + }, main: { search: { placeholder: 'Arama yapmak için yazmaya başlayın...', diff --git a/admin/src/pages/HomePage/utils/appendViewId.ts b/admin/src/utils/appendViewId.ts similarity index 76% rename from admin/src/pages/HomePage/utils/appendViewId.ts rename to admin/src/utils/appendViewId.ts index 39dacad2..f351090a 100644 --- a/admin/src/pages/HomePage/utils/appendViewId.ts +++ b/admin/src/utils/appendViewId.ts @@ -1,4 +1,4 @@ -import { NavigationItemSchema } from '../../../api/validators'; +import { NavigationItemSchema } from '../api/validators'; export const appendViewId = (item: NavigationItemSchema): NavigationItemSchema => { return { From 3672cdcb8b8caae505c60b39534bcf5d23afe59d Mon Sep 17 00:00:00 2001 From: Wouter Konecny Date: Tue, 7 Jul 2026 15:29:08 +0200 Subject: [PATCH 2/2] refactor: reuse existing translation keys to minimize locale changes Point the overview page, form modal and detail header at the existing popup.navigation.manage.* and form toggle keys instead of introducing a parallel pages.overview namespace. Locale files now only add the four genuinely new strings (subtitle, items/actions columns, empty state), drop keys that lost their last consumer, and backfill the visibility toggle labels missing from ca. --- .../components/NavigationHeader/index.tsx | 2 +- .../components/NavigationFormModal/index.tsx | 8 +- admin/src/pages/OverviewPage/index.tsx | 46 +++++----- admin/src/translations/ca.ts | 90 ++++++++----------- admin/src/translations/de.ts | 86 +++++++----------- admin/src/translations/en.ts | 86 +++++++----------- admin/src/translations/es.ts | 86 +++++++----------- admin/src/translations/fr.ts | 86 +++++++----------- admin/src/translations/tr.ts | 86 +++++++----------- 9 files changed, 234 insertions(+), 342 deletions(-) diff --git a/admin/src/pages/DetailPage/components/NavigationHeader/index.tsx b/admin/src/pages/DetailPage/components/NavigationHeader/index.tsx index b6e9fc0f..b60791d7 100644 --- a/admin/src/pages/DetailPage/components/NavigationHeader/index.tsx +++ b/admin/src/pages/DetailPage/components/NavigationHeader/index.tsx @@ -55,7 +55,7 @@ export const NavigationHeader: React.FC = ({ } to={`/plugins/${PLUGIN_ID}`}> - {formatMessage(getTrad('header.action.back'))} + {formatMessage(getTrad('popup.navigation.manage.button.goBack'))} } title={activeNavigation?.name ?? formatMessage(getTrad('header.title', 'UI Navigation'))} diff --git a/admin/src/pages/OverviewPage/components/NavigationFormModal/index.tsx b/admin/src/pages/OverviewPage/components/NavigationFormModal/index.tsx index 5e01ce92..395407db 100644 --- a/admin/src/pages/OverviewPage/components/NavigationFormModal/index.tsx +++ b/admin/src/pages/OverviewPage/components/NavigationFormModal/index.tsx @@ -47,10 +47,10 @@ export const NavigationFormModal = ({ {isEdit - ? formatMessage(getTrad('pages.overview.modal.edit.header'), { + ? formatMessage(getTrad('popup.navigation.manage.header.EDIT'), { name: navigation.name, }) - : formatMessage(getTrad('pages.overview.modal.create.header'))} + : formatMessage(getTrad('popup.navigation.manage.header.CREATE'))} @@ -64,11 +64,11 @@ export const NavigationFormModal = ({ diff --git a/admin/src/pages/OverviewPage/index.tsx b/admin/src/pages/OverviewPage/index.tsx index 9400e71d..94b90b12 100644 --- a/admin/src/pages/OverviewPage/index.tsx +++ b/admin/src/pages/OverviewPage/index.tsx @@ -113,7 +113,7 @@ const OverviewPage = () => { console.warn(error); toggleNotification({ type: 'warning', - message: formatMessage(getTrad('pages.overview.notification.error')), + message: formatMessage(getTrad('notification.error.common')), }); }, }; @@ -181,11 +181,11 @@ const OverviewPage = () => { startIcon={} onClick={() => setOverlay({ type: 'purge' })} > - {formatMessage(getTrad('pages.overview.action.purgeAll'))} + {formatMessage(getTrad('popup.navigation.manage.button.purge'))} )} ) @@ -203,7 +203,7 @@ const OverviewPage = () => { startIcon={} onClick={() => setOverlay({ type: 'create' })} > - {formatMessage(getTrad('pages.overview.action.create'))} + {formatMessage(getTrad('popup.navigation.manage.header.CREATE'))} ) } @@ -214,27 +214,27 @@ const OverviewPage = () => { - {formatMessage(getTrad('pages.overview.table.header.name'))} + {formatMessage(getTrad('popup.navigation.manage.table.name'))} - {formatMessage(getTrad('pages.overview.table.header.locales'))} + {formatMessage(getTrad('popup.navigation.manage.table.locale'))} - {formatMessage(getTrad('pages.overview.table.header.visibility'))} + {formatMessage(getTrad('popup.navigation.manage.table.visibility'))} - {formatMessage(getTrad('pages.overview.table.header.items'))} + {formatMessage(getTrad('pages.overview.table.items'))} - {formatMessage(getTrad('pages.overview.table.header.actions'))} + {formatMessage(getTrad('pages.overview.table.actions'))} @@ -266,8 +266,8 @@ const OverviewPage = () => { > {navigation.visible - ? formatMessage(getTrad('pages.overview.table.visibility.visible')) - : formatMessage(getTrad('pages.overview.table.visibility.hidden'))} + ? formatMessage(getTrad('popup.navigation.form.visible.toggle.visible')) + : formatMessage(getTrad('popup.navigation.form.visible.toggle.hidden'))} @@ -279,7 +279,7 @@ const OverviewPage = () => { {canUpdate && ( setOverlay({ type: 'edit', navigation })} - label={formatMessage(getTrad('pages.overview.table.action.edit'))} + label={formatMessage(getTrad('popup.navigation.manage.button.edit'))} variant="ghost" > @@ -288,7 +288,7 @@ const OverviewPage = () => { {canUpdate && ( setOverlay({ type: 'delete', navigation })} - label={formatMessage(getTrad('pages.overview.table.action.delete'))} + label={formatMessage(getTrad('popup.navigation.manage.button.delete'))} variant="ghost" > @@ -297,7 +297,7 @@ const OverviewPage = () => { {canUpdate && hasCache && ( setOverlay({ type: 'purge', navigation })} - label={formatMessage(getTrad('pages.overview.table.action.purge'))} + label={formatMessage(getTrad('popup.navigation.manage.button.purge'))} variant="ghost" > @@ -331,15 +331,13 @@ const OverviewPage = () => { } onConfirm={handleDelete} onCancel={() => setOverlay(null)} > - {formatMessage(getTrad('pages.overview.dialog.delete.description'), { - name: overlay.navigation.name, - })} + {`${formatMessage(getTrad('popup.navigation.manage.delete.header'))} "${overlay.navigation.name}"`} )} @@ -347,17 +345,15 @@ const OverviewPage = () => { } onConfirm={handlePurge} onCancel={() => setOverlay(null)} > {overlay.navigation - ? formatMessage(getTrad('pages.overview.dialog.purge.description'), { - name: overlay.navigation.name, - }) - : formatMessage(getTrad('pages.overview.dialog.purge.descriptionAll'))} + ? `${formatMessage(getTrad('popup.navigation.manage.purge.header'))} "${overlay.navigation.name}"` + : formatMessage(getTrad('popup.navigation.manage.purge.header'))} )} diff --git a/admin/src/translations/ca.ts b/admin/src/translations/ca.ts index 441f1e98..496cd800 100644 --- a/admin/src/translations/ca.ts +++ b/admin/src/translations/ca.ts @@ -12,7 +12,6 @@ const ca = { meta: 'ID: { id }, slug: { key }', action: { newItem: 'Nouvel élément', - back: 'Retour', collapseAll: 'Tout réduire', expandAll: 'Tout développer', }, @@ -32,6 +31,38 @@ const ca = { }, popup: { navigation: { + manage: { + header: { + CREATE: 'Nouvelle navigation', + DELETE: 'Suppression', + EDIT: 'Édition de "{name}"', + }, + button: { + cancel: 'Annuler', + delete: 'Supprimer', + save: 'Enregistrer', + edit: 'Modifier', + goBack: 'Retourner', + purge: 'Effacer le cache de lecture', + }, + table: { + name: 'Nom', + locale: 'Versions locales', + visibility: 'Visibilité', + }, + footer: { + button: { + purge: 'Effacer', + }, + }, + purge: { + header: + "Cette action effacera le cache de lecture de l'API. Cela entraînera un ralentissement temporaire des lectures pour les navigations ci-dessous.", + }, + delete: { + header: 'Les navigations suivantes seront supprimées :', + }, + }, form: { name: { label: 'Nom', @@ -49,6 +80,10 @@ const ca = { }, visible: { label: 'Visibilité', + toggle: { + visible: 'Visible', + hidden: 'Masqué', + }, }, }, }, @@ -188,62 +223,13 @@ const ca = { header: { subtitle: '{count, plural, one {# navigation trouvée} other {# navigations trouvées}}', }, - action: { - create: 'Nouvelle navigation', - purgeAll: 'Effacer le cache de lecture', - }, table: { - header: { - name: 'Nom', - locales: 'Versions locales', - visibility: 'Visibilité', - items: 'Éléments', - actions: 'Actions', - }, - action: { - edit: 'Modifier la navigation', - delete: 'Supprimer la navigation', - purge: 'Effacer le cache de lecture de la navigation', - }, - visibility: { - visible: 'Visible', - hidden: 'Masquée', - }, + items: 'Éléments', + actions: 'Actions', }, empty: { description: "Vous n'avez pas encore de navigation", }, - modal: { - create: { - header: 'Nouvelle navigation', - }, - edit: { - header: 'Édition de "{name}"', - }, - button: { - cancel: 'Annuler', - save: 'Enregistrer', - }, - }, - dialog: { - delete: { - header: 'Supprimer la navigation', - description: - 'Voulez-vous vraiment supprimer "{name}" ? Tous ses éléments et versions locales seront supprimés.', - confirm: 'Supprimer', - }, - purge: { - header: 'Effacer le cache de lecture', - description: - 'Cette action effacera le cache de lecture de l\'API pour "{name}". Cela entraînera un ralentissement temporaire des lectures.', - descriptionAll: - "Cette action effacera le cache de lecture de l'API pour toutes les navigations. Cela entraînera un ralentissement temporaire des lectures.", - confirm: 'Effacer le cache', - }, - }, - notification: { - error: "Une erreur est survenue lors de l'enregistrement de la navigation", - }, }, main: { search: { diff --git a/admin/src/translations/de.ts b/admin/src/translations/de.ts index be5de408..26e54eb6 100644 --- a/admin/src/translations/de.ts +++ b/admin/src/translations/de.ts @@ -12,7 +12,6 @@ const de = { meta: 'ID: { id }, Slug: { key }', action: { newItem: 'Neuer Eintrag', - back: 'Zurück', collapseAll: 'Alle einklappen', expandAll: 'Alle ausklappen', }, @@ -32,6 +31,38 @@ const de = { }, popup: { navigation: { + manage: { + header: { + CREATE: 'Neue Navigation', + DELETE: 'Löschen', + EDIT: '"{name}" bearbeiten', + }, + button: { + cancel: 'Abbrechen', + delete: 'Löschen', + save: 'Speichern', + edit: 'Bearbeiten', + goBack: 'Zurück', + purge: 'Lese-Cache leeren', + }, + table: { + name: 'Name', + locale: 'Sprachversionen', + visibility: 'Sichtbarkeit', + }, + footer: { + button: { + purge: 'Leeren', + }, + }, + purge: { + header: + 'Diese Aktion leert den API-Lese-Cache. Dadurch können die untenstehenden Navigationen kurzzeitig langsamer gelesen werden.', + }, + delete: { + header: 'Die folgenden Navigationen werden entfernt:', + }, + }, form: { name: { label: 'Name', @@ -193,62 +224,13 @@ const de = { header: { subtitle: '{count, plural, one {# Navigation gefunden} other {# Navigationen gefunden}}', }, - action: { - create: 'Neue Navigation', - purgeAll: 'Lese-Cache leeren', - }, table: { - header: { - name: 'Name', - locales: 'Sprachversionen', - visibility: 'Sichtbarkeit', - items: 'Einträge', - actions: 'Aktionen', - }, - action: { - edit: 'Navigation bearbeiten', - delete: 'Navigation löschen', - purge: 'Lese-Cache der Navigation leeren', - }, - visibility: { - visible: 'Sichtbar', - hidden: 'Ausgeblendet', - }, + items: 'Einträge', + actions: 'Aktionen', }, empty: { description: 'Sie haben noch keine Navigationen', }, - modal: { - create: { - header: 'Neue Navigation', - }, - edit: { - header: '"{name}" bearbeiten', - }, - button: { - cancel: 'Abbrechen', - save: 'Speichern', - }, - }, - dialog: { - delete: { - header: 'Navigation löschen', - description: - 'Möchten Sie "{name}" wirklich löschen? Alle Einträge und Sprachversionen werden entfernt.', - confirm: 'Löschen', - }, - purge: { - header: 'Lese-Cache leeren', - description: - 'Diese Aktion leert den API-Lese-Cache für "{name}". Dadurch können Lesevorgänge kurzzeitig langsamer sein.', - descriptionAll: - 'Diese Aktion leert den API-Lese-Cache für alle Navigationen. Dadurch können Lesevorgänge kurzzeitig langsamer sein.', - confirm: 'Cache leeren', - }, - }, - notification: { - error: 'Beim Speichern der Navigation ist ein Fehler aufgetreten', - }, }, main: { search: { diff --git a/admin/src/translations/en.ts b/admin/src/translations/en.ts index 8b879414..44fc8f8c 100644 --- a/admin/src/translations/en.ts +++ b/admin/src/translations/en.ts @@ -12,7 +12,6 @@ const en = { meta: 'ID: { id }, slug: { key }', action: { newItem: 'New Item', - back: 'Back', collapseAll: 'Collapse All', expandAll: 'Expand All', }, @@ -32,6 +31,38 @@ const en = { }, popup: { navigation: { + manage: { + header: { + CREATE: 'New navigation', + DELETE: 'Deleting', + EDIT: 'Editing "{name}"', + }, + button: { + cancel: 'Cancel', + delete: 'Delete', + save: 'Save', + edit: 'Edit', + goBack: 'Go back', + purge: 'Clear read cache', + }, + table: { + name: 'Name', + locale: 'Locale versions', + visibility: 'Visibility', + }, + footer: { + button: { + purge: 'Clear', + }, + }, + purge: { + header: + 'This action will clear API read cache. This will result in brief slowdown of reads for navigations below.', + }, + delete: { + header: 'Following navigations will be removed:', + }, + }, form: { name: { label: 'Name', @@ -191,62 +222,13 @@ const en = { header: { subtitle: '{count, plural, one {# navigation} other {# navigations}} found', }, - action: { - create: 'New navigation', - purgeAll: 'Clear read cache', - }, table: { - header: { - name: 'Name', - locales: 'Locale versions', - visibility: 'Visibility', - items: 'Items', - actions: 'Actions', - }, - action: { - edit: 'Edit navigation', - delete: 'Delete navigation', - purge: 'Clear navigation read cache', - }, - visibility: { - visible: 'Visible', - hidden: 'Hidden', - }, + items: 'Items', + actions: 'Actions', }, empty: { description: 'You don’t have any navigations yet', }, - modal: { - create: { - header: 'New navigation', - }, - edit: { - header: 'Editing "{name}"', - }, - button: { - cancel: 'Cancel', - save: 'Save', - }, - }, - dialog: { - delete: { - header: 'Delete navigation', - description: - 'Are you sure you want to delete "{name}"? All of its items and locale versions will be removed.', - confirm: 'Delete', - }, - purge: { - header: 'Clear read cache', - description: - 'This action will clear the API read cache for "{name}". This will result in a brief slowdown of reads.', - descriptionAll: - 'This action will clear the API read cache for all navigations. This will result in a brief slowdown of reads.', - confirm: 'Clear cache', - }, - }, - notification: { - error: 'An error occurred while saving the navigation', - }, }, main: { search: { diff --git a/admin/src/translations/es.ts b/admin/src/translations/es.ts index ff1c1767..2f3b3f48 100644 --- a/admin/src/translations/es.ts +++ b/admin/src/translations/es.ts @@ -12,7 +12,6 @@ const en = { meta: 'ID: { id }, slug: { key }', action: { newItem: 'Nuevo ítem', - back: 'Volver', collapseAll: 'Colapsar todo', expandAll: 'Expandir todo', }, @@ -32,6 +31,38 @@ const en = { }, popup: { navigation: { + manage: { + header: { + CREATE: 'Nueva navegación', + DELETE: 'Eliminando', + EDIT: 'Editando "{name}"', + }, + button: { + cancel: 'Cancelar', + delete: 'Eliminar', + save: 'Guardar', + edit: 'Edit', + goBack: 'Volver', + purge: 'Borrar caché de lectura', + }, + table: { + name: 'Nombre', + locale: 'Versiones de idioma', + visibility: 'Visibilidad', + }, + footer: { + button: { + purge: 'Clear', + }, + }, + purge: { + header: + 'Esta acción limpiará la caché de lectura de la API. Esto puede causar una breve ralentización en las lecturas de las navegaciones siguientes.', + }, + delete: { + header: 'Las siguientes navegaciones serán eliminadas:', + }, + }, form: { name: { label: 'Nombre', @@ -193,62 +224,13 @@ const en = { subtitle: '{count, plural, one {# navegación encontrada} other {# navegaciones encontradas}}', }, - action: { - create: 'Nueva navegación', - purgeAll: 'Borrar caché de lectura', - }, table: { - header: { - name: 'Nombre', - locales: 'Versiones de idioma', - visibility: 'Visibilidad', - items: 'Ítems', - actions: 'Acciones', - }, - action: { - edit: 'Editar navegación', - delete: 'Eliminar navegación', - purge: 'Borrar caché de lectura de la navegación', - }, - visibility: { - visible: 'Visible', - hidden: 'Oculta', - }, + items: 'Ítems', + actions: 'Acciones', }, empty: { description: 'Todavía no tienes ninguna navegación', }, - modal: { - create: { - header: 'Nueva navegación', - }, - edit: { - header: 'Editando "{name}"', - }, - button: { - cancel: 'Cancelar', - save: 'Guardar', - }, - }, - dialog: { - delete: { - header: 'Eliminar navegación', - description: - '¿Seguro que quieres eliminar "{name}"? Se eliminarán todos sus ítems y versiones de idioma.', - confirm: 'Eliminar', - }, - purge: { - header: 'Borrar caché de lectura', - description: - 'Esta acción limpiará la caché de lectura de la API para "{name}". Esto puede causar una breve ralentización en las lecturas.', - descriptionAll: - 'Esta acción limpiará la caché de lectura de la API para todas las navegaciones. Esto puede causar una breve ralentización en las lecturas.', - confirm: 'Borrar caché', - }, - }, - notification: { - error: 'Ocurrió un error al guardar la navegación', - }, }, main: { search: { diff --git a/admin/src/translations/fr.ts b/admin/src/translations/fr.ts index 4ec3e625..d602297c 100644 --- a/admin/src/translations/fr.ts +++ b/admin/src/translations/fr.ts @@ -12,7 +12,6 @@ const fr = { meta: 'ID : { id }, slug : { key }', action: { newItem: 'Nouvel élément', - back: 'Retour', collapseAll: 'Tout réduire', expandAll: 'Tout développer', }, @@ -32,6 +31,38 @@ const fr = { }, popup: { navigation: { + manage: { + header: { + CREATE: 'Nouvelle navigation', + DELETE: 'Suppression', + EDIT: 'Édition de « {name} »', + }, + button: { + cancel: 'Annuler', + delete: 'Supprimer', + save: 'Enregistrer', + edit: 'Modifier', + goBack: 'Retour', + purge: 'Effacer le cache de lecture', + }, + table: { + name: 'Nom', + locale: 'Versions locales', + visibility: 'Visibilité', + }, + footer: { + button: { + purge: 'Effacer', + }, + }, + purge: { + header: + "Cette action effacera le cache de lecture de l'API. Cela entraînera un ralentissement temporaire des lectures pour les navigations ci-dessous.", + }, + delete: { + header: 'Les navigations suivantes seront supprimées :', + }, + }, form: { name: { label: 'Nom', @@ -192,62 +223,13 @@ const fr = { header: { subtitle: '{count, plural, one {# navigation trouvée} other {# navigations trouvées}}', }, - action: { - create: 'Nouvelle navigation', - purgeAll: 'Effacer le cache de lecture', - }, table: { - header: { - name: 'Nom', - locales: 'Versions locales', - visibility: 'Visibilité', - items: 'Éléments', - actions: 'Actions', - }, - action: { - edit: 'Modifier la navigation', - delete: 'Supprimer la navigation', - purge: 'Effacer le cache de lecture de la navigation', - }, - visibility: { - visible: 'Visible', - hidden: 'Masquée', - }, + items: 'Éléments', + actions: 'Actions', }, empty: { description: "Vous n'avez pas encore de navigation", }, - modal: { - create: { - header: 'Nouvelle navigation', - }, - edit: { - header: 'Édition de « {name} »', - }, - button: { - cancel: 'Annuler', - save: 'Enregistrer', - }, - }, - dialog: { - delete: { - header: 'Supprimer la navigation', - description: - 'Voulez-vous vraiment supprimer « {name} » ? Tous ses éléments et versions locales seront supprimés.', - confirm: 'Supprimer', - }, - purge: { - header: 'Effacer le cache de lecture', - description: - "Cette action effacera le cache de lecture de l'API pour « {name} ». Cela entraînera un ralentissement temporaire des lectures.", - descriptionAll: - "Cette action effacera le cache de lecture de l'API pour toutes les navigations. Cela entraînera un ralentissement temporaire des lectures.", - confirm: 'Effacer le cache', - }, - }, - notification: { - error: "Une erreur est survenue lors de l'enregistrement de la navigation", - }, }, main: { search: { diff --git a/admin/src/translations/tr.ts b/admin/src/translations/tr.ts index bcf4f2a1..ed9024a3 100644 --- a/admin/src/translations/tr.ts +++ b/admin/src/translations/tr.ts @@ -12,7 +12,6 @@ const tr = { meta: 'ID: { id }, slug: { key }', action: { newItem: 'Yeni Öğe', - back: 'Geri', collapseAll: 'Tümünü Daralt', expandAll: 'Tümünü Genişlet', }, @@ -32,6 +31,38 @@ const tr = { }, popup: { navigation: { + manage: { + header: { + CREATE: 'Yeni navigasyon', + DELETE: 'Silme işlemi', + EDIT: '"{name}" düzenleniyor', + }, + button: { + cancel: 'İptal', + delete: 'Sil', + save: 'Kaydet', + edit: 'Düzenle', + goBack: 'Geri dön', + purge: 'Önbelleği temizle', + }, + table: { + name: 'Ad', + locale: 'Dil versiyonları', + visibility: 'Görünürlük', + }, + footer: { + button: { + purge: 'Temizle', + }, + }, + purge: { + header: + 'Bu işlem API okuma önbelleğini temizleyecektir. Aşağıdaki navigasyonlar için kısa bir yavaşlama yaşanacaktır.', + }, + delete: { + header: 'Aşağıdaki navigasyonlar kaldırılacaktır:', + }, + }, form: { name: { label: 'Ad', @@ -191,62 +222,13 @@ const tr = { header: { subtitle: '{count, plural, one {# navigasyon bulundu} other {# navigasyon bulundu}}', }, - action: { - create: 'Yeni navigasyon', - purgeAll: 'Önbelleği temizle', - }, table: { - header: { - name: 'Ad', - locales: 'Dil versiyonları', - visibility: 'Görünürlük', - items: 'Öğeler', - actions: 'İşlemler', - }, - action: { - edit: 'Navigasyonu düzenle', - delete: 'Navigasyonu sil', - purge: 'Navigasyonun okuma önbelleğini temizle', - }, - visibility: { - visible: 'Görünür', - hidden: 'Gizli', - }, + items: 'Öğeler', + actions: 'İşlemler', }, empty: { description: 'Henüz bir navigasyonunuz yok', }, - modal: { - create: { - header: 'Yeni navigasyon', - }, - edit: { - header: '"{name}" düzenleniyor', - }, - button: { - cancel: 'İptal', - save: 'Kaydet', - }, - }, - dialog: { - delete: { - header: 'Navigasyonu sil', - description: - '"{name}" navigasyonunu silmek istediğinizden emin misiniz? Tüm öğeleri ve dil versiyonları kaldırılacaktır.', - confirm: 'Sil', - }, - purge: { - header: 'Önbelleği temizle', - description: - 'Bu işlem "{name}" için API okuma önbelleğini temizleyecektir. Okumalarda kısa bir yavaşlama yaşanacaktır.', - descriptionAll: - 'Bu işlem tüm navigasyonlar için API okuma önbelleğini temizleyecektir. Okumalarda kısa bir yavaşlama yaşanacaktır.', - confirm: 'Önbelleği temizle', - }, - }, - notification: { - error: 'Navigasyon kaydedilirken bir hata oluştu', - }, }, main: { search: {