cdslogviewer/frontend/app/index.jsx (199 lines of code) (raw):
import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Navigate, Routes, Route } from "react-router-dom";
import {
ThemeProvider,
createTheme,
CssBaseline,
IconButton,
} from "@material-ui/core";
import axios from "axios";
import MainWindow from "./MainWindow";
import {
AppSwitcher,
Header,
OAuthContextProvider,
SystemNotification,
UserContextProvider,
verifyExistingLogin,
handleUnauthorized,
} from "@guardian/pluto-headers";
import { Brightness4, Brightness7 } from "@material-ui/icons";
import createCustomisedTheme from "./theming";
import LogByJobName from "./LogByJobName";
const darkTheme = createCustomisedTheme({
typography: {
fontFamily: [
"sans-serif",
'"Helvetica Neue"',
"Helvetica",
"Arial",
"sans-serif",
].join(","),
fontWeight: 400,
},
palette: {
type: "dark",
logviewer: {
main: "#00a000",
background: "#000000e0",
},
},
});
const lightTheme = createCustomisedTheme({
typography: {
fontFamily: [
"sans-serif",
'"Helvetica Neue"',
"Helvetica",
"Arial",
"sans-serif",
].join(","),
fontWeight: 400,
},
palette: {
type: "light",
logviewer: {
main: "#008000",
background: "#00000020",
},
},
});
axios.interceptors.request.use(function (config) {
const token = window.localStorage.getItem("pluto:access-token");
if (token) config.headers.Authorization = `Bearer ${token}`;
// this is set in the index.scala.html template file and gives us the value of deployment-root from the server config
// Only apply deployment root when url begins with /api
if (config.url.startsWith("/api")) {
config.baseURL = deploymentRootPath;
}
return config;
});
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isDark: true,
loading: true,
isLoggedIn: false,
tokenExpired: false,
plutoConfig: {},
userProfile: undefined,
};
this.handleUnauthorizedFailed = this.handleUnauthorizedFailed.bind(this);
this.onLoginValid = this.onLoginValid.bind(this);
this.oAuthConfigLoaded = this.oAuthConfigLoaded.bind(this);
axios.interceptors.response.use(
(response) => response,
async (error) => {
handleUnauthorized(
this.state.plutoConfig,
error,
this.handleUnauthorizedFailed
);
return Promise.reject(error);
}
);
}
handleUnauthorizedFailed() {
this.setState({
isLoggedIn: false,
tokenExpired: true,
});
}
async onLoginValid(valid, loginData) {
// Fetch the OAuth config.
try {
const response = await fetch("/meta/oauth/config.json");
if (response.status === 200) {
const data = await response.json();
this.setState({ plutoConfig: data });
}
} catch (error) {
console.error(error);
}
this.setState(
{
isLoggedIn: valid,
},
() => {
this.setState({ loading: false });
}
);
}
haveToken() {
return window.localStorage.getItem("pluto:access-token");
}
oAuthConfigLoaded(oAuthConfig) {
//If we already have a user token at mount, verify it and update our internal state.
//If we do not, ignore for the time being; it will be set dynamically when the login occurs.
console.log("Loaded oAuthConfig: ", oAuthConfig);
if (this.haveToken()) {
verifyExistingLogin(oAuthConfig)
.then((profile) => this.setState({ userProfile: profile }))
.catch((err) => {
console.error("Could not verify existing user profile: ", err);
});
}
}
render() {
return (
<OAuthContextProvider onLoaded={this.oAuthConfigLoaded}>
<UserContextProvider
value={{
profile: this.state.userProfile,
updateProfile: (newValue) =>
this.setState({ userProfile: newValue }),
}}
>
<ThemeProvider theme={this.state.isDark ? darkTheme : lightTheme}>
<CssBaseline />
<Header></Header>
<AppSwitcher onLoginValid={this.onLoginValid}></AppSwitcher>
<div className="app">
<div
style={{
float: "right",
height: 0,
marginRight: "1em",
marginTop: "1em",
marginBottom: "-1em",
}}
>
<IconButton
onClick={() =>
this.setState((prev) => ({ isDark: !prev.isDark }))
}
>
{this.state.isDark ? <Brightness7 /> : <Brightness4 />}
</IconButton>
</div>
<Routes>
<Route
path="/log/:routename/:podname"
element={<MainWindow />}
/>
<Route path="/log/:routename" element={<MainWindow />} />
<Route
path="/logByJobName/:jobname"
element={<LogByJobName />}
/>
<Route path="/log" element={<MainWindow />} />
<Route path="/" element={<Navigate to="/log" replace />} />
</Routes>
<SystemNotification />
</div>
</ThemeProvider>
</UserContextProvider>
</OAuthContextProvider>
);
}
}
document.addEventListener("DOMContentLoaded", () => {
render(
<BrowserRouter basename={deploymentRootPath}>
<App />
</BrowserRouter>,
document.getElementById("app")
);
});