diff --git a/compendium-frontend/src/App.tsx b/compendium-frontend/src/App.tsx index 28b3398e25b3b92f841e58e94543e36af74dd7e7..a0e07e28fbb649c180a08c88f851bfc92fcc3239 100644 --- a/compendium-frontend/src/App.tsx +++ b/compendium-frontend/src/App.tsx @@ -1,4 +1,4 @@ -import { ReactElement } from "react"; +import { ReactElement, useEffect } from "react"; import { createBrowserRouter, RouterProvider, Outlet, useLocation } from "react-router-dom"; import Providers from "./Providers"; import { ConnectivityPage, ServiceCategory } from "./Schema"; @@ -67,12 +67,6 @@ import NetworkWeatherMapPage from "./pages/Network/WeatherMap"; // Services Matrix import ServicesPage from "./pages/Services/Services"; -// Survey pages -import SurveyLanding from "./survey/Landing"; -import SurveyContainerComponent from "./survey/SurveyContainerComponent"; -import SurveyManagementComponent from "./survey/management/SurveyManagementComponent"; -import UserManagementComponent from "./survey/management/UserManagementComponent"; - const GlobalLayout = () => { // this component is needed to provide a global layout for the app, including the navbar and footer, // and make them part of the react-router-dom context @@ -93,6 +87,21 @@ const GlobalLayout = () => { ) } +const RedirectToSurvey = () => { + const { pathname } = useLocation(); + + useEffect(() => { + // Only redirect if we're not already on a survey path + if (!pathname.startsWith('/survey')) { + window.location.replace(`/survey${pathname}`); + } else { + window.location.replace(pathname); + } + }, [pathname]); + + return <Landing /> +} + const router = createBrowserRouter([ { "path": "", @@ -161,18 +170,12 @@ const router = createBrowserRouter([ { path: "/service-management-framework", element: <ServiceManagementFrameworkPage /> }, { path: "/service-level-targets", element: <ServiceLevelTargetsPage /> }, { path: "/corporate-strategy", element: <CorporateStrategyPage /> }, - { path: "survey/admin/surveys", element: <SurveyManagementComponent /> }, - { path: "survey/admin/users", element: <UserManagementComponent /> }, - { path: "survey/admin/inspect/:year", element: <SurveyContainerComponent loadFrom={"/api/response/inspect/"} /> }, - { path: "survey/admin/try/:year", element: <SurveyContainerComponent loadFrom={"/api/response/try/"} /> }, - { path: "survey/response/:year/:nren", element: <SurveyContainerComponent loadFrom={"/api/response/load/"} /> }, - { path: "survey/*", element: <SurveyLanding /> }, + { path: "/survey/*", element: <RedirectToSurvey /> }, { path: "*", element: <Landing /> }, ] } ]); - function App(): ReactElement { return ( <div className="app"> diff --git a/compendium-frontend/src/components/DataPage.tsx b/compendium-frontend/src/components/DataPage.tsx index 747a851471f9985550dd949714b76b665f4c02a2..68e9ec376130ee58549f392fa72988e14ffddcd4 100644 --- a/compendium-frontend/src/components/DataPage.tsx +++ b/compendium-frontend/src/components/DataPage.tsx @@ -9,7 +9,6 @@ import { Sections } from "../helpers/constants"; import PolicySidebar from "./sidebar/PolicySidebar"; import { Chart as ChartJS } from 'chart.js'; -import { usePreview } from "../helpers/usePreview"; import NetworkSidebar from "./sidebar/NetworkSidebar"; import ConnectedUsersSidebar from "./sidebar/ConnectedUsersSidebar"; import ServicesSidebar from "./sidebar/ServicesSidebar"; @@ -34,8 +33,7 @@ interface inputProps { } function DataPage({ title, description, filter, children, category, data, filename }: inputProps): ReactElement { - const { setPreview } = useContext(PreviewContext); - const preview = usePreview(); + const { preview, setPreview } = useContext(PreviewContext); const locationWithoutPreview = window.location.origin + window.location.pathname; const { trackPageView } = useMatomo() diff --git a/compendium-frontend/src/index.tsx b/compendium-frontend/src/index.tsx index 02df09a3eebf4b6fb1ab5f9a57712a952afe882f..8cca5a6c1ff3f6991063cc9ecef40afef8681c01 100644 --- a/compendium-frontend/src/index.tsx +++ b/compendium-frontend/src/index.tsx @@ -1,4 +1,3 @@ - import React from 'react'; import { createRoot } from 'react-dom/client'; import App from "./App"; diff --git a/compendium-frontend/src/survey/App.tsx b/compendium-frontend/src/survey/App.tsx new file mode 100644 index 0000000000000000000000000000000000000000..488ce6f53d6286443b53a09d3c3201bd5de896d5 --- /dev/null +++ b/compendium-frontend/src/survey/App.tsx @@ -0,0 +1,71 @@ +import { useEffect } from "react"; +import { createBrowserRouter, RouterProvider, Outlet, useLocation } from "react-router-dom"; +import Providers from "../Providers"; +import ExternalPageNavBar from "../components/global/ExternalPageNavBar"; +import GeantFooter from "../components/global/GeantFooter"; +import PrivacyModal from "../matomo/PrivacyModal"; + +import SurveyLanding from "./Landing"; +import SurveyContainerComponent from "./SurveyContainerComponent"; +import SurveyManagementComponent from "./management/SurveyManagementComponent"; +import UserManagementComponent from "./management/UserManagementComponent"; + +const RedirectToReport = ({ pathname }) => { + + useEffect(() => { + console.log(pathname) + // Only redirect if we're not already on a survey path + if (!pathname.startsWith('/survey')) { + window.location.replace(`${pathname}`); + } + }, [pathname]); + + return null; +} + +const GlobalLayout = () => { + // this component is needed to provide a global layout for the app, including the navbar and footer, + // and make them part of the react-router-dom context + const { pathname } = useLocation(); + // hacky workaround for supporting a landing page on the root path, as well as any undefined path + const hasOutlet = pathname !== "/survey" + return ( + <> + <Providers> + <RedirectToReport pathname={pathname} /> + <ExternalPageNavBar /> + <main className="grow"> + {hasOutlet ? <Outlet /> : <SurveyLanding />} + </main> + <PrivacyModal /> + </Providers> + <GeantFooter /> + </> + ) +} + +const router = createBrowserRouter([ + { + "path": "", + "element": <GlobalLayout />, + "children": [ + { path: "/survey/admin/surveys", element: <SurveyManagementComponent /> }, + { path: "/survey/admin/users", element: <UserManagementComponent /> }, + { path: "/survey/admin/inspect/:year", element: <SurveyContainerComponent loadFrom={"/api/response/inspect/"} /> }, + { path: "/survey/admin/try/:year", element: <SurveyContainerComponent loadFrom={"/api/response/try/"} /> }, + { path: "/survey/response/:year/:nren", element: <SurveyContainerComponent loadFrom={"/api/response/load/"} /> }, + { path: "*", element: <SurveyLanding /> }, + ] + } +]) + +function App() { + return ( + <div className="app"> + <RouterProvider router={router} /> + </div> + ); +} + +export default App + diff --git a/compendium-frontend/src/survey/index.tsx b/compendium-frontend/src/survey/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5aa6d5bf91bd75c00a572688559bd14ad634f182 --- /dev/null +++ b/compendium-frontend/src/survey/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from "./App"; +import 'bootstrap/dist/css/bootstrap.min.css'; +import '../main.scss'; + +const container = document.getElementById('root') as HTMLElement; +const root = createRoot(container); +root.render( + <React.StrictMode> + <App /> + </React.StrictMode> +) \ No newline at end of file diff --git a/compendium-frontend/survey.html b/compendium-frontend/survey.html new file mode 100644 index 0000000000000000000000000000000000000000..0b50b4accf9ace201254975fb22a96dfa30010bb --- /dev/null +++ b/compendium-frontend/survey.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"/> + <title>Compendium Survey</title> +</head> +<body> + <div id="root"></div> + <script type="module" src="./src/survey/index.tsx"></script> +</body> +</html> \ No newline at end of file diff --git a/compendium-frontend/vite.config.ts b/compendium-frontend/vite.config.ts index 78d3fc45d9bfce17c0c482f014c34d62707030e7..c787da94e1bd2f23c9bdbf6668869d7ae82a7f4f 100644 --- a/compendium-frontend/vite.config.ts +++ b/compendium-frontend/vite.config.ts @@ -3,7 +3,7 @@ import react from '@vitejs/plugin-react' import license from 'rollup-plugin-license' import path from 'path' -const ReactCompilerConfig = { +const ReactCompilerConfig = { target: "19" }; const outDir = path.resolve(__dirname, '..', 'compendium_v2', 'static'); @@ -22,7 +22,7 @@ export default defineConfig({ } }), license({ thirdParty: { - output: path.join(outDir, 'bundle.js.LICENSE.txt') + output: path.resolve(__dirname, 'third-party-licenses.txt'), } })], base: isProduction ? '/static/' : '/', @@ -53,22 +53,21 @@ export default defineConfig({ outDir: outDir, sourcemap: process.env.NODE_ENV !== 'production', rollupOptions: { + input: { + report: path.resolve(__dirname, 'index.html'), + survey: path.resolve(__dirname, 'survey.html'), + }, output: { - entryFileNames: "bundle.js", + entryFileNames: '[name].js', assetFileNames: function (assetInfo) { const names = assetInfo.names; if (names.some(name => name.endsWith('.css'))) { - // put all css into a single file - return 'bundle.css'; + return '[name].[ext]'; } return '[hash].[ext]'; }, - //split surveyjs and chartjs into separate chunks, they are large and not always needed - manualChunks: { - survey: ['survey-react-ui', 'survey-core'], - report: ['chart.js', 'chartjs-plugin-datalabels', 'cartesian-product-multiple-arrays'], - }, + manualChunks: undefined, chunkFileNames: '[name]-[hash].js', }, }, diff --git a/compendium_v2/routes/default.py b/compendium_v2/routes/default.py index 42ee4b082384e7e941c790a87a24270eb4af68b4..da63095b365c53ed5eb853757d938ab9c8f8c07b 100644 --- a/compendium_v2/routes/default.py +++ b/compendium_v2/routes/default.py @@ -67,7 +67,7 @@ def survey_index(path): # fallback to serving the SPA through index.html for all other requests # https://flask.palletsprojects.com/en/2.0.x/patterns/singlepageapplications/ - return current_app.send_static_file("index.html") + return current_app.send_static_file("survey.html") @routes.route('/version', methods=['GET', 'POST'])