From db99a1c265d4f13c498955f38463d025878a9ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dafydd=20Ll=C5=B7r=20Pearson?= Date: Tue, 17 Sep 2024 12:10:32 +0100 Subject: [PATCH] Revert "feat: Pesist `FlowEditor` state on route changes (#3671)" This reverts commit 12bf4182ca71750746166d72ce57360a38841e5d. --- .../src/components/EditorNavMenu.tsx | 41 ++---- .../src/components/RouteLoadingIndicator.tsx | 36 ------ editor.planx.uk/src/index.tsx | 11 +- .../Settings/DataManagerSettings.tsx | 25 ++++ .../components/Settings/ServiceFlags.tsx | 25 ++++ .../src/pages/FlowEditor/index.tsx | 5 +- editor.planx.uk/src/pages/Login.tsx | 5 - .../src/pages/layout/AuthenticatedLayout.tsx | 2 - .../src/pages/layout/FlowEditorLayout.tsx | 6 +- editor.planx.uk/src/routes/flow.tsx | 120 +++++++++++++++++- .../src/routes/serviceSettings.tsx | 65 ---------- editor.planx.uk/src/routes/submissionsLog.tsx | 23 ---- editor.planx.uk/src/routes/team.tsx | 15 +-- 13 files changed, 187 insertions(+), 192 deletions(-) delete mode 100644 editor.planx.uk/src/components/RouteLoadingIndicator.tsx create mode 100644 editor.planx.uk/src/pages/FlowEditor/components/Settings/DataManagerSettings.tsx create mode 100644 editor.planx.uk/src/pages/FlowEditor/components/Settings/ServiceFlags.tsx delete mode 100644 editor.planx.uk/src/routes/serviceSettings.tsx delete mode 100644 editor.planx.uk/src/routes/submissionsLog.tsx diff --git a/editor.planx.uk/src/components/EditorNavMenu.tsx b/editor.planx.uk/src/components/EditorNavMenu.tsx index a3af14ef2e..bb821e1895 100644 --- a/editor.planx.uk/src/components/EditorNavMenu.tsx +++ b/editor.planx.uk/src/components/EditorNavMenu.tsx @@ -13,8 +13,8 @@ import Tooltip, { tooltipClasses, TooltipProps } from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; import { Role } from "@opensystemslab/planx-core/types"; import { useStore } from "pages/FlowEditor/lib/store"; -import React, { useRef } from "react"; -import { useCurrentRoute, useLoadingRoute, useNavigation } from "react-navi"; +import React from "react"; +import { useCurrentRoute, useNavigation } from "react-navi"; import { FONT_WEIGHT_SEMI_BOLD } from "theme"; import EditorIcon from "ui/icons/Editor"; @@ -26,11 +26,6 @@ interface Route { disabled?: boolean; } -interface RoutesForURL { - routes: Route[]; - compact: boolean; -} - const MENU_WIDTH_COMPACT = "51px"; const MENU_WIDTH_FULL = "164px"; @@ -109,7 +104,6 @@ const MenuButton = styled(IconButton, { function EditorNavMenu() { const { navigate } = useNavigation(); const { url } = useCurrentRoute(); - const isRouteLoading = useLoadingRoute(); const [teamSlug, flowSlug, user, canUserEditTeam, flowAnalyticsLink] = useStore((state) => [ state.teamSlug, @@ -231,29 +225,14 @@ function EditorNavMenu() { ...flowAnalyticsRoute, ]; - const defaultRoutes: RoutesForURL = { - routes: globalLayoutRoutes, - compact: false, - }; - const previousRoutes = useRef(defaultRoutes); - - const getRoutesForUrl = (url: string): RoutesForURL => { - // Return the previous value when route is loading to avoid flash of incorrect version - if (isRouteLoading) return previousRoutes.current; - - let result: RoutesForURL; - - if (flowSlug && url.includes(flowSlug)) { - result = { routes: flowLayoutRoutes, compact: true }; - } else if (teamSlug && url.includes(teamSlug)) { - result = { routes: teamLayoutRoutes, compact: false }; - } else { - result = defaultRoutes; - } - - previousRoutes.current = result; - - return result; + const getRoutesForUrl = ( + url: string, + ): { routes: Route[]; compact: boolean } => { + if (flowSlug && url.includes(flowSlug)) + return { routes: flowLayoutRoutes, compact: true }; + if (teamSlug && url.includes(teamSlug)) + return { routes: teamLayoutRoutes, compact: false }; + return { routes: globalLayoutRoutes, compact: false }; }; const { routes, compact } = getRoutesForUrl(url.href); diff --git a/editor.planx.uk/src/components/RouteLoadingIndicator.tsx b/editor.planx.uk/src/components/RouteLoadingIndicator.tsx deleted file mode 100644 index 72c6852ce2..0000000000 --- a/editor.planx.uk/src/components/RouteLoadingIndicator.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import Box from "@mui/material/Box"; -import LinearProgress from "@mui/material/LinearProgress"; -import { styled } from "@mui/material/styles"; -import React, { useEffect, useState } from "react"; -import { useLoadingRoute } from "react-navi"; - -const Root = styled(Box)({ - width: "100%", - position: "fixed", - top: 0, - left: 0, -}); - -const RouteLoadingIndicator: React.FC<{ - msDelayBeforeVisible?: number; -}> = ({ msDelayBeforeVisible = 50 }) => { - const isLoading = useLoadingRoute(); - const [isVisible, setIsVisible] = useState(false); - - useEffect(() => { - if (!isLoading) return setIsVisible(false); - - const timer = setTimeout(() => setIsVisible(true), msDelayBeforeVisible); - return () => clearTimeout(timer); - }, [isLoading, msDelayBeforeVisible]); - - if (!isVisible) return null; - - return ( - - - - ); -}; - -export default RouteLoadingIndicator; \ No newline at end of file diff --git a/editor.planx.uk/src/index.tsx b/editor.planx.uk/src/index.tsx index 7c8687f3ff..b2c4b6b3ce 100644 --- a/editor.planx.uk/src/index.tsx +++ b/editor.planx.uk/src/index.tsx @@ -12,12 +12,13 @@ import ErrorPage from "pages/ErrorPage"; import { AnalyticsProvider } from "pages/FlowEditor/lib/analytics/provider"; import React, { Suspense, useEffect } from "react"; import { createRoot } from "react-dom/client"; -import { NotFoundBoundary, Router, View } from "react-navi"; +import { NotFoundBoundary, Router, useLoadingRoute, View } from "react-navi"; import HelmetProvider from "react-navi-helmet-async"; import { ToastContainer } from "react-toastify"; // init airbrake before everything else import * as airbrake from "./airbrake"; +import DelayedLoadingIndicator from "./components/DelayedLoadingIndicator"; import { client } from "./lib/graphql"; import navigation from "./lib/navigation"; import { defaultTheme } from "./theme"; @@ -54,6 +55,8 @@ const hasJWT = (): boolean | void => { const Layout: React.FC<{ children: React.ReactNode; }> = ({ children }) => { + const isLoading = useLoadingRoute(); + useEffect(() => { const observer = new MutationObserver(() => { // set the page title based on whatever heading is currently shown @@ -79,7 +82,11 @@ const Layout: React.FC<{ }> - {children} + {isLoading ? ( + + ) : ( + children + )} diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Settings/DataManagerSettings.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DataManagerSettings.tsx new file mode 100644 index 0000000000..c5899d05e2 --- /dev/null +++ b/editor.planx.uk/src/pages/FlowEditor/components/Settings/DataManagerSettings.tsx @@ -0,0 +1,25 @@ +import Container from "@mui/material/Container"; +import Typography from "@mui/material/Typography"; +import React from "react"; +import { FeaturePlaceholder } from "ui/editor/FeaturePlaceholder"; +import SettingsSection from "ui/editor/SettingsSection"; + +const DataManagerSettings: React.FC = () => { + return ( + + + + Data Manager + + + Manage the data that your service uses and makes available via its + API. + + + + + + + ); +}; +export default DataManagerSettings; diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Settings/ServiceFlags.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Settings/ServiceFlags.tsx new file mode 100644 index 0000000000..d8165924c1 --- /dev/null +++ b/editor.planx.uk/src/pages/FlowEditor/components/Settings/ServiceFlags.tsx @@ -0,0 +1,25 @@ +import Container from "@mui/material/Container"; +import Typography from "@mui/material/Typography"; +import React from "react"; +import { FeaturePlaceholder } from "ui/editor/FeaturePlaceholder"; +import SettingsSection from "ui/editor/SettingsSection"; + +const ServiceFlags: React.FC = () => { + return ( + + + + Service flags + + + Manage the flag sets that this service uses. Flags at the top of a set + override flags below. + + + + + + + ); +}; +export default ServiceFlags; diff --git a/editor.planx.uk/src/pages/FlowEditor/index.tsx b/editor.planx.uk/src/pages/FlowEditor/index.tsx index 4dd0e5a36c..cf55d4806b 100644 --- a/editor.planx.uk/src/pages/FlowEditor/index.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/index.tsx @@ -4,7 +4,6 @@ import Box from "@mui/material/Box"; import { styled } from "@mui/material/styles"; import { HEADER_HEIGHT_EDITOR } from "components/Header"; import React, { useRef } from "react"; -import { useCurrentRoute } from "react-navi"; import Flow from "./components/Flow"; import Sidebar from "./components/Sidebar"; @@ -19,9 +18,7 @@ const EditorContainer = styled(Box)(() => ({ maxHeight: `calc(100vh - ${HEADER_HEIGHT_EDITOR}px)`, })); -const FlowEditor = () => { - const [ flow, ...breadcrumbs ] = useCurrentRoute().url.pathname.split("/").at(-1)?.split(",") || []; - +const FlowEditor: React.FC = ({ flow, breadcrumbs }) => { const scrollContainerRef = useRef(null); useScrollControlsAndRememberPosition(scrollContainerRef); const showSidebar = useStore((state) => state.showSidebar); diff --git a/editor.planx.uk/src/pages/Login.tsx b/editor.planx.uk/src/pages/Login.tsx index dce5378a3c..d4fe9e22c7 100644 --- a/editor.planx.uk/src/pages/Login.tsx +++ b/editor.planx.uk/src/pages/Login.tsx @@ -5,9 +5,7 @@ import Button from "@mui/material/Button"; import Container from "@mui/material/Container"; import { styled } from "@mui/material/styles"; import Typography from "@mui/material/Typography"; -import DelayedLoadingIndicator from "components/DelayedLoadingIndicator"; import React from "react"; -import { useLoadingRoute } from "react-navi"; const Wrapper = styled(Box)(({ theme }) => ({ width: "100vw", @@ -48,9 +46,6 @@ const LoginButton = styled(Button)(({ theme }) => ({ })); const Login: React.FC = () => { - const isLoading = useLoadingRoute(); - if (isLoading) return ; - return ( diff --git a/editor.planx.uk/src/pages/layout/AuthenticatedLayout.tsx b/editor.planx.uk/src/pages/layout/AuthenticatedLayout.tsx index 6f93190696..437ddee99b 100644 --- a/editor.planx.uk/src/pages/layout/AuthenticatedLayout.tsx +++ b/editor.planx.uk/src/pages/layout/AuthenticatedLayout.tsx @@ -3,7 +3,6 @@ import { containerClasses } from "@mui/material/Container"; import { styled } from "@mui/material/styles"; import EditorNavMenu from "components/EditorNavMenu"; import { HEADER_HEIGHT_EDITOR } from "components/Header"; -import RouteLoadingIndicator from "components/RouteLoadingIndicator"; import React, { PropsWithChildren } from "react"; import { DndProvider } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; @@ -37,7 +36,6 @@ const DashboardContainer = styled(Box)(({ theme }) => ({ const Layout: React.FC = ({ children }) => ( <> -
diff --git a/editor.planx.uk/src/pages/layout/FlowEditorLayout.tsx b/editor.planx.uk/src/pages/layout/FlowEditorLayout.tsx index 327d8da975..bb66ae8e20 100644 --- a/editor.planx.uk/src/pages/layout/FlowEditorLayout.tsx +++ b/editor.planx.uk/src/pages/layout/FlowEditorLayout.tsx @@ -1,13 +1,9 @@ import ErrorFallback from "components/ErrorFallback"; -import FlowEditor from "pages/FlowEditor"; import React, { PropsWithChildren } from "react"; import { ErrorBoundary } from "react-error-boundary"; const FlowEditorLayout: React.FC = ({ children }) => ( - - - {children} - + {children} ); export default FlowEditorLayout; diff --git a/editor.planx.uk/src/routes/flow.tsx b/editor.planx.uk/src/routes/flow.tsx index bc089262cb..1bb284969a 100644 --- a/editor.planx.uk/src/routes/flow.tsx +++ b/editor.planx.uk/src/routes/flow.tsx @@ -1,25 +1,36 @@ import { gql } from "@apollo/client"; -import { ComponentType as TYPES } from "@opensystemslab/planx-core/types"; +import { + ComponentType as TYPES, + FlowStatus, +} from "@opensystemslab/planx-core/types"; import natsort from "natsort"; import { compose, + lazy, map, Matcher, mount, + NaviRequest, redirect, route, withData, withView, } from "navi"; +import DataManagerSettings from "pages/FlowEditor/components/Settings/DataManagerSettings"; +import ServiceFlags from "pages/FlowEditor/components/Settings/ServiceFlags"; +import ServiceSettings from "pages/FlowEditor/components/Settings/ServiceSettings"; +import Submissions from "pages/FlowEditor/components/Settings/Submissions"; import mapAccum from "ramda/src/mapAccum"; import React from "react"; +import { View } from "react-navi"; import { client } from "../lib/graphql"; +import FlowEditor from "../pages/FlowEditor"; import components from "../pages/FlowEditor/components/forms"; import FormModal from "../pages/FlowEditor/components/forms/FormModal"; import { SLUGS } from "../pages/FlowEditor/data/types"; import { useStore } from "../pages/FlowEditor/lib/store"; -import type { Flow } from "../types"; +import type { Flow, FlowSettings } from "../types"; import { makeTitle } from "./utils"; import { flowEditorView } from "./views/flowEditor"; @@ -168,6 +179,44 @@ const nodeRoutes = mount({ "/:parent/nodes/:id/edit": editNode, }); +const SettingsContainer = () => ; + +interface GetFlowSettings { + flows: { + id: string; + settings: FlowSettings; + status: FlowStatus; + }[]; +} + +export const getFlowSettings = async (req: NaviRequest) => { + const { + data: { + flows: [{ settings, status }], + }, + } = await client.query({ + query: gql` + query GetFlow($slug: String!, $team_slug: String!) { + flows( + limit: 1 + where: { slug: { _eq: $slug }, team: { slug: { _eq: $team_slug } } } + ) { + id + settings + status + } + } + `, + variables: { + slug: req.params.flow, + team_slug: req.params.team, + }, + }); + + useStore.getState().setFlowSettings(settings); + useStore.getState().setFlowStatus(status); +}; + const routes = compose( withData((req) => ({ flow: req.params.flow.split(",")[0], @@ -179,12 +228,73 @@ const routes = compose( "/": route(async (req) => { return { title: makeTitle([req.params.team, req.params.flow].join("/")), - // Default view of FlowEditor (single instance held in layout) - view: () => null, + view: () => { + const [flow, ...breadcrumbs] = req.params.flow.split(","); + return ( + + ); + }, }; }), - "/nodes": nodeRoutes, + "/feedback": lazy(() => import("./feedback")), + + "/nodes": compose( + withView((req) => { + const [flow, ...breadcrumbs] = req.params.flow.split(","); + return ( + <> + + + + ); + }), + nodeRoutes, + ), + + "/service": compose( + withView(SettingsContainer), + + route(async (req) => ({ + getData: await getFlowSettings(req), + title: makeTitle( + [req.params.team, req.params.flow, "service"].join("/"), + ), + view: ServiceSettings, + })), + ), + + "/service-flags": compose( + withView(SettingsContainer), + + route(async (req) => ({ + getData: await getFlowSettings(req), + title: makeTitle( + [req.params.team, req.params.flow, "service-flags"].join("/"), + ), + view: ServiceFlags, + })), + ), + + "/data": compose( + withView(SettingsContainer), + + route(async (req) => ({ + title: makeTitle([req.params.team, req.params.flow, "data"].join("/")), + view: DataManagerSettings, + })), + ), + + "/submissions-log": compose( + withView(SettingsContainer), + + route(async (req) => ({ + title: makeTitle( + [req.params.team, req.params.flow, "submissions-log"].join("/"), + ), + view: Submissions, + })), + ), }), ); diff --git a/editor.planx.uk/src/routes/serviceSettings.tsx b/editor.planx.uk/src/routes/serviceSettings.tsx deleted file mode 100644 index ca4a16e8b5..0000000000 --- a/editor.planx.uk/src/routes/serviceSettings.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { gql } from "@apollo/client"; -import { FlowStatus } from "@opensystemslab/planx-core/types"; -import { compose, mount, NaviRequest, route, withData } from "navi"; -import ServiceSettings from "pages/FlowEditor/components/Settings/ServiceSettings"; - -import { client } from "../lib/graphql"; -import { useStore } from "../pages/FlowEditor/lib/store"; -import type { FlowSettings } from "../types"; -import { makeTitle } from "./utils"; - -interface GetFlowSettings { - flows: { - id: string; - settings: FlowSettings; - status: FlowStatus; - }[]; -} - -export const getFlowSettings = async (req: NaviRequest) => { - const { - data: { - flows: [{ settings, status }], - }, - } = await client.query({ - query: gql` - query GetFlow($slug: String!, $team_slug: String!) { - flows( - limit: 1 - where: { slug: { _eq: $slug }, team: { slug: { _eq: $team_slug } } } - ) { - id - settings - status - } - } - `, - variables: { - slug: req.params.flow, - team_slug: req.params.team, - }, - }); - - useStore.getState().setFlowSettings(settings); - useStore.getState().setFlowStatus(status); -}; - -const serviceSettingsRoutes = compose( - withData((req) => ({ - mountpath: req.mountpath, - })), - - mount({ - "/": compose( - route(async (req) => ({ - getData: await getFlowSettings(req), - title: makeTitle( - [req.params.team, req.params.flow, "service"].join("/"), - ), - view: ServiceSettings, - })), - ), - }), -); - -export default serviceSettingsRoutes; diff --git a/editor.planx.uk/src/routes/submissionsLog.tsx b/editor.planx.uk/src/routes/submissionsLog.tsx deleted file mode 100644 index 8d9bd29516..0000000000 --- a/editor.planx.uk/src/routes/submissionsLog.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { compose, mount, route, withData } from "navi"; -import Submissions from "pages/FlowEditor/components/Settings/Submissions"; - -import { makeTitle } from "./utils"; - -const submissionsLogRoutes = compose( - withData((req) => ({ - mountpath: req.mountpath, - })), - - mount({ - "/": compose( - route(async (req) => ({ - title: makeTitle( - [req.params.team, req.params.flow, "submissions-log"].join("/"), - ), - view: Submissions, - })), - ), - }), -); - -export default submissionsLogRoutes; diff --git a/editor.planx.uk/src/routes/team.tsx b/editor.planx.uk/src/routes/team.tsx index 02e14e96b4..ad89c46704 100644 --- a/editor.planx.uk/src/routes/team.tsx +++ b/editor.planx.uk/src/routes/team.tsx @@ -1,5 +1,5 @@ import gql from "graphql-tag"; -import { compose, lazy, map, mount, route, withData, withView } from "navi"; +import { compose, lazy, mount, route, withData, withView } from "navi"; import DesignSettings from "pages/FlowEditor/components/Settings/DesignSettings"; import GeneralSettings from "pages/FlowEditor/components/Settings/GeneralSettings"; import React from "react"; @@ -15,13 +15,6 @@ let cached: { flowSlug?: string; teamSlug?: string } = { teamSlug: undefined, }; -const setFlowAndLazyLoad = (importComponent: Parameters[0]) => { - return map(async (request) => { - useStore.getState().setFlowSlug(request.params.flow); - return lazy(importComponent); - }); -}; - const routes = compose( withData((req) => ({ team: req.params.team, @@ -81,12 +74,6 @@ const routes = compose( return import("./flow"); }), - "/:flow/feedback": setFlowAndLazyLoad(() => import("./feedback")), - - "/:flow/service": setFlowAndLazyLoad(() => import("./serviceSettings")), - - "/:flow/submissions-log": setFlowAndLazyLoad(() => import("./submissionsLog")), - "/members": lazy(() => import("./teamMembers")), "/design": compose( route(async (req) => ({