123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- /*
- * Copyright 2021-2025 Avaiga Private Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
- import React, { useEffect, useReducer, useState } from "react";
- import axios from "axios";
- import Box from "@mui/material/Box";
- import CircularProgress from "@mui/material/CircularProgress";
- import CssBaseline from "@mui/material/CssBaseline";
- import { ThemeProvider } from "@mui/system";
- import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
- import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFnsV3";
- import { SnackbarProvider } from "notistack";
- import { HelmetProvider } from "react-helmet-async";
- import { BrowserRouter, Route, Routes } from "react-router";
- import { ErrorBoundary } from "react-error-boundary";
- import { DndProvider } from "react-dnd";
- import { HTML5Backend } from "react-dnd-html5-backend";
- import { PageContext, TaipyContext } from "../context/taipyContext";
- import {
- createBlockAction,
- createSetLocationsAction,
- initializeWebSocket,
- INITIAL_STATE,
- retrieveBlockUi,
- taipyInitialize,
- taipyReducer,
- } from "../context/taipyReducers";
- import UIBlocker from "./Taipy/UIBlocker";
- import Navigate from "./Taipy/Navigate";
- import Menu from "./Taipy/Menu";
- import TaipyNotification from "./Taipy/Notification";
- import GuiDownload from "./Taipy/GuiDownload";
- import ErrorFallback from "../utils/ErrorBoundary";
- import MainPage from "./pages/MainPage";
- import TaipyRendered from "./pages/TaipyRendered";
- import NotFound404 from "./pages/NotFound404";
- import { getBaseURL } from "../utils";
- import { useLocalStorageWithEvent } from "../hooks";
- interface AxiosRouter {
- router: string;
- locations: Record<string, string>;
- blockUI: boolean;
- }
- const mainSx = { flexGrow: 1, bgcolor: "background.default" };
- const containerSx = { display: "flex" };
- const progressSx = { position: "fixed", bottom: "1em", right: "1em" };
- const pageStore = {};
- const Router = () => {
- const [state, dispatch] = useReducer(taipyReducer, INITIAL_STATE, taipyInitialize);
- const [routes, setRoutes] = useState<Record<string, string>>({});
- const refresh = !!Object.keys(routes).length;
- const themeClass = "taipy-" + state.theme.palette.mode;
- const baseURL = getBaseURL();
- useLocalStorageWithEvent(dispatch, state.id);
- useEffect(() => {
- if (refresh) {
- // no need to access the backend again, the routes are static
- return;
- }
- if (!state.isSocketConnected) {
- // initialize only when there is an existing ws connection
- // --> assuring that there is a session data scope on the backend
- return;
- }
- // Fetch Flask Rendered JSX React Router
- axios
- .get<AxiosRouter>("taipy-init", { params: { client_id: state.id || "", v: window.taipyVersion } })
- .then((result) => {
- dispatch(createSetLocationsAction(result.data.locations));
- setRoutes(result.data.locations);
- result.data.blockUI && dispatch(createBlockAction(retrieveBlockUi()));
- })
- .catch((error) => {
- // Fallback router if there is any error
- setRoutes({ "/": "/TaiPy_root_page" });
- console.log(error);
- });
- }, [refresh, state.isSocketConnected, state.id]);
- useEffect(() => {
- initializeWebSocket(state.socket, dispatch);
- }, [state.socket]);
- useEffect(() => {
- const classes = [themeClass];
- document.body.classList.forEach((cls) => {
- if (!cls.startsWith("taipy-")) {
- classes.push(cls);
- }
- });
- document.body.className = classes.join(" ");
- }, [themeClass]);
- return (
- <TaipyContext.Provider value={{ state, dispatch }}>
- <HelmetProvider>
- <ThemeProvider theme={state.theme}>
- <SnackbarProvider maxSnack={5}>
- <LocalizationProvider dateAdapter={AdapterDateFns}>
- <DndProvider backend={HTML5Backend}>
- <PageContext.Provider value={pageStore}>
- <BrowserRouter>
- <Box style={containerSx}>
- <CssBaseline />
- <ErrorBoundary FallbackComponent={ErrorFallback}>
- <Menu {...state.menu} />
- </ErrorBoundary>
- <Box component="main" sx={mainSx}>
- <ErrorBoundary FallbackComponent={ErrorFallback}>
- {Object.keys(routes).length ? (
- <Routes>
- <Route
- path={baseURL}
- element={
- <MainPage
- path={routes["/"]}
- route={Object.keys(routes).find(
- (path) => path !== "/"
- )}
- />
- }
- >
- {Object.entries(routes)
- .filter(([path]) => path !== "/")
- .map(([path, name]) => (
- <Route
- key={name}
- path={path.substring(1)}
- element={<TaipyRendered />}
- />
- ))}
- <Route
- path="*"
- key="NotFound"
- element={<NotFound404 />}
- />
- </Route>
- </Routes>
- ) : null}
- </ErrorBoundary>
- </Box>
- {state.ackList.length ? (
- <Box sx={progressSx} className="taipy-busy">
- <CircularProgress size="1em" disableShrink />
- </Box>
- ) : null}
- </Box>
- <ErrorBoundary FallbackComponent={ErrorFallback}>
- <TaipyNotification notifications={state.notifications} />
- <UIBlocker block={state.block} />
- <Navigate
- to={state.navigateTo}
- params={state.navigateParams}
- tab={state.navigateTab}
- force={state.navigateForce}
- />
- <GuiDownload download={state.download} />
- </ErrorBoundary>
- </BrowserRouter>
- </PageContext.Provider>
- </DndProvider>
- </LocalizationProvider>
- </SnackbarProvider>
- </ThemeProvider>
- </HelmetProvider>
- </TaipyContext.Provider>
- );
- };
- export default Router;
|