mirror of
https://github.com/empayre/fleet.git
synced 2024-11-07 01:15:22 +00:00
164 lines
4.3 KiB
TypeScript
164 lines
4.3 KiB
TypeScript
import React, { useContext, useEffect, useState } from "react";
|
|
import { AxiosResponse } from "axios";
|
|
import { QueryClient, QueryClientProvider } from "react-query";
|
|
import classnames from "classnames";
|
|
|
|
import TableProvider from "context/table";
|
|
import QueryProvider from "context/query";
|
|
import PolicyProvider from "context/policy";
|
|
import NotificationProvider from "context/notification";
|
|
import { AppContext } from "context/app";
|
|
import local, { authToken } from "utilities/local";
|
|
import useDeepEffect from "hooks/useDeepEffect";
|
|
|
|
import usersAPI from "services/entities/users";
|
|
import configAPI from "services/entities/config";
|
|
|
|
import { ErrorBoundary } from "react-error-boundary";
|
|
// @ts-ignore
|
|
import Fleet403 from "pages/errors/Fleet403";
|
|
// @ts-ignore
|
|
import Fleet404 from "pages/errors/Fleet404";
|
|
// @ts-ignore
|
|
import Fleet500 from "pages/errors/Fleet500";
|
|
import Spinner from "components/Spinner";
|
|
|
|
interface IAppProps {
|
|
children: JSX.Element;
|
|
location:
|
|
| {
|
|
pathname: string;
|
|
}
|
|
| undefined;
|
|
}
|
|
|
|
const baseClass = "app";
|
|
|
|
const App = ({ children, location }: IAppProps): JSX.Element => {
|
|
const queryClient = new QueryClient();
|
|
const {
|
|
currentUser,
|
|
isGlobalObserver,
|
|
isOnlyObserver,
|
|
isAnyTeamMaintainerOrTeamAdmin,
|
|
setAvailableTeams,
|
|
setCurrentUser,
|
|
setConfig,
|
|
setEnrollSecret,
|
|
setSandboxExpiry,
|
|
} = useContext(AppContext);
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const fetchConfig = async () => {
|
|
try {
|
|
const config = await configAPI.loadAll();
|
|
if (config.sandbox_enabled) {
|
|
const timestamp = await configAPI.loadSandboxExpiry();
|
|
setSandboxExpiry(timestamp as string);
|
|
}
|
|
setConfig(config);
|
|
} catch (error) {
|
|
console.error(error);
|
|
return false;
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
const fetchCurrentUser = async () => {
|
|
try {
|
|
const { user, available_teams } = await usersAPI.me();
|
|
setCurrentUser(user);
|
|
setAvailableTeams(available_teams);
|
|
fetchConfig();
|
|
} catch (error) {
|
|
if (!location?.pathname.includes("/login/reset")) {
|
|
console.log(error);
|
|
local.removeItem("auth_token");
|
|
|
|
// if this is not the device user page,
|
|
// redirect to login
|
|
if (!location?.pathname.includes("/device/")) {
|
|
window.location.href = "/login";
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (authToken() && !location?.pathname.includes("/device/")) {
|
|
fetchCurrentUser();
|
|
}
|
|
}, [location?.pathname]);
|
|
|
|
useDeepEffect(() => {
|
|
const canGetEnrollSecret =
|
|
currentUser &&
|
|
typeof isGlobalObserver !== "undefined" &&
|
|
!isGlobalObserver &&
|
|
typeof isOnlyObserver !== "undefined" &&
|
|
!isOnlyObserver &&
|
|
typeof isAnyTeamMaintainerOrTeamAdmin !== "undefined" &&
|
|
!isAnyTeamMaintainerOrTeamAdmin &&
|
|
!location?.pathname.includes("/device/");
|
|
|
|
const getEnrollSecret = async () => {
|
|
try {
|
|
const { spec } = await configAPI.loadEnrollSecret();
|
|
setEnrollSecret(spec.secrets);
|
|
} catch (error) {
|
|
console.error(error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
if (canGetEnrollSecret) {
|
|
getEnrollSecret();
|
|
}
|
|
}, [currentUser, isGlobalObserver, isOnlyObserver]);
|
|
|
|
// "any" is used on purpose. We are using Axios but this
|
|
// function expects a native React Error type, which is incompatible.
|
|
const renderErrorOverlay = ({ error }: any) => {
|
|
// @ts-ignore
|
|
console.error(error);
|
|
|
|
const overlayError = error as AxiosResponse;
|
|
if (overlayError.status === 403 || overlayError.status === 402) {
|
|
return <Fleet403 />;
|
|
}
|
|
|
|
if (overlayError.status === 404) {
|
|
return <Fleet404 />;
|
|
}
|
|
|
|
return <Fleet500 />;
|
|
};
|
|
|
|
return isLoading ? (
|
|
<Spinner />
|
|
) : (
|
|
<QueryClientProvider client={queryClient}>
|
|
<TableProvider>
|
|
<QueryProvider>
|
|
<PolicyProvider>
|
|
<NotificationProvider>
|
|
<ErrorBoundary
|
|
fallbackRender={renderErrorOverlay}
|
|
resetKeys={[location?.pathname]}
|
|
>
|
|
<div className={baseClass}>{children}</div>
|
|
</ErrorBoundary>
|
|
</NotificationProvider>
|
|
</PolicyProvider>
|
|
</QueryProvider>
|
|
</TableProvider>
|
|
</QueryClientProvider>
|
|
);
|
|
};
|
|
|
|
export default App;
|