From 5095b5e7137e2f5be504f77bb119468ba6e8d455 Mon Sep 17 00:00:00 2001 From: Tony CABAYE Date: Mon, 3 Feb 2025 18:25:39 +0100 Subject: [PATCH] refactor: layout and add access right management --- assets/components/Layout/AppHeader.tsx | 4 +- assets/components/Layout/AppLayout.tsx | 62 +--- assets/components/Layout/CommunityLayout.tsx | 81 ++++++ assets/components/Layout/DatastoreLayout.tsx | 57 +++- assets/components/Layout/Main.tsx | 50 ++++ assets/components/Utils/ErrorBoundary.tsx | 23 +- assets/contexts/community.tsx | 16 ++ assets/contexts/datastore.tsx | 35 +++ .../accesses-request/AccessesRequest.tsx | 194 +++++++------ .../CommunityList/CommunityList.tsx | 9 +- .../CommunityMembers.locale.tsx | 3 - .../CommunityMembers/CommunityMembers.tsx | 85 ++---- .../entrepot/pages/dashboard/DashboardPro.tsx | 40 ++- .../pages/data_details/StoredDataDetails.tsx | 18 +- .../pages/data_details/UploadDetails.tsx | 15 +- .../datasheet/DatasheetList/DatasheetList.tsx | 26 +- .../DatasheetUploadForm.tsx | 6 +- .../DatasheetUploadIntegrationPage.tsx | 6 +- .../DatasheetView/DatasheetView.tsx | 6 +- .../DatastoreCreationForm.tsx | 9 +- .../DatastoreCreationRequestConfirmation.tsx | 9 +- .../ManagePermissions/AddPermissionForm.tsx | 6 +- .../DatastoreManagePermissions.tsx | 14 +- .../ManagePermissions/EditPermissionForm.tsx | 6 +- .../ManageStorage/DatastoreManageStorage.tsx | 48 ++-- .../PyramidVectorGenerateForm.tsx | 6 +- .../PyramidVectorTmsServiceForm.tsx | 6 +- .../pages/service/view/ServiceView.tsx | 6 +- .../pages/service/wfs/WfsServiceForm.tsx | 6 +- .../PyramidRasterGenerateForm.tsx | 6 +- .../PyramidRasterWmsRasterServiceForm.tsx | 6 +- .../PyramidRasterWmtsServiceForm.tsx | 6 +- .../wms-vector/WmsVectorServiceForm.tsx | 8 +- .../pages/users/access-keys/MyAccessKeys.tsx | 9 +- .../pages/users/documents/MyDocuments.tsx | 6 +- .../entrepot/pages/users/keys/UserKeyForm.tsx | 8 +- assets/entrepot/pages/users/me/Me.tsx | 10 +- assets/i18n/Common.locale.tsx | 3 + assets/pages/About.tsx | 6 +- assets/pages/Documentation.tsx | 6 +- assets/pages/Home.tsx | 35 +-- assets/pages/Join.tsx | 6 +- assets/pages/LoginDisabled/LoginDisabled.tsx | 7 +- assets/pages/Offer.tsx | 6 +- assets/pages/RedirectToLogin.tsx | 7 +- assets/pages/assistance/Faq.tsx | 6 +- assets/pages/assistance/ServiceStatus.tsx | 7 +- assets/pages/assistance/contact/Contact.tsx | 6 +- .../contact/ContactConfirmation.tsx | 6 +- assets/pages/error/Forbidden.tsx | 17 ++ assets/pages/error/PageNotFound.tsx | 11 +- assets/pages/error/PageNotFoundWithLayout.tsx | 14 + assets/pages/footer/Accessibility.tsx | 7 +- assets/pages/footer/LegalNotice.tsx | 7 +- assets/pages/footer/PersonalData.tsx | 6 +- assets/pages/footer/Sitemap.tsx | 6 +- assets/pages/footer/TermsOfService.tsx | 7 +- assets/pages/news/NewsArticle.tsx | 8 +- assets/pages/news/NewsList.tsx | 6 +- assets/router/GroupApp.tsx | 129 +++++++++ assets/router/GroupCommunity.tsx | 39 +++ assets/router/GroupDatastore.tsx | 200 +++++++++++++ assets/router/RouterRenderer.tsx | 267 +++--------------- assets/router/router.ts | 202 ++++++------- 64 files changed, 1106 insertions(+), 832 deletions(-) create mode 100644 assets/components/Layout/CommunityLayout.tsx create mode 100644 assets/components/Layout/Main.tsx create mode 100644 assets/contexts/community.tsx create mode 100644 assets/contexts/datastore.tsx create mode 100644 assets/pages/error/Forbidden.tsx create mode 100644 assets/pages/error/PageNotFoundWithLayout.tsx create mode 100644 assets/router/GroupApp.tsx create mode 100644 assets/router/GroupCommunity.tsx create mode 100644 assets/router/GroupDatastore.tsx diff --git a/assets/components/Layout/AppHeader.tsx b/assets/components/Layout/AppHeader.tsx index 3917070a..271a91e6 100644 --- a/assets/components/Layout/AppHeader.tsx +++ b/assets/components/Layout/AppHeader.tsx @@ -5,7 +5,7 @@ import { FC, memo } from "react"; // import { useLang } from "../../i18n/i18n"; import SymfonyRouting from "../../modules/Routing"; -import { catalogueUrl, publicRoutes, routes, useRoute } from "../../router/router"; +import { catalogueUrl, groups, routes, useRoute } from "../../router/router"; import { useAuthStore } from "../../stores/AuthStore"; // import LanguageSelector from "../Utils/LanguageSelector"; @@ -58,7 +58,7 @@ const AppHeader: FC = ({ navItems = [] }) => { }); } else { // utilisateur est connecté - if (route.name === false || publicRoutes.includes(route.name)) { + if (route.name === false || groups.public.has(route)) { // on garde le lien vers le géoportail sur les pages également accessibles publiquement quickAccessItems.push(geoportailQuickAccessItem); } else { diff --git a/assets/components/Layout/AppLayout.tsx b/assets/components/Layout/AppLayout.tsx index 0b612f4a..52e2e5f0 100644 --- a/assets/components/Layout/AppLayout.tsx +++ b/assets/components/Layout/AppLayout.tsx @@ -1,20 +1,11 @@ -import { fr } from "@codegouvfr/react-dsfr"; -import { Breadcrumb, BreadcrumbProps } from "@codegouvfr/react-dsfr/Breadcrumb"; import { MainNavigationProps } from "@codegouvfr/react-dsfr/MainNavigation"; -import { Notice, addNoticeTranslations } from "@codegouvfr/react-dsfr/Notice"; +import { addNoticeTranslations } from "@codegouvfr/react-dsfr/Notice"; import { SkipLinks } from "@codegouvfr/react-dsfr/SkipLinks"; -import { useQuery } from "@tanstack/react-query"; -import { FC, PropsWithChildren, ReactNode, memo, useMemo } from "react"; +import { FC, PropsWithChildren, memo, useMemo } from "react"; import { ConsentBannerAndConsentManagement } from "../../config/consentManagement"; import { defaultNavItems } from "../../config/navItems/navItems"; -import api from "../../entrepot/api"; -import useDocumentTitle from "../../hooks/useDocumentTitle"; import { useTranslation } from "../../i18n/i18n"; -import RQKeys from "../../modules/entrepot/RQKeys"; -import getBreadcrumb from "../../modules/entrepot/breadcrumbs/Breadcrumb"; -import { useRoute } from "../../router/router"; -import SessionExpiredAlert from "../Utils/SessionExpiredAlert"; import SnackbarMessage from "../Utils/SnackbarMessage"; import AppFooter from "./AppFooter"; import AppHeader from "./AppHeader"; @@ -41,56 +32,19 @@ const HiddenElements: FC = () => { const HiddenElementsMemoized = memo(HiddenElements); -type AppLayoutProps = { +export interface AppLayoutProps { navItems?: MainNavigationProps.Item[]; - documentTitle?: string; - customBreadcrumbProps?: BreadcrumbProps; - infoBannerMsg?: ReactNode; -}; +} -const AppLayout: FC> = ({ children, navItems, documentTitle, customBreadcrumbProps, infoBannerMsg }) => { - useDocumentTitle(documentTitle); +const AppLayout: FC> = ({ children, navItems }) => { const { t } = useTranslation("navItems"); - - const route = useRoute(); - - const datastoreQuery = useQuery({ - // @ts-expect-error fausse alerte - queryKey: RQKeys.datastore(route.params.datastoreId), - // @ts-expect-error fausse alerte - queryFn: ({ signal }) => api.datastore.get(route.params.datastoreId, { signal }), - staleTime: 3600000, - enabled: "datastoreId" in route.params, - }); - - const breadcrumbProps = useMemo(() => { - if (customBreadcrumbProps !== undefined) { - return customBreadcrumbProps; - } - - return getBreadcrumb(route, datastoreQuery.data); - }, [route, datastoreQuery.data, customBreadcrumbProps]); - - navItems = useMemo(() => navItems ?? defaultNavItems(t), [navItems, t]); + const nav = useMemo(() => navItems ?? defaultNavItems(t), [navItems, t]); return ( <> - -
- {/* doit être le premier élément atteignable après le lien d'évitement (Accessibilité) : https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bandeau-d-information-importante */} - {infoBannerMsg && } - -
- {breadcrumbProps && } - -
- -
- - {children} -
-
+ + {children} diff --git a/assets/components/Layout/CommunityLayout.tsx b/assets/components/Layout/CommunityLayout.tsx new file mode 100644 index 00000000..230818da --- /dev/null +++ b/assets/components/Layout/CommunityLayout.tsx @@ -0,0 +1,81 @@ +import { useQuery } from "@tanstack/react-query"; +import { FC, PropsWithChildren, memo, useMemo } from "react"; + +import api from "../../entrepot/api"; +import RQKeys from "../../modules/entrepot/RQKeys"; +import { CartesApiException } from "../../modules/jsonFetch"; +import { DatastoreLayoutProps } from "./DatastoreLayout"; +import { useAuthStore } from "../../stores/AuthStore"; +import { CommunityDetailResponseDto, CommunityMemberDtoRightsEnum } from "../../@types/entrepot"; +import Forbidden from "../../pages/error/Forbidden"; +import { CommunityProvider } from "../../contexts/community"; +import { Datastore } from "../../@types/app"; +import { datastoreNavItems } from "../../config/navItems/datastoreNavItems"; +import AppLayout from "./AppLayout"; +import PageNotFoundWithLayout from "../../pages/error/PageNotFoundWithLayout"; +import Main from "./Main"; +import LoadingText from "../Utils/LoadingText"; +import { DatastoreProvider } from "../../contexts/datastore"; + +export interface CommunityLayoutProps extends Omit { + accessRight?: CommunityMemberDtoRightsEnum; + communityId: string; +} + +const CommunityLayout: FC> = (props) => { + const { accessRight, children, communityId, ...rest } = props; + + const { user } = useAuthStore(); + const { data, error, failureReason, isFetching, isLoading, status } = useQuery<[CommunityDetailResponseDto, Datastore | undefined], CartesApiException>({ + queryKey: RQKeys.community(communityId), + queryFn: async ({ signal }) => { + const community = await api.community.get(communityId, { signal }); + let datastore: Datastore | undefined; + if (community.datastore?._id) { + datastore = await api.datastore.get(community.datastore?._id, { signal }); + } + return [community, datastore]; + }, + staleTime: 20000, + enabled: !!communityId, + }); + + const [community, datastore] = data ?? []; + const navItems = useMemo(() => datastoreNavItems(datastore), [datastore]); + + const isAuthorized = useMemo(() => { + const communityMember = user?.communities_member.find((member) => member.community?._id === communityId); + if (!communityMember) { + return false; // is not part of the community + } + const { community, rights } = communityMember; + const isSupervisor = community?.supervisor === user?.id; + return isSupervisor || !accessRight || rights?.includes(accessRight); + }, [accessRight, user?.communities_member, communityId, user?.id]); + + if (isLoading) { + return ( + +
+ +
+
+ ); + } + + if (error?.code === 404 || failureReason?.code === 404 || !community) { + return ; + } + + return ( + + + + {isAuthorized ? children : } + + + + ); +}; + +export default memo(CommunityLayout); diff --git a/assets/components/Layout/DatastoreLayout.tsx b/assets/components/Layout/DatastoreLayout.tsx index c561c1f5..a6b82b46 100644 --- a/assets/components/Layout/DatastoreLayout.tsx +++ b/assets/components/Layout/DatastoreLayout.tsx @@ -1,4 +1,3 @@ -import { BreadcrumbProps } from "@codegouvfr/react-dsfr/Breadcrumb"; import { useQuery } from "@tanstack/react-query"; import { FC, PropsWithChildren, memo, useMemo } from "react"; @@ -7,30 +6,60 @@ import { datastoreNavItems } from "../../config/navItems/datastoreNavItems"; import api from "../../entrepot/api"; import RQKeys from "../../modules/entrepot/RQKeys"; import { CartesApiException } from "../../modules/jsonFetch"; -import PageNotFound from "../../pages/error/PageNotFound"; -import AppLayout from "./AppLayout"; +import AppLayout, { AppLayoutProps } from "./AppLayout"; +import { DatastoreProvider } from "../../contexts/datastore"; +import LoadingText from "../Utils/LoadingText"; +import PageNotFoundWithLayout from "../../pages/error/PageNotFoundWithLayout"; +import { useAuthStore } from "../../stores/AuthStore"; +import Main from "./Main"; +import { CommunityMemberDtoRightsEnum } from "../../@types/entrepot"; +import Forbidden from "../../pages/error/Forbidden"; -type DatastoreLayoutProps = { +export interface DatastoreLayoutProps extends Omit { + accessRight?: CommunityMemberDtoRightsEnum; datastoreId: string; - documentTitle?: string; - customBreadcrumbProps?: BreadcrumbProps; -}; -const DatastoreLayout: FC> = ({ datastoreId, documentTitle, customBreadcrumbProps, children }) => { - const datastoreQuery = useQuery({ +} +const DatastoreLayout: FC> = (props) => { + const { accessRight, datastoreId, children, ...rest } = props; + + const { user } = useAuthStore(); + const { data, error, failureReason, isFetching, isLoading, status } = useQuery({ queryKey: RQKeys.datastore(datastoreId), queryFn: ({ signal }) => api.datastore.get(datastoreId, { signal }), staleTime: 3600000, }); - const navItems = useMemo(() => datastoreNavItems(datastoreQuery.data), [datastoreQuery.data]); + const navItems = useMemo(() => datastoreNavItems(data), [data]); + + const isAuthorized = useMemo(() => { + const communityMember = user?.communities_member.find((member) => member.community?.datastore === datastoreId); + if (!communityMember) { + return false; // is not part of the community + } + const { community, rights } = communityMember; + const isSupervisor = community?.supervisor === user?.id; + return isSupervisor || !accessRight || rights?.includes(accessRight); + }, [accessRight, user?.communities_member, datastoreId, user?.id]); + + if (isLoading) { + return ( + +
+ +
+
+ ); + } - if (datastoreQuery?.error?.code === 404 || datastoreQuery.failureReason?.code === 404) { - return ; + if (error?.code === 404 || failureReason?.code === 404 || !data) { + return ; } return ( - - {children} + + + {isAuthorized ? children : } + ); }; diff --git a/assets/components/Layout/Main.tsx b/assets/components/Layout/Main.tsx new file mode 100644 index 00000000..719c2b29 --- /dev/null +++ b/assets/components/Layout/Main.tsx @@ -0,0 +1,50 @@ +import { fr } from "@codegouvfr/react-dsfr"; +import { Breadcrumb, BreadcrumbProps } from "@codegouvfr/react-dsfr/Breadcrumb"; +import { Notice } from "@codegouvfr/react-dsfr/Notice"; +import { PropsWithChildren, ReactNode, memo, useContext, useMemo } from "react"; + +import getBreadcrumb from "../../modules/entrepot/breadcrumbs/Breadcrumb"; +import { useRoute } from "../../router/router"; +import SessionExpiredAlert from "../Utils/SessionExpiredAlert"; +import useDocumentTitle from "../../hooks/useDocumentTitle"; +import { datastoreContext } from "../../contexts/datastore"; + +export interface MainProps { + customBreadcrumbProps?: BreadcrumbProps; + infoBannerMsg?: ReactNode; + title?: string; +} + +function Main(props: PropsWithChildren) { + const { children, customBreadcrumbProps, infoBannerMsg, title } = props; + const route = useRoute(); + useDocumentTitle(title); + const datastoreValue = useContext(datastoreContext); + + const breadcrumbProps = useMemo(() => { + if (customBreadcrumbProps !== undefined) { + return customBreadcrumbProps; + } + + return getBreadcrumb(route, datastoreValue.datastore); + }, [route, datastoreValue.datastore, customBreadcrumbProps]); + + return ( +
+ {/* doit être le premier élément atteignable après le lien d'évitement (Accessibilité) : https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bandeau-d-information-importante */} + {infoBannerMsg && } + +
+ {breadcrumbProps && } + +
+ +
+ + {children} +
+
+ ); +} + +export default memo(Main); diff --git a/assets/components/Utils/ErrorBoundary.tsx b/assets/components/Utils/ErrorBoundary.tsx index b4bc09dd..ceb68a6e 100644 --- a/assets/components/Utils/ErrorBoundary.tsx +++ b/assets/components/Utils/ErrorBoundary.tsx @@ -6,19 +6,22 @@ import { ErrorBoundary as BaseErrorBoundary, type FallbackProps } from "react-er import { routes } from "../../router/router"; import AppLayout from "../Layout/AppLayout"; +import Main from "../Layout/Main"; const Fallback: FC = ({ error, resetErrorBoundary }) => { return ( - - - + +
+ + +
); }; diff --git a/assets/contexts/community.tsx b/assets/contexts/community.tsx new file mode 100644 index 00000000..72afc840 --- /dev/null +++ b/assets/contexts/community.tsx @@ -0,0 +1,16 @@ +import { createContext, ReactNode, useContext } from "react"; +import { CommunityDetailResponseDto } from "../@types/entrepot"; + +export const communityContext = createContext(null); + +export function useCommunity() { + const community = useContext(communityContext); + if (!community) { + throw new Error("useCommunity must be used within a CommunityProvider"); + } + return community; +} + +export function CommunityProvider({ children, community }: { children: ReactNode; community: CommunityDetailResponseDto }) { + return {children}; +} diff --git a/assets/contexts/datastore.tsx b/assets/contexts/datastore.tsx new file mode 100644 index 00000000..ac54c837 --- /dev/null +++ b/assets/contexts/datastore.tsx @@ -0,0 +1,35 @@ +import { createContext, ReactNode, useContext, useMemo } from "react"; +import { Datastore } from "../@types/app"; + +export interface IDatastoreContext { + datastore?: Datastore; + isFetching: boolean; + status: "error" | "success" | "pending"; +} + +export const datastoreContext = createContext({ + datastore: undefined, + isFetching: false, + status: "pending", +}); + +export function useDatastore() { + const datastore = useContext(datastoreContext); + if (!datastore || !datastore.datastore) { + throw new Error("useDatastore must be used within a DatastoreProvider"); + } + return datastore; +} + +interface IDatastoreProviderProps { + children: ReactNode; + datastore?: Datastore; + isFetching: boolean; + status: "error" | "success" | "pending"; +} + +export function DatastoreProvider(props: IDatastoreProviderProps) { + const { children, datastore, isFetching, status } = props; + const context = useMemo(() => ({ datastore, isFetching, status }), [datastore, isFetching, status]); + return {children}; +} diff --git a/assets/entrepot/pages/accesses-request/AccessesRequest.tsx b/assets/entrepot/pages/accesses-request/AccessesRequest.tsx index 5b2469cd..64ecf428 100644 --- a/assets/entrepot/pages/accesses-request/AccessesRequest.tsx +++ b/assets/entrepot/pages/accesses-request/AccessesRequest.tsx @@ -11,7 +11,6 @@ import { useForm } from "react-hook-form"; import * as yup from "yup"; import { GeonetworkMetadataResponse } from "../../../@types/app"; -import AppLayout from "../../../components/Layout/AppLayout"; import LoadingText from "../../../components/Utils/LoadingText"; import Wait from "../../../components/Utils/Wait"; import { useTranslation } from "../../../i18n/i18n"; @@ -21,6 +20,7 @@ import { CartesApiException, jsonFetch } from "../../../modules/jsonFetch"; import { catalogueUrl, routes } from "../../../router/router"; import { useAuthStore } from "../../../stores/AuthStore"; import api from "../../api"; +import Main from "../../../components/Layout/Main"; type AskForAccesses = { fileIdentifier: string; @@ -121,108 +121,106 @@ const AccessesRequest: FC = ({ fileIdentifier }) => { }; return ( - - <> - {query.error ? ( - {t("back_to_dashboard")}} - /> - ) : ( - <> -

{t("title")}

- {query.isLoading ? ( - - ) : sendError !== undefined ? ( - - ) : query.data?.private_layers.length ? ( -
- {t("explain", { url: catalogueDatasheetUrl })} - { - const label = ( - - {layer.name} - {layer.endpointType && ( - - {layer.endpointType} - - )} - - ); - return { - label: label, - nativeInputProps: { - ...register("layers"), - value: layer.name, - }, - }; - })} - state={errors.layers ? "error" : "default"} - stateRelatedMessage={errors?.layers?.message?.toString()} - /> - { - const checked = e.currentTarget.checked; - setValue("myself", checked); - }, - checked: myself === true, - value: "myself", - }, +
+ {query.error ? ( + {t("back_to_dashboard")}} + /> + ) : ( + <> +

{t("title")}

+ {query.isLoading ? ( + + ) : sendError !== undefined ? ( + + ) : query.data?.private_layers.length ? ( +
+ {t("explain", { url: catalogueDatasheetUrl })} + { + const label = ( + + {layer.name} + {layer.endpointType && ( + + {layer.endpointType} + + )} + + ); + return { + label: label, + nativeInputProps: { + ...register("layers"), + value: layer.name, }, - ]} - /> - - + { + const checked = e.currentTarget.checked; + setValue("myself", checked); + }, + checked: myself === true, + value: "myself", }, - ]} - inlineLayoutWhen="always" - alignment="right" - className={fr.cx("fr-mt-2w")} - /> -
- ) : ( -
-

{t("explain_no_access")}

- + }, + ]} + /> + + +
+ ) : ( +
+

{t("explain_no_access")}

+ +
+ )} + + )} + {isSending && ( + +
+
+
+
- )} - - )} - {isSending && ( - -
-
-
- -
-
-
{t("sending_message")}
-
+
+
{t("sending_message")}
- - )} - - +
+
+ )} +
); }; diff --git a/assets/entrepot/pages/communities/CommunityList/CommunityList.tsx b/assets/entrepot/pages/communities/CommunityList/CommunityList.tsx index f5a5cbd0..10c69b4a 100644 --- a/assets/entrepot/pages/communities/CommunityList/CommunityList.tsx +++ b/assets/entrepot/pages/communities/CommunityList/CommunityList.tsx @@ -9,10 +9,8 @@ import { FC, useMemo, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { CommunityListResponseDto } from "../../../../@types/entrepot"; -import AppLayout from "../../../../components/Layout/AppLayout"; import LoadingText from "../../../../components/Utils/LoadingText"; import Wait from "../../../../components/Utils/Wait"; -import { datastoreNavItems } from "../../../../config/navItems/datastoreNavItems"; import { useTranslation } from "../../../../i18n"; import RQKeys from "../../../../modules/entrepot/RQKeys"; import { CartesApiException } from "../../../../modules/jsonFetch"; @@ -21,14 +19,13 @@ import { regex, removeDiacritics } from "../../../../utils"; import api from "../../../api"; import "../../../../sass/pages/community_list.scss"; +import Main from "../../../../components/Layout/Main"; const joinCommunityModal = createModal({ id: "join-community-modal", isOpenedByDefault: false, }); -const navItems = datastoreNavItems(); - const CommunityList: FC = () => { const { t } = useTranslation("CommunityList"); const { t: tCommon } = useTranslation("Common"); @@ -88,7 +85,7 @@ const CommunityList: FC = () => { }; return ( - +

{t("title")}

@@ -184,7 +181,7 @@ const CommunityList: FC = () => { document.body )} - +
); }; diff --git a/assets/entrepot/pages/communities/CommunityMembers/CommunityMembers.locale.tsx b/assets/entrepot/pages/communities/CommunityMembers/CommunityMembers.locale.tsx index b756ca1e..8947b040 100644 --- a/assets/entrepot/pages/communities/CommunityMembers/CommunityMembers.locale.tsx +++ b/assets/entrepot/pages/communities/CommunityMembers/CommunityMembers.locale.tsx @@ -12,7 +12,6 @@ const { i18n } = declareComponentKeys< | "remove_user" | "confirm_remove" | { K: "add_remove_right_title"; P: { right: string }; R: string } - | "no_necessary_rights" >()("CommunityMembers"); export type I18n = typeof i18n; @@ -27,7 +26,6 @@ export const CommunityMembersFrTranslations: Translations<"fr">["CommunityMember remove_user: "Supprimer cet utilisateur", confirm_remove: "Êtes-vous sûr de vouloir supprimer cet utilisateur ?", add_remove_right_title: ({ right }) => `Ajouter/supprimer le droit ${right}`, - no_necessary_rights: "Vous n'avez pas les droits nécessaires pour visualiser les membres de cet espace de travail.", }; export const CommunityMembersEnTranslations: Translations<"en">["CommunityMembers"] = { @@ -41,5 +39,4 @@ export const CommunityMembersEnTranslations: Translations<"en">["CommunityMember remove_user: "Remove this user", confirm_remove: "Are you sure you want to delete this user ?", add_remove_right_title: ({ right }) => `Add/remove right ${right} to user`, - no_necessary_rights: "You do not have the necessary rights to view and modify the users of this community.", }; diff --git a/assets/entrepot/pages/communities/CommunityMembers/CommunityMembers.tsx b/assets/entrepot/pages/communities/CommunityMembers/CommunityMembers.tsx index 64cfa873..a24475b9 100644 --- a/assets/entrepot/pages/communities/CommunityMembers/CommunityMembers.tsx +++ b/assets/entrepot/pages/communities/CommunityMembers/CommunityMembers.tsx @@ -3,11 +3,10 @@ import Alert from "@codegouvfr/react-dsfr/Alert"; import Button from "@codegouvfr/react-dsfr/Button"; import { ToggleSwitch } from "@codegouvfr/react-dsfr/ToggleSwitch"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { FC, useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { UserRightsResponseDto } from "../../../../@types/app"; -import { CommunityMemberDtoRightsEnum, CommunityUserResponseDto, UserDto } from "../../../../@types/entrepot"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; +import { CommunityUserResponseDto, UserDto } from "../../../../@types/entrepot"; import ConfirmDialog, { ConfirmDialogModal } from "../../../../components/Utils/ConfirmDialog"; import LoadingText from "../../../../components/Utils/LoadingText"; import Wait from "../../../../components/Utils/Wait"; @@ -21,9 +20,11 @@ import { AddMember, addMemberModal } from "../AddMember/AddMember"; import { complete, getTranslatedRightTypes, UserRights } from "../UserRights"; import "../../../../sass/pages/community_members.scss"; +import { useCommunity } from "../../../../contexts/community"; +import Main from "../../../../components/Layout/Main"; +import { useDatastore } from "../../../../contexts/datastore"; type CommunityMembersProps = { - communityId: string; userId?: string; }; @@ -50,7 +51,7 @@ const getName = (member: UserDto) => { return name.replace(/\s+/g, "") === "" ? member.email : name; }; -const CommunityMembers: FC = ({ communityId, userId }) => { +function CommunityMembers({ userId }: CommunityMembersProps) { // Traductions const { t: tCommon } = useTranslation("Common"); const { t } = useTranslation({ CommunityMembers }); @@ -60,47 +61,21 @@ const CommunityMembers: FC = ({ communityId, userId }) => // const [members, setMembers] = useState([]); const [currentMember, setCurrentMember] = useState(undefined); - // La communauté - const { data: community, isLoading: isLoadingCommunity } = useQuery({ - queryKey: RQKeys.community(communityId), - queryFn: ({ signal }) => api.community.get(communityId, { signal }), - staleTime: 20000, - enabled: !!communityId, - }); + // Data + const community = useCommunity(); + const { datastore } = useDatastore(); - const { data: datastore, isLoading: isLoadingDatastore } = useQuery({ - queryKey: RQKeys.datastore(community?.datastore?._id ?? "XXXX"), - queryFn: ({ signal }) => { - if (community?.datastore?._id !== undefined) { - return api.datastore.get(community?.datastore?._id, { signal }); - } - }, - staleTime: 3600000, - enabled: community?.datastore?._id !== undefined, + // Les membres de cette communauté + const { data: communityMembers, isLoading: isLoadingMembers } = useQuery({ + queryKey: RQKeys.community_members(community._id), + queryFn: ({ signal }) => api.community.getMembers(community._id, { signal }), + staleTime: 20000, }); - // Les droits sur cette communauté - const userRights = useMemo(() => { - const communityMember = user?.communities_member.filter((member) => member.community?._id === communityId); - return communityMember?.length ? communityMember[0].rights : undefined; - }, [user?.communities_member, communityId]); - const communitySupervisor = useMemo(() => { return community?.supervisor._id; }, [community]); - const isAuthorized = useMemo(() => { - const isSupervisor = communitySupervisor === user?.id; - return isSupervisor || userRights?.includes(CommunityMemberDtoRightsEnum.COMMUNITY); - }, [communitySupervisor, user?.id, userRights]); - - // Les membres de cette communauté - const { data: communityMembers, isLoading: isLoadingMembers } = useQuery({ - queryKey: RQKeys.community_members(communityId), - queryFn: ({ signal }) => api.community.getMembers(communityId, { signal }), - staleTime: 20000, - }); - const communityMemberIds = useMemo(() => { return communityMembers?.map((member) => member.user._id) ?? []; }, [communityMembers]); @@ -129,22 +104,22 @@ const CommunityMembers: FC = ({ communityId, userId }) => }, [communityMembers, communitySupervisor, user?.id]); useEffect(() => { - if (isAuthorized && userId && !isLoadingMembers && !communityMemberIds.includes(userId)) { + if (userId && !isLoadingMembers && !communityMemberIds.includes(userId)) { addMemberModal.open(); } - }, [communityMemberIds, isAuthorized, isLoadingMembers, userId]); + }, [communityMemberIds, isLoadingMembers, userId]); const queryClient = useQueryClient(); // Suppression d'un utilisateur const { isPending: isRemovePending, mutate: mutateRemove } = useMutation<{ user: string } | undefined, CartesApiException, string>({ mutationFn: (user_id: string) => { - if (communityId) return api.community.removeMember(communityId, user_id); + if (community._id) return api.community.removeMember(community._id, user_id); return Promise.resolve(undefined); }, onSuccess: (response) => { if (response) { - queryClient.setQueryData(RQKeys.community_members(communityId), () => { + queryClient.setQueryData(RQKeys.community_members(community._id), () => { return communityMembers?.filter((member) => member.user._id !== response.user); }); } @@ -154,12 +129,12 @@ const CommunityMembers: FC = ({ communityId, userId }) => // Modification des droits d'un utilisateur const { isPending: isModifyPending, mutate: mutateModify } = useMutation({ mutationFn: (datas) => { - if (communityId) return api.community.updateMember(communityId, datas); + if (community._id) return api.community.updateMember(community._id, datas); return Promise.resolve(undefined); }, onSuccess: (response) => { if (response) { - queryClient.setQueryData(RQKeys.community_members(communityId), (communityMembers) => { + queryClient.setQueryData(RQKeys.community_members(community._id), (communityMembers) => { communityMembers?.forEach((member) => { if (member.user._id === response.user) { member.rights = response.rights; // Mise a jour des droits @@ -186,9 +161,7 @@ const CommunityMembers: FC = ({ communityId, userId }) => }; return ( - = ({ communityId, userId }) => ], currentPageLabel: tBreadcrumb("members_list"), }} + title="Membres" > - {(isLoadingDatastore || isLoadingCommunity || isLoadingMembers) && } + {isLoadingMembers && } {!isLoadingMembers && userId && communityMemberIds.includes(userId) && ( = ({ communityId, userId }) => title={t("already_member", { userId: userId })} closable onClose={() => { - routes.members_list({ communityId }).push(); + routes.members_list({ communityId: community._id }).push(); }} /> )} - {!isLoadingMembers && isAuthorized === true && ( + {!isLoadingMembers && ( <>

{t("community_members", { communityName: community?.name ?? "" })}

@@ -290,10 +264,7 @@ const CommunityMembers: FC = ({ communityId, userId }) => )} )} - {isLoadingCommunity === false && isAuthorized === false && ( - - )} - + { @@ -302,8 +273,8 @@ const CommunityMembers: FC = ({ communityId, userId }) => } }} /> - + ); -}; +} export default CommunityMembers; diff --git a/assets/entrepot/pages/dashboard/DashboardPro.tsx b/assets/entrepot/pages/dashboard/DashboardPro.tsx index 9ae42f6b..93879ea1 100644 --- a/assets/entrepot/pages/dashboard/DashboardPro.tsx +++ b/assets/entrepot/pages/dashboard/DashboardPro.tsx @@ -5,10 +5,8 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import { useEffect } from "react"; import { CartesUser, Datastore } from "../../../@types/app"; -import AppLayout from "../../../components/Layout/AppLayout"; import LoadingIcon from "../../../components/Utils/LoadingIcon"; import Skeleton from "../../../components/Utils/Skeleton"; -import { datastoreNavItems } from "../../../config/navItems/datastoreNavItems"; import { useTranslation } from "../../../i18n/i18n"; import RQKeys from "../../../modules/entrepot/RQKeys"; import { CartesApiException } from "../../../modules/jsonFetch"; @@ -22,12 +20,11 @@ import avatarSvgUrl from "@codegouvfr/react-dsfr/dsfr/artwork/pictograms/digital import mailSendSvgUrl from "@codegouvfr/react-dsfr/dsfr/artwork/pictograms/digital/mail-send.svg"; import humanCoopSvgUrl from "@codegouvfr/react-dsfr/dsfr/artwork/pictograms/environment/human-cooperation.svg"; import padlockSvgUrl from "@codegouvfr/react-dsfr/dsfr/artwork/pictograms/system/padlock.svg"; +import Main from "../../../components/Layout/Main"; const DashboardPro = () => { const { t } = useTranslation("DashboardPro"); - const navItems = datastoreNavItems(); - const user = useAuthStore((state) => state.user); const setUser = useAuthStore((state) => state.setUser); const isApiEspaceCoDefined = useApiEspaceCoStore((state) => state.isUrlDefined); @@ -62,23 +59,24 @@ const DashboardPro = () => { mutate(undefined, { onSuccess: () => routes.datasheet_list({ datastoreId: datastoreId }).push() }); }; - const infoBannerMsg = ( - <> - Votre avis compte ! Participez à notre questionnaire pour nous aider à améliorer la fonctionnalité d’alimentation et de diffusion. Merci pour votre - contribution précieuse.{" "} - - Participer - - - ); - return ( - +
+ Votre avis compte ! Participez à notre questionnaire pour nous aider à améliorer la fonctionnalité d’alimentation et de diffusion. Merci + pour votre contribution précieuse.{" "} + + Participer + + + } + title={t("document_title")} + >

Bienvenue {user?.first_name ?? user?.user_name}

@@ -188,7 +186,7 @@ const DashboardPro = () => {
)} - +
); }; diff --git a/assets/entrepot/pages/data_details/StoredDataDetails.tsx b/assets/entrepot/pages/data_details/StoredDataDetails.tsx index 89f06208..0c495a50 100644 --- a/assets/entrepot/pages/data_details/StoredDataDetails.tsx +++ b/assets/entrepot/pages/data_details/StoredDataDetails.tsx @@ -5,8 +5,7 @@ import Tabs from "@codegouvfr/react-dsfr/Tabs"; import { useQuery } from "@tanstack/react-query"; import { FC, useEffect, useMemo, useState } from "react"; -import { Datastore, StoredDataStatusEnum } from "../../../@types/app"; -import DatastoreLayout from "../../../components/Layout/DatastoreLayout"; +import { StoredDataStatusEnum } from "../../../@types/app"; import LoadingIcon from "../../../components/Utils/LoadingIcon"; import RQKeys from "../../../modules/entrepot/RQKeys"; import { CartesApiException } from "../../../modules/jsonFetch"; @@ -14,6 +13,8 @@ import { routes } from "../../../router/router"; import api from "../../api"; import PreviewTab from "./PreviewTab/StoredDataPreviewTab"; import ReportTab from "./ReportTab/ReportTab"; +import { useDatastore } from "../../../contexts/datastore"; +import Main from "../../../components/Layout/Main"; type StoredDataDetailsProps = { datastoreId: string; @@ -21,12 +22,7 @@ type StoredDataDetailsProps = { }; const StoredDataDetails: FC = ({ datastoreId, storedDataId }) => { const [reportQueryEnabled, setReportQueryEnabled] = useState(true); - - const datastoreQuery = useQuery({ - queryKey: RQKeys.datastore(datastoreId), - queryFn: ({ signal }) => api.datastore.get(datastoreId, { signal }), - staleTime: 3600000, - }); + const { datastore } = useDatastore(); const reportQuery = useQuery({ queryKey: RQKeys.datastore_stored_data_report(datastoreId, storedDataId), @@ -47,7 +43,7 @@ const StoredDataDetails: FC = ({ datastoreId, storedData const datasheetName = useMemo(() => reportQuery?.data?.stored_data?.tags?.datasheet_name, [reportQuery?.data?.stored_data?.tags?.datasheet_name]); return ( - +
{datasheetName ? (
)} -
+ ); }; diff --git a/assets/entrepot/pages/data_details/UploadDetails.tsx b/assets/entrepot/pages/data_details/UploadDetails.tsx index b716f476..3ca173b6 100644 --- a/assets/entrepot/pages/data_details/UploadDetails.tsx +++ b/assets/entrepot/pages/data_details/UploadDetails.tsx @@ -6,7 +6,6 @@ import { useQuery } from "@tanstack/react-query"; import { FC, useMemo } from "react"; import { UploadReport } from "../../../@types/app"; -import DatastoreLayout from "../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../components/Utils/LoadingIcon"; import RQKeys from "../../../modules/entrepot/RQKeys"; import { CartesApiException } from "../../../modules/jsonFetch"; @@ -14,6 +13,8 @@ import { routes } from "../../../router/router"; import api from "../../api"; import UploadPreviewTab from "./PreviewTab/UploadPreviewTab"; import ReportTab from "./ReportTab/ReportTab"; +import { useDatastore } from "../../../contexts/datastore"; +import Main from "../../../components/Layout/Main"; type UploadDetailsProps = { datastoreId: string; @@ -21,11 +22,7 @@ type UploadDetailsProps = { }; const UploadDetails: FC = ({ datastoreId, uploadId }) => { - const datastoreQuery = useQuery({ - queryKey: RQKeys.datastore(datastoreId), - queryFn: ({ signal }) => api.datastore.get(datastoreId, { signal }), - staleTime: 3600000, - }); + const { datastore } = useDatastore(); const reportQuery = useQuery({ queryKey: RQKeys.datastore_upload_report(datastoreId, uploadId), @@ -36,7 +33,7 @@ const UploadDetails: FC = ({ datastoreId, uploadId }) => { const datasheetName = useMemo(() => reportQuery?.data?.input_upload?.tags?.datasheet_name, [reportQuery?.data?.input_upload?.tags?.datasheet_name]); return ( - +
{datasheetName ? (
)} - + ); }; diff --git a/assets/entrepot/pages/datasheet/DatasheetList/DatasheetList.tsx b/assets/entrepot/pages/datasheet/DatasheetList/DatasheetList.tsx index 14d6ab29..0ea251f4 100644 --- a/assets/entrepot/pages/datasheet/DatasheetList/DatasheetList.tsx +++ b/assets/entrepot/pages/datasheet/DatasheetList/DatasheetList.tsx @@ -5,7 +5,6 @@ import { useQuery } from "@tanstack/react-query"; import { FC, useMemo } from "react"; import { Datasheet, EndpointTypeEnum } from "../../../../@types/app"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../components/Utils/LoadingIcon"; import Skeleton from "../../../../components/Utils/Skeleton"; import { useTranslation } from "../../../../i18n/i18n"; @@ -13,42 +12,39 @@ import RQKeys from "../../../../modules/entrepot/RQKeys"; import { routes } from "../../../../router/router"; import api from "../../../api"; import DatasheetListItem from "./DatasheetListItem"; +import { useDatastore } from "../../../../contexts/datastore"; +import Main from "../../../../components/Layout/Main"; type DatasheetListProps = { datastoreId: string; }; const DatasheetList: FC = ({ datastoreId }) => { const { t } = useTranslation("DatasheetList"); - - const datastoreQuery = useQuery({ - queryKey: RQKeys.datastore(datastoreId), - queryFn: ({ signal }) => api.datastore.get(datastoreId, { signal }), - staleTime: 3600000, - }); + const { datastore, isFetching } = useDatastore(); const datasheetListQuery = useQuery({ queryKey: RQKeys.datastore_datasheet_list(datastoreId), queryFn: ({ signal }) => api.datasheet.getList(datastoreId, { signal }), staleTime: 60000, refetchInterval: 60000, - enabled: datastoreQuery.data !== undefined, + enabled: datastore !== undefined, }); const metadataEndpoint = useMemo( - () => datastoreQuery.data?.endpoints?.find((endpoint) => endpoint.endpoint.type === EndpointTypeEnum.METADATA), - [datastoreQuery.data?.endpoints] + () => datastore?.endpoints?.find((endpoint) => endpoint.endpoint.type === EndpointTypeEnum.METADATA), + [datastore?.endpoints] ); return ( - +

- {t("title", { datastoreName: datastoreQuery?.data?.name })} - {(datastoreQuery?.isFetching || datasheetListQuery?.isFetching) && } + {t("title", { datastoreName: datastore?.name })} + {(isFetching || datasheetListQuery?.isFetching) && }

- {datastoreQuery.data?.is_sandbox === true && t("sandbox_datastore_explanation")} + {datastore?.is_sandbox === true && t("sandbox_datastore_explanation")}
@@ -71,7 +67,7 @@ const DatasheetList: FC = ({ datastoreId }) => { )) )} - +
); }; diff --git a/assets/entrepot/pages/datasheet/DatasheetNew/DatasheetUploadForm/DatasheetUploadForm.tsx b/assets/entrepot/pages/datasheet/DatasheetNew/DatasheetUploadForm/DatasheetUploadForm.tsx index f6da1926..378191fa 100644 --- a/assets/entrepot/pages/datasheet/DatasheetNew/DatasheetUploadForm/DatasheetUploadForm.tsx +++ b/assets/entrepot/pages/datasheet/DatasheetNew/DatasheetUploadForm/DatasheetUploadForm.tsx @@ -13,7 +13,6 @@ import { symToStr } from "tsafe/symToStr"; import { v4 as uuidv4 } from "uuid"; import * as yup from "yup"; -import DatastoreLayout from "../../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../../components/Utils/LoadingIcon"; import LoadingText from "../../../../../components/Utils/LoadingText"; import Progress from "../../../../../components/Utils/Progress"; @@ -27,6 +26,7 @@ import { routes, useRoute } from "../../../../../router/router"; import { getFileExtension, regex } from "../../../../../utils"; import api from "../../../../api"; import DatasheetUploadIntegrationDialog from "../DatasheetUploadIntegration/DatasheetUploadIntegrationDialog"; +import Main from "../../../../../components/Layout/Main"; const maxFileSize = 2000000000; // 2 GB const fileExtensions = ["gpkg", "zip"]; @@ -232,7 +232,7 @@ const DatasheetUploadForm: FC = ({ datastoreId }) => { }; return ( - +
); }; diff --git a/assets/entrepot/pages/datasheet/DatasheetNew/DatasheetUploadIntegration/DatasheetUploadIntegrationPage.tsx b/assets/entrepot/pages/datasheet/DatasheetNew/DatasheetUploadIntegration/DatasheetUploadIntegrationPage.tsx index d1833188..e02c279b 100644 --- a/assets/entrepot/pages/datasheet/DatasheetNew/DatasheetUploadIntegration/DatasheetUploadIntegrationPage.tsx +++ b/assets/entrepot/pages/datasheet/DatasheetNew/DatasheetUploadIntegration/DatasheetUploadIntegrationPage.tsx @@ -1,9 +1,9 @@ import { fr } from "@codegouvfr/react-dsfr"; import { FC } from "react"; -import DatastoreLayout from "../../../../../components/Layout/DatastoreLayout"; import { useTranslation } from "../../../../../i18n"; import DatasheetUploadIntegrationDialog from "./DatasheetUploadIntegrationDialog"; +import Main from "../../../../../components/Layout/Main"; type DatasheetUploadIntegrationPageProps = { datastoreId: string; @@ -14,14 +14,14 @@ const DatasheetUploadIntegrationPage: FC = const { t } = useTranslation("DatasheetUploadIntegration"); return ( - +

{t("integration_page.title")}

- +
); }; diff --git a/assets/entrepot/pages/datasheet/DatasheetView/DatasheetView/DatasheetView.tsx b/assets/entrepot/pages/datasheet/DatasheetView/DatasheetView/DatasheetView.tsx index b6b04f1f..8bc81f58 100644 --- a/assets/entrepot/pages/datasheet/DatasheetView/DatasheetView/DatasheetView.tsx +++ b/assets/entrepot/pages/datasheet/DatasheetView/DatasheetView/DatasheetView.tsx @@ -11,7 +11,6 @@ import { createPortal } from "react-dom"; import { symToStr } from "tsafe/symToStr"; import { type Datasheet, type DatasheetDetailed, type Metadata } from "../../../../../@types/app"; -import DatastoreLayout from "../../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../../components/Utils/LoadingIcon"; import Wait from "../../../../../components/Utils/Wait"; import { useTranslation } from "../../../../../i18n/i18n"; @@ -24,6 +23,7 @@ import DatasheetThumbnail from "../DatasheetThumbnail"; import DocumentsTab from "../DocumentsTab/DocumentsTab"; import MetadataTab from "../MetadataTab/MetadataTab"; import ServicesListTab from "../ServiceListTab/ServicesListTab"; +import Main from "../../../../../components/Layout/Main"; const deleteDataConfirmModal = createModal({ id: "delete-data-confirm-modal", @@ -96,7 +96,7 @@ const DatasheetView: FC = ({ datastoreId, datasheetName }) = }); return ( - +
); }; diff --git a/assets/entrepot/pages/datastore/DatastoreCreationForm/DatastoreCreationForm.tsx b/assets/entrepot/pages/datastore/DatastoreCreationForm/DatastoreCreationForm.tsx index 380da7a0..249b418c 100644 --- a/assets/entrepot/pages/datastore/DatastoreCreationForm/DatastoreCreationForm.tsx +++ b/assets/entrepot/pages/datastore/DatastoreCreationForm/DatastoreCreationForm.tsx @@ -7,14 +7,13 @@ import { FC, useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import * as yup from "yup"; -import AppLayout from "../../../../components/Layout/AppLayout"; import Wait from "../../../../components/Utils/Wait"; -import { datastoreNavItems } from "../../../../config/navItems/datastoreNavItems"; import { useTranslation } from "../../../../i18n"; import SymfonyRouting from "../../../../modules/Routing"; import { jsonFetch } from "../../../../modules/jsonFetch"; import { routes } from "../../../../router/router"; import { removeDiacritics } from "../../../../utils"; +import Main from "../../../../components/Layout/Main"; const DatastoreCreationForm: FC = () => { const { t } = useTranslation("DatastoreCreationForm"); @@ -66,10 +65,8 @@ const DatastoreCreationForm: FC = () => { .finally(() => setIsSending(false)); }; - const navItems = datastoreNavItems(); - return ( - +

{t("title")}

@@ -128,7 +125,7 @@ const DatastoreCreationForm: FC = () => {
)} - +
); }; diff --git a/assets/entrepot/pages/datastore/DatastoreCreationForm/DatastoreCreationRequestConfirmation.tsx b/assets/entrepot/pages/datastore/DatastoreCreationForm/DatastoreCreationRequestConfirmation.tsx index f3062643..df1c6668 100644 --- a/assets/entrepot/pages/datastore/DatastoreCreationForm/DatastoreCreationRequestConfirmation.tsx +++ b/assets/entrepot/pages/datastore/DatastoreCreationForm/DatastoreCreationRequestConfirmation.tsx @@ -2,18 +2,15 @@ import { fr } from "@codegouvfr/react-dsfr"; import Alert from "@codegouvfr/react-dsfr/Alert"; import Button from "@codegouvfr/react-dsfr/Button"; -import AppLayout from "../../../../components/Layout/AppLayout"; -import { datastoreNavItems } from "../../../../config/navItems/datastoreNavItems"; import { useTranslation } from "../../../../i18n"; import { routes } from "../../../../router/router"; - -const navItems = datastoreNavItems(); +import Main from "../../../../components/Layout/Main"; const DatastoreCreationRequestConfirmation = () => { const { t } = useTranslation("DatastoreCreationForm"); return ( - +

{t("request_confirmation.title")}

{
- +
); }; diff --git a/assets/entrepot/pages/datastore/ManagePermissions/AddPermissionForm.tsx b/assets/entrepot/pages/datastore/ManagePermissions/AddPermissionForm.tsx index 5309015c..9a4da6bb 100644 --- a/assets/entrepot/pages/datastore/ManagePermissions/AddPermissionForm.tsx +++ b/assets/entrepot/pages/datastore/ManagePermissions/AddPermissionForm.tsx @@ -13,7 +13,6 @@ import "../../../../sass/pages/permission.scss"; import api from "../../../api"; import DatePicker from "../../../../components/Input/DatePicker"; import InputCollection from "../../../../components/Input/InputCollection"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; import LoadingText from "../../../../components/Utils/LoadingText"; import Wait from "../../../../components/Utils/Wait"; import { useTranslation } from "../../../../i18n/i18n"; @@ -25,6 +24,7 @@ import CommunityListForm from "./CommunityListForm"; import ScrollOfferingList from "./ScrollOfferingList"; import { getAddSchema } from "./ValidationSchemas"; import createRequestBody, { type AddPermissionFormType } from "./utils"; +import Main from "../../../../components/Layout/Main"; type AddPermissionFormProps = { datastoreId: string; @@ -137,7 +137,7 @@ const AddPermissionForm: FC = ({ datastoreId }) => { }, [type, setFormValue]); return ( - +

{t("add_form.title")}

{addPermissionStatus === "pending" && ( @@ -270,7 +270,7 @@ const AddPermissionForm: FC = ({ datastoreId }) => { )} - +
); }; diff --git a/assets/entrepot/pages/datastore/ManagePermissions/DatastoreManagePermissions.tsx b/assets/entrepot/pages/datastore/ManagePermissions/DatastoreManagePermissions.tsx index cfb54d19..022ecbe9 100644 --- a/assets/entrepot/pages/datastore/ManagePermissions/DatastoreManagePermissions.tsx +++ b/assets/entrepot/pages/datastore/ManagePermissions/DatastoreManagePermissions.tsx @@ -7,16 +7,16 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { compareAsc } from "date-fns"; import { FC, ReactNode, useMemo, useState } from "react"; import api from "../../../api"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; import LoadingText from "../../../../components/Utils/LoadingText"; import { useTranslation } from "../../../../i18n/i18n"; import RQKeys from "../../../../modules/entrepot/RQKeys"; import { routes } from "../../../../router/router"; -import { Datastore } from "../../../../@types/app"; import { DatastorePermissionResponseDto } from "../../../../@types/entrepot"; import ConfirmDialog, { ConfirmDialogModal } from "../../../../components/Utils/ConfirmDialog"; import { CartesApiException } from "../../../../modules/jsonFetch"; import Wait from "../../../../components/Utils/Wait"; +import { useDatastore } from "../../../../contexts/datastore"; +import Main from "../../../../components/Layout/Main"; type DatastoreManagePermissionsProps = { datastoreId: string; @@ -29,11 +29,7 @@ const DatastoreManagePermissions: FC = ({ datas const queryClient = useQueryClient(); // Le datastore - const { data: datastore, status: datastoreStatus } = useQuery({ - queryKey: RQKeys.datastore(datastoreId), - queryFn: ({ signal }) => api.datastore.get(datastoreId, { signal }), - staleTime: 3600000, - }); + const { datastore, status: datastoreStatus } = useDatastore(); // Les permissions const { data: permissions, status: permissionStatus } = useQuery({ @@ -119,7 +115,7 @@ const DatastoreManagePermissions: FC = ({ datas }, [datastoreId, permissions, tCommon, t]); return ( - +

{t("list.title", { datastoreName: datastore?.name })}

{removeStatus === "error" && } {removeStatus === "pending" && ( @@ -148,7 +144,7 @@ const DatastoreManagePermissions: FC = ({ datas } }} /> - +
); }; diff --git a/assets/entrepot/pages/datastore/ManagePermissions/EditPermissionForm.tsx b/assets/entrepot/pages/datastore/ManagePermissions/EditPermissionForm.tsx index 2caea6fe..4a991b65 100644 --- a/assets/entrepot/pages/datastore/ManagePermissions/EditPermissionForm.tsx +++ b/assets/entrepot/pages/datastore/ManagePermissions/EditPermissionForm.tsx @@ -9,7 +9,6 @@ import { FC, useMemo } from "react"; import { Controller, useForm } from "react-hook-form"; import api from "../../../api"; import DatePicker from "../../../../components/Input/DatePicker"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; import LoadingText from "../../../../components/Utils/LoadingText"; import Wait from "../../../../components/Utils/Wait"; import { useTranslation } from "../../../../i18n/i18n"; @@ -19,6 +18,7 @@ import { DatastorePermissionResponseDto } from "../../../../@types/entrepot"; import ScrollOfferingList from "./ScrollOfferingList"; import { getEditSchema } from "./ValidationSchemas"; import createRequestBody, { EditPermissionFormType } from "./utils"; +import Main from "../../../../components/Layout/Main"; type EditPermissionFormProps = { datastoreId: string; @@ -95,7 +95,7 @@ const EditPermissionForm: FC = ({ datastoreId, permissi }; return ( - +

{t("edit_form.title", { permission: permissionQuery.data })}

{updateMutation.isPending && ( @@ -182,7 +182,7 @@ const EditPermissionForm: FC = ({ datastoreId, permissi )} - +
); }; diff --git a/assets/entrepot/pages/datastore/ManageStorage/DatastoreManageStorage.tsx b/assets/entrepot/pages/datastore/ManageStorage/DatastoreManageStorage.tsx index 9ddc67d7..06e372da 100644 --- a/assets/entrepot/pages/datastore/ManageStorage/DatastoreManageStorage.tsx +++ b/assets/entrepot/pages/datastore/ManageStorage/DatastoreManageStorage.tsx @@ -1,13 +1,9 @@ import { fr } from "@codegouvfr/react-dsfr"; import Tabs, { TabsProps } from "@codegouvfr/react-dsfr/Tabs"; -import { useQuery } from "@tanstack/react-query"; import { FC, useMemo } from "react"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../components/Utils/LoadingIcon"; import { useTranslation } from "../../../../i18n/i18n"; -import RQKeys from "../../../../modules/entrepot/RQKeys"; -import api from "../../../api"; import AnnexeUsage from "./storages/AnnexeUsage"; import EndpointsUsage from "./storages/EndpointsUsage"; import FilesystemUsage from "./storages/FilesystemUsage"; @@ -15,82 +11,76 @@ import PostgresqlUsage from "./storages/PostgresqlUsage"; import S3Usage from "./storages/S3Usage"; import StaticsUsage from "./storages/StaticsUsage"; import UploadUsage from "./storages/UploadUsage"; +import { useDatastore } from "../../../../contexts/datastore"; +import Main from "../../../../components/Layout/Main"; -type DatastoreManageStorageProps = { - datastoreId: string; -}; -const DatastoreManageStorage: FC = ({ datastoreId }) => { +const DatastoreManageStorage: FC = () => { const { t } = useTranslation("DatastoreManageStorage"); - - const datastoreQuery = useQuery({ - queryKey: RQKeys.datastore(datastoreId), - queryFn: ({ signal }) => api.datastore.get(datastoreId, { signal }), - staleTime: 3600000, - }); + const { datastore, isFetching } = useDatastore(); const tabs: TabsProps["tabs"] = useMemo(() => { - if (datastoreQuery.data === undefined) { + if (datastore === undefined) { return []; } // NOTE : d'après les utilisations de l'API vues jusque là, seul le stockage FILESYSTEM est optionnel, les autres sont forcément là - const hasFilesystemStorage = datastoreQuery.data?.storages.data?.find((data) => data.storage.type === "FILESYSTEM") !== undefined; + const hasFilesystemStorage = datastore?.storages.data?.find((data) => data.storage.type === "FILESYSTEM") !== undefined; const tabs: TabsProps["tabs"] = [ { label: t("storage.postgresql.label"), - content: , + content: , }, { label: t("storage.s3.label"), - content: , + content: , }, { label: t("storage.upload.label"), - content: , + content: , }, { label: t("storage.annexe.label"), - content: , + content: , }, { label: t("storage.endpoints.label"), - content: , + content: , }, { label: t("storage.statics.label"), - content: , + content: , }, ]; if (hasFilesystemStorage) { tabs.unshift({ label: t("storage.filesystem.label"), - content: , + content: , }); } return tabs; - }, [datastoreQuery.data, t]); + }, [datastore, t]); return ( - +

- {t("title", { datastoreName: datastoreQuery?.data?.name })} - {datastoreQuery?.isFetching && } + {t("title", { datastoreName: datastore?.name })} + {isFetching && }

{t("explanation")}

- {datastoreQuery.data && ( + {datastore && (
)} - +
); }; diff --git a/assets/entrepot/pages/service/tms/PyramidVectorGenerateForm/PyramidVectorGenerateForm.tsx b/assets/entrepot/pages/service/tms/PyramidVectorGenerateForm/PyramidVectorGenerateForm.tsx index 25937198..4745085d 100644 --- a/assets/entrepot/pages/service/tms/PyramidVectorGenerateForm/PyramidVectorGenerateForm.tsx +++ b/assets/entrepot/pages/service/tms/PyramidVectorGenerateForm/PyramidVectorGenerateForm.tsx @@ -10,7 +10,6 @@ import { useForm } from "react-hook-form"; import * as yup from "yup"; import { type StoredDataRelation, type VectorDb } from "../../../../../@types/app"; -import DatastoreLayout from "../../../../../components/Layout/DatastoreLayout"; import LoadingText from "../../../../../components/Utils/LoadingText"; import Wait from "../../../../../components/Utils/Wait"; import olDefaults from "../../../../../data/ol-defaults.json"; @@ -26,6 +25,7 @@ import Sample, { type SampleType } from "../sample/Sample"; import TableAttributeSelection from "../tables/TableAttributeSelection"; import TableZoomLevels from "../tables/TableZoomLevels"; import TippeCanoe from "../tippecanoes/Tippecanoe"; +import Main from "../../../../../components/Layout/Main"; export type PyramidVectorGenerateFormValuesType = { selected_tables?: string[]; @@ -160,7 +160,7 @@ const PyramidVectorGenerateForm: FC = ({ datastoreId, vec }; return ( - +

{t("title")}

{vectorDbQuery.isLoading ? ( @@ -232,7 +232,7 @@ const PyramidVectorGenerateForm: FC = ({ datastoreId, vec )} - +
); }; diff --git a/assets/entrepot/pages/service/tms/PyramidVectorTmsServiceForm/PyramidVectorTmsServiceForm.tsx b/assets/entrepot/pages/service/tms/PyramidVectorTmsServiceForm/PyramidVectorTmsServiceForm.tsx index 4d703d74..51631726 100644 --- a/assets/entrepot/pages/service/tms/PyramidVectorTmsServiceForm/PyramidVectorTmsServiceForm.tsx +++ b/assets/entrepot/pages/service/tms/PyramidVectorTmsServiceForm/PyramidVectorTmsServiceForm.tsx @@ -9,7 +9,6 @@ import { FC, useCallback, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; import { ConfigurationTypeEnum, EndpointTypeEnum, PyramidVector, Service, ServiceFormValuesBaseType } from "../../../../../@types/app"; -import DatastoreLayout from "../../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../../components/Utils/LoadingIcon"; import LoadingText from "../../../../../components/Utils/LoadingText"; import Wait from "../../../../../components/Utils/Wait"; @@ -25,6 +24,7 @@ import { getPyramidVectorTmsServiceFormDefaultValues } from "../../common/defaul import AdditionalInfo from "../../metadata/AdditionalInfo"; import Description from "../../metadata/Description"; import UploadMDFile from "../../metadata/UploadMDFile"; +import Main from "../../../../../components/Layout/Main"; export type PyramidVectorTmsServiceFormValuesType = ServiceFormValuesBaseType; @@ -182,7 +182,7 @@ const PyramidVectorTmsServiceForm: FC = ({ dat }, [createServiceMutation, editServiceMutation, currentStep, trigger, editMode]); return ( - +

{t("title", { editMode })}

{pyramidQuery.isLoading || offeringQuery.isLoading ? ( @@ -274,7 +274,7 @@ const PyramidVectorTmsServiceForm: FC = ({ dat )} - +
); }; diff --git a/assets/entrepot/pages/service/view/ServiceView.tsx b/assets/entrepot/pages/service/view/ServiceView.tsx index f403d829..16a83435 100644 --- a/assets/entrepot/pages/service/view/ServiceView.tsx +++ b/assets/entrepot/pages/service/view/ServiceView.tsx @@ -7,7 +7,6 @@ import { useQuery } from "@tanstack/react-query"; import { FC, useEffect, useMemo, useState } from "react"; import { type CartesStyle, OfferingStatusEnum, OfferingTypeEnum, type Service, StoredDataTypeEnum, type TypeInfosWithBbox } from "../../../../@types/app"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; import LoadingText from "../../../../components/Utils/LoadingText"; import type { MapInitial } from "../../../../components/Utils/RMap"; import RMap from "../../../../components/Utils/RMap"; @@ -20,6 +19,7 @@ import DiffuseServiceTab from "./DiffuseServiceTab"; import ManageStylesTab from "./ManageStylesTab"; import "../../../../sass/pages/service_view.scss"; +import Main from "../../../../components/Layout/Main"; type ServiceViewProps = { datastoreId: string; @@ -96,7 +96,7 @@ const ServiceView: FC = ({ datastoreId, offeringId, datasheetN }, [datasheetName, datastoreId, offeringId, serviceQuery.data, route.params]); return ( - +
{serviceQuery.isLoading ? ( ) : serviceQuery.error ? ( @@ -159,7 +159,7 @@ const ServiceView: FC = ({ datastoreId, offeringId, datasheetN )} - +
); }; diff --git a/assets/entrepot/pages/service/wfs/WfsServiceForm.tsx b/assets/entrepot/pages/service/wfs/WfsServiceForm.tsx index 074b008d..62af820e 100644 --- a/assets/entrepot/pages/service/wfs/WfsServiceForm.tsx +++ b/assets/entrepot/pages/service/wfs/WfsServiceForm.tsx @@ -11,7 +11,6 @@ import { symToStr } from "tsafe/symToStr"; import * as yup from "yup"; import { ConfigurationTypeEnum, EndpointTypeEnum, Service, ServiceFormValuesBaseType, StoredDataRelation, VectorDb } from "../../../../@types/app"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../components/Utils/LoadingIcon"; import LoadingText from "../../../../components/Utils/LoadingText"; import Wait from "../../../../components/Utils/Wait"; @@ -31,6 +30,7 @@ import Description from "../metadata/Description"; import UploadMDFile from "../metadata/UploadMDFile"; import TableInfosForm from "./TablesInfoForm"; import { regex } from "../../../../utils"; +import Main from "../../../../components/Layout/Main"; type TableInfoType = Record; @@ -283,7 +283,7 @@ const WfsServiceForm: FC = ({ datastoreId, vectorDbId, offe }, [createServiceMutation, editServiceMutation, currentStep, trigger, editMode]); return ( - +

{t("title", { editMode })}

{vectorDbQuery.isLoading || offeringQuery.isLoading || metadataQuery.isLoading ? ( @@ -383,7 +383,7 @@ const WfsServiceForm: FC = ({ datastoreId, vectorDbId, offe )} - +
); }; diff --git a/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterGenerateForm/PyramidRasterGenerateForm.tsx b/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterGenerateForm/PyramidRasterGenerateForm.tsx index e597f0b6..6172fa8c 100644 --- a/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterGenerateForm/PyramidRasterGenerateForm.tsx +++ b/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterGenerateForm/PyramidRasterGenerateForm.tsx @@ -12,7 +12,6 @@ import * as yup from "yup"; import type { PyramidRaster, Service } from "../../../../../@types/app"; import type { ConfigurationWmsVectorDetailsContent } from "../../../../../@types/entrepot"; -import DatastoreLayout from "../../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../../components/Utils/LoadingIcon"; import LoadingText from "../../../../../components/Utils/LoadingText"; import Wait from "../../../../../components/Utils/Wait"; @@ -26,6 +25,7 @@ import { routes } from "../../../../../router/router"; import { bboxToWkt } from "../../../../../utils"; import api from "../../../../api"; import { DatasheetViewActiveTabEnum } from "../../../datasheet/DatasheetView/DatasheetView/DatasheetView"; +import Main from "../../../../../components/Layout/Main"; const STEPS = { TECHNICAL_NAME: 1, @@ -121,7 +121,7 @@ const PyramidRasterGenerateForm: FC = ({ datasto }, [currentStep, generatePyramidRasterMutation, trigger]); return ( - +

{t("title")}

{serviceQuery.isLoading ? ( @@ -236,7 +236,7 @@ const PyramidRasterGenerateForm: FC = ({ datasto )} - +
); }; diff --git a/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterWmsRasterServiceForm/PyramidRasterWmsRasterServiceForm.tsx b/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterWmsRasterServiceForm/PyramidRasterWmsRasterServiceForm.tsx index c80617b2..930b1f9a 100644 --- a/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterWmsRasterServiceForm/PyramidRasterWmsRasterServiceForm.tsx +++ b/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterWmsRasterServiceForm/PyramidRasterWmsRasterServiceForm.tsx @@ -10,7 +10,6 @@ import { useForm } from "react-hook-form"; import { symToStr } from "tsafe/symToStr"; import { ConfigurationTypeEnum, EndpointTypeEnum, PyramidRaster, Service, ServiceFormValuesBaseType } from "../../../../../@types/app"; -import DatastoreLayout from "../../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../../components/Utils/LoadingIcon"; import LoadingText from "../../../../../components/Utils/LoadingText"; import Wait from "../../../../../components/Utils/Wait"; @@ -26,6 +25,7 @@ import { getPyramidRasterWmsRasterServiceFormDefaultValues } from "../../common/ import AdditionalInfo from "../../metadata/AdditionalInfo"; import Description from "../../metadata/Description"; import UploadMDFile from "../../metadata/UploadMDFile"; +import Main from "../../../../../components/Layout/Main"; const STEPS = { METADATA_UPLOAD: 1, @@ -162,7 +162,7 @@ const PyramidRasterWmsRasterServiceForm: FC +

{t("title", { editMode })}

{pyramidQuery.isLoading || offeringQuery.isLoading || metadataQuery.isLoading ? ( @@ -255,7 +255,7 @@ const PyramidRasterWmsRasterServiceForm: FC )} - +
); }; diff --git a/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterWmtsServiceForm/PyramidRasterWmtsServiceForm.tsx b/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterWmtsServiceForm/PyramidRasterWmtsServiceForm.tsx index 88bbef54..1b687b02 100644 --- a/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterWmtsServiceForm/PyramidRasterWmtsServiceForm.tsx +++ b/assets/entrepot/pages/service/wms-raster-wmts/PyramidRasterWmtsServiceForm/PyramidRasterWmtsServiceForm.tsx @@ -10,7 +10,6 @@ import { useForm } from "react-hook-form"; import { symToStr } from "tsafe/symToStr"; import { ConfigurationTypeEnum, EndpointTypeEnum, PyramidRaster, Service, ServiceFormValuesBaseType } from "../../../../../@types/app"; -import DatastoreLayout from "../../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../../components/Utils/LoadingIcon"; import LoadingText from "../../../../../components/Utils/LoadingText"; import Wait from "../../../../../components/Utils/Wait"; @@ -26,6 +25,7 @@ import { getPyramidRasterWmtsServiceFormDefaultValues } from "../../common/defau import AdditionalInfo from "../../metadata/AdditionalInfo"; import Description from "../../metadata/Description"; import UploadMDFile from "../../metadata/UploadMDFile"; +import Main from "../../../../../components/Layout/Main"; const STEPS = { METADATA_UPLOAD: 1, @@ -162,7 +162,7 @@ const PyramidRasterWmtsServiceForm: FC = ({ d }, [createServiceMutation, editServiceMutation, currentStep, trigger, editMode]); return ( - +

{t("title", { editMode })}

{pyramidQuery.isLoading || offeringQuery.isLoading || metadataQuery.isLoading ? ( @@ -255,7 +255,7 @@ const PyramidRasterWmtsServiceForm: FC = ({ d )} - +
); }; diff --git a/assets/entrepot/pages/service/wms-vector/WmsVectorServiceForm.tsx b/assets/entrepot/pages/service/wms-vector/WmsVectorServiceForm.tsx index a5593247..8e680290 100644 --- a/assets/entrepot/pages/service/wms-vector/WmsVectorServiceForm.tsx +++ b/assets/entrepot/pages/service/wms-vector/WmsVectorServiceForm.tsx @@ -19,7 +19,6 @@ import { type StoredDataRelation, type VectorDb, } from "../../../../@types/app"; -import DatastoreLayout from "../../../../components/Layout/DatastoreLayout"; import LoadingIcon from "../../../../components/Utils/LoadingIcon"; import LoadingText from "../../../../components/Utils/LoadingText"; import Wait from "../../../../components/Utils/Wait"; @@ -38,6 +37,7 @@ import AdditionalInfo from "../metadata/AdditionalInfo"; import Description from "../metadata/Description"; import UploadMDFile from "../metadata/UploadMDFile"; import UploadStyleFile from "./UploadStyleFile"; +import Main from "../../../../components/Layout/Main"; /** * Convertir en v1.0.0 si l'utilisateur a déposé un sld en v1.1.0 @@ -122,8 +122,8 @@ const WmsVectorServiceForm: FC = ({ datastoreId, vect const { t } = useTranslation("WmsVectorServiceForm"); const { t: tCommon } = useTranslation("Common"); - const editMode = useMemo(() => !!offeringId, [offeringId]); const [currentStep, setCurrentStep] = useState(STEPS.TABLES_INFOS); + const editMode = useMemo(() => !!offeringId, [offeringId]); const queryClient = useQueryClient(); @@ -297,7 +297,7 @@ const WmsVectorServiceForm: FC = ({ datastoreId, vect }, [createServiceMutation, editServiceMutation, currentStep, trigger, editMode]); return ( - +

{t("title", { editMode })}

{vectorDbQuery.isLoading || offeringQuery.isLoading || metadataQuery.isLoading ? ( @@ -391,7 +391,7 @@ const WmsVectorServiceForm: FC = ({ datastoreId, vect )} - +
); }; diff --git a/assets/entrepot/pages/users/access-keys/MyAccessKeys.tsx b/assets/entrepot/pages/users/access-keys/MyAccessKeys.tsx index 69bad25d..05a87360 100644 --- a/assets/entrepot/pages/users/access-keys/MyAccessKeys.tsx +++ b/assets/entrepot/pages/users/access-keys/MyAccessKeys.tsx @@ -5,20 +5,17 @@ import { FC } from "react"; import { UserKeyDetailedWithAccessesResponseDto } from "../../../../@types/app"; import { PermissionWithOfferingsDetailsResponseDto } from "../../../../@types/entrepot"; -import AppLayout from "../../../../components/Layout/AppLayout"; import LoadingText from "../../../../components/Utils/LoadingText"; -import { datastoreNavItems } from "../../../../config/navItems/datastoreNavItems"; import { getTranslation } from "../../../../i18n/i18n"; import RQKeys from "../../../../modules/entrepot/RQKeys"; import api from "../../../api"; import UserKeysListTab from "../keys/UserKeysListTab/UserKeysListTab"; import PermissionsListTab from "../permissions/PermissionsListTab"; +import Main from "../../../../components/Layout/Main"; const { t } = getTranslation("MyAccessKeys"); const MyAccessKeys: FC = () => { - const navItems = datastoreNavItems(); - // Les cles d'acces const { data: keys, isLoading: isLoadingKeys } = useQuery({ queryKey: RQKeys.my_keys(), @@ -34,7 +31,7 @@ const MyAccessKeys: FC = () => { }); return ( - +
{isLoadingKeys || isLoadingPermissions ? ( ) : ( @@ -60,7 +57,7 @@ const MyAccessKeys: FC = () => { )} - +
); }; diff --git a/assets/entrepot/pages/users/documents/MyDocuments.tsx b/assets/entrepot/pages/users/documents/MyDocuments.tsx index fb8c5445..d88acf46 100644 --- a/assets/entrepot/pages/users/documents/MyDocuments.tsx +++ b/assets/entrepot/pages/users/documents/MyDocuments.tsx @@ -10,13 +10,13 @@ import { FC, FormEvent, useState } from "react"; import { useDebounceCallback } from "usehooks-ts"; import { DocumentListResponseDto } from "../../../../@types/entrepot"; -import AppLayout from "../../../../components/Layout/AppLayout"; import LoadingIcon from "../../../../components/Utils/LoadingIcon"; import Wait from "../../../../components/Utils/Wait"; import RQKeys from "../../../../modules/entrepot/RQKeys"; import { CartesApiException, jsonFetch } from "../../../../modules/jsonFetch"; import SymfonyRouting from "../../../../modules/Routing"; import { niceBytes } from "../../../../utils"; +import Main from "../../../../components/Layout/Main"; const MyDocuments: FC = () => { const [filter, setFilter] = useState({}); @@ -66,7 +66,7 @@ const MyDocuments: FC = () => { }; return ( - +

Mes documents

Liste de documents {documentsQuery.isFetching ? : `(${documentsQuery?.data?.length ?? 0})`}

@@ -151,7 +151,7 @@ const MyDocuments: FC = () => {

Suppression du document en cours

)} - +
); }; diff --git a/assets/entrepot/pages/users/keys/UserKeyForm.tsx b/assets/entrepot/pages/users/keys/UserKeyForm.tsx index 1580d6ab..d0e7af30 100644 --- a/assets/entrepot/pages/users/keys/UserKeyForm.tsx +++ b/assets/entrepot/pages/users/keys/UserKeyForm.tsx @@ -11,10 +11,8 @@ import { useForm } from "react-hook-form"; import * as yup from "yup"; import { KeyFormValuesType, UserKeyDetailedWithAccessesResponseDto, UserKeyInfoDtoTypeEnum, UserKeyWithAccessesResponseDto } from "../../../../@types/app"; import { PermissionWithOfferingsDetailsResponseDto, UserKeyResponseDto, UserKeyResponseDtoTypeEnum } from "../../../../@types/entrepot"; -import AppLayout from "../../../../components/Layout/AppLayout"; import LoadingText from "../../../../components/Utils/LoadingText"; import Wait from "../../../../components/Utils/Wait"; -import { datastoreNavItems } from "../../../../config/navItems/datastoreNavItems"; import { getTranslation, useTranslation } from "../../../../i18n/i18n"; import RQKeys from "../../../../modules/entrepot/RQKeys"; import { CartesApiException } from "../../../../modules/jsonFetch"; @@ -26,6 +24,7 @@ import SecurityOptionsForm from "./SecurityOptionsForm"; import ServicesForm from "./ServicesForm"; import { getSecurityOptionsSchema, getServicesSchema } from "./ValidationSchemas"; import { UserKeyDefaultValues, getDefaultValues } from "./utils/DefaultValues"; +import Main from "../../../../components/Layout/Main"; const { t } = getTranslation("UserKey"); @@ -58,7 +57,6 @@ const createRequestBody = (editMode: boolean, formValues: KeyFormValuesType) => }; const UserKeyForm: FC = ({ keyId }) => { - const navItems = datastoreNavItems(); const { t: tCommon } = useTranslation("Common"); /* Mode edition ? */ @@ -219,7 +217,7 @@ const UserKeyForm: FC = ({ keyId }) => { }); return ( - +

{t("title", { keyId: keyId })}

{(addKeyStatus === "pending" || updatekeyStatus === "pending") && ( @@ -268,7 +266,7 @@ const UserKeyForm: FC = ({ keyId }) => { /> )} - +
); }; diff --git a/assets/entrepot/pages/users/me/Me.tsx b/assets/entrepot/pages/users/me/Me.tsx index 02545c4e..efb5b476 100644 --- a/assets/entrepot/pages/users/me/Me.tsx +++ b/assets/entrepot/pages/users/me/Me.tsx @@ -1,25 +1,21 @@ import { fr } from "@codegouvfr/react-dsfr"; import Button from "@codegouvfr/react-dsfr/Button"; -import { useMemo } from "react"; -import AppLayout from "../../../../components/Layout/AppLayout"; -import { datastoreNavItems } from "../../../../config/navItems/datastoreNavItems"; import { getTranslation, useTranslation } from "../../../../i18n/i18n"; import SymfonyRouting from "../../../../modules/Routing"; import { useAuthStore } from "../../../../stores/AuthStore"; import { useSnackbarStore } from "../../../../stores/SnackbarStore"; import { formatDateFromISO } from "../../../../utils"; +import Main from "../../../../components/Layout/Main"; const Me = () => { const { t: tCommon } = getTranslation("Common"); const { t } = useTranslation({ Me }); const user = useAuthStore((state) => state.user); - const navItems = useMemo(() => datastoreNavItems(), []); - const setMessage = useSnackbarStore((state) => state.setMessage); return ( - +

{t("my_account")}

{user && ( @@ -55,7 +51,7 @@ const Me = () => { > {t("manage_my_account")} - +
); }; diff --git a/assets/i18n/Common.locale.tsx b/assets/i18n/Common.locale.tsx index ef18bfb9..5deb71da 100644 --- a/assets/i18n/Common.locale.tsx +++ b/assets/i18n/Common.locale.tsx @@ -25,6 +25,7 @@ const { i18n } = declareComponentKeys< | "published" | "not_published" | "information" + | "no_necessary_rights" | "mandatory_fields" | "none" | "new_window" @@ -60,6 +61,7 @@ export const commonFrTranslations: Translations<"fr">["Common"] = { published: "Publié", not_published: "Non publié", information: "Information", + no_necessary_rights: "Vous n'avez pas les droits nécessaires pour visualiser les membres de cet espace de travail.", mandatory_fields: "Sauf mention contraire “(optionnel)” dans le label, tous les champs sont obligatoires.", none: "Aucune", new_window: "ouvre une nouvelle fenêtre", @@ -94,6 +96,7 @@ export const commonEnTranslations: Translations<"en">["Common"] = { published: "Published", not_published: "Not published", information: "Information", + no_necessary_rights: "You do not have the necessary rights to view and modify the users of this community.", mandatory_fields: "All fields are mandatory unless label states “optional”", none: "None", new_window: "new window", diff --git a/assets/pages/About.tsx b/assets/pages/About.tsx index d4591d98..31a9d87a 100644 --- a/assets/pages/About.tsx +++ b/assets/pages/About.tsx @@ -1,11 +1,11 @@ import { fr } from "@codegouvfr/react-dsfr"; import { Card } from "@codegouvfr/react-dsfr/Card"; -import AppLayout from "../components/Layout/AppLayout"; +import Main from "../components/Layout/Main"; const About = () => { return ( - +

À propos

@@ -131,7 +131,7 @@ const About = () => { Mis à jour le 24/10/2023
- +
); }; diff --git a/assets/pages/Documentation.tsx b/assets/pages/Documentation.tsx index 2ea4ad14..dc1266b7 100644 --- a/assets/pages/Documentation.tsx +++ b/assets/pages/Documentation.tsx @@ -1,9 +1,9 @@ import { fr } from "@codegouvfr/react-dsfr"; -import AppLayout from "../components/Layout/AppLayout"; +import Main from "../components/Layout/Main"; const Documentation = () => { return ( - +

Documentation

@@ -43,7 +43,7 @@ const Documentation = () => {

- +
); }; diff --git a/assets/pages/Home.tsx b/assets/pages/Home.tsx index b3e78527..6144377f 100644 --- a/assets/pages/Home.tsx +++ b/assets/pages/Home.tsx @@ -6,7 +6,6 @@ import CallOut from "@codegouvfr/react-dsfr/CallOut"; import Tile from "@codegouvfr/react-dsfr/Tile"; import { useEffect } from "react"; -import AppLayout from "../components/Layout/AppLayout"; import SymfonyRouting from "../modules/Routing"; import { catalogueUrl, routes, useRoute } from "../router/router"; import { useAuthStore } from "../stores/AuthStore"; @@ -19,6 +18,7 @@ import locationFranceSvgUrl from "@codegouvfr/react-dsfr/dsfr/artwork/pictograms import mapSvgUrl from "@codegouvfr/react-dsfr/dsfr/artwork/pictograms/map/map.svg"; import systemSvgUrl from "@codegouvfr/react-dsfr/dsfr/artwork/pictograms/system/system.svg"; import homeImgUrl from "../img/home/home.png"; +import Main from "../components/Layout/Main"; const Home = () => { const { params } = useRoute(); @@ -34,22 +34,23 @@ const Home = () => { } }, [params, user]); - const infoBannerMsg = ( - <> - Devenez acteur de cartes.gouv.fr et co-construisez les fonctionnalités en participant à des ateliers thématiques.{" "} - - Inscrivez-vous - - - ); - return ( - +
+ Devenez acteur de cartes.gouv.fr et co-construisez les fonctionnalités en participant à des ateliers thématiques.{" "} + + Inscrivez-vous + + + } + title="Le service public des cartes et données du territoire" + > {params?.["authentication_failed"] === 1 && ( { - +
); }; diff --git a/assets/pages/Join.tsx b/assets/pages/Join.tsx index 913e03ef..e4b71e56 100644 --- a/assets/pages/Join.tsx +++ b/assets/pages/Join.tsx @@ -1,11 +1,11 @@ import { fr } from "@codegouvfr/react-dsfr"; -import AppLayout from "../components/Layout/AppLayout"; import { routes } from "../router/router"; +import Main from "../components/Layout/Main"; const Join = () => { return ( - +

Rejoignez la communauté des utilisateurs et contributeurs de la Géoplateforme et cartes.gouv.fr

@@ -43,7 +43,7 @@ const Join = () => { {"En savoir plus sur la gestion des données à caractère personnel"}.
- +
); }; diff --git a/assets/pages/LoginDisabled/LoginDisabled.tsx b/assets/pages/LoginDisabled/LoginDisabled.tsx index 8f3876aa..9602d830 100644 --- a/assets/pages/LoginDisabled/LoginDisabled.tsx +++ b/assets/pages/LoginDisabled/LoginDisabled.tsx @@ -2,15 +2,14 @@ import { fr } from "@codegouvfr/react-dsfr"; import Alert from "@codegouvfr/react-dsfr/Alert"; import Button from "@codegouvfr/react-dsfr/Button"; -import AppLayout from "../../components/Layout/AppLayout"; import { useTranslation } from "../../i18n/i18n"; import { routes } from "../../router/router"; +import Main from "../../components/Layout/Main"; const LoginDisabled = () => { const { t } = useTranslation("LoginDisabled"); - return ( - +

{t("title")}

@@ -18,7 +17,7 @@ const LoginDisabled = () => { - +
); }; diff --git a/assets/pages/Offer.tsx b/assets/pages/Offer.tsx index f9259fdf..9d84c63f 100644 --- a/assets/pages/Offer.tsx +++ b/assets/pages/Offer.tsx @@ -1,14 +1,14 @@ import { fr } from "@codegouvfr/react-dsfr"; import CallOut from "@codegouvfr/react-dsfr/CallOut"; -import AppLayout from "../components/Layout/AppLayout"; import { routes } from "../router/router"; +import Main from "../components/Layout/Main"; import "../sass/pages/offer.scss"; const Offer = () => { return ( - +

Offre

@@ -141,7 +141,7 @@ const Offer = () => {
- +
); }; diff --git a/assets/pages/RedirectToLogin.tsx b/assets/pages/RedirectToLogin.tsx index f30a5c1c..a1d2d129 100644 --- a/assets/pages/RedirectToLogin.tsx +++ b/assets/pages/RedirectToLogin.tsx @@ -2,6 +2,7 @@ import { useEffect } from "react"; import AppLayout from "../components/Layout/AppLayout"; import SymfonyRouting from "../modules/Routing"; +import Main from "../components/Layout/Main"; const RedirectToLogin = () => { useEffect(() => { @@ -9,8 +10,10 @@ const RedirectToLogin = () => { }, []); return ( - -

Redirection vers la page de connexion...

+ +
+

Redirection vers la page de connexion...

+
); }; diff --git a/assets/pages/assistance/Faq.tsx b/assets/pages/assistance/Faq.tsx index 49559105..34d91176 100644 --- a/assets/pages/assistance/Faq.tsx +++ b/assets/pages/assistance/Faq.tsx @@ -1,11 +1,11 @@ import { fr } from "@codegouvfr/react-dsfr"; import { Accordion } from "@codegouvfr/react-dsfr/Accordion"; -import AppLayout from "../../components/Layout/AppLayout"; +import Main from "../../components/Layout/Main"; const Faq = () => { return ( - +

Questions fréquentes

@@ -52,7 +52,7 @@ const Faq = () => {
- +
); }; diff --git a/assets/pages/assistance/ServiceStatus.tsx b/assets/pages/assistance/ServiceStatus.tsx index 0a4dbf78..bc504dca 100644 --- a/assets/pages/assistance/ServiceStatus.tsx +++ b/assets/pages/assistance/ServiceStatus.tsx @@ -1,14 +1,13 @@ import { fr } from "@codegouvfr/react-dsfr"; import { useState } from "react"; -import AppLayout from "../../components/Layout/AppLayout"; import LoadingIcon from "../../components/Utils/LoadingIcon"; +import Main from "../../components/Layout/Main"; const ServiceStatus = () => { const [loading, setLoading] = useState(true); - return ( - +

Niveau de service {loading === true && }

@@ -23,7 +22,7 @@ const ServiceStatus = () => {