Files
redash/client/app/components/ApplicationArea/routeWithUserSession.jsx
Levko Kravets 0ac24e38a1 Vertical navbar (#4859)
* Vertical navbar

* Update vertical menu look and add create menu.

* Make query editor work with vertical nav.

* Dark mode

* Fix create menu & make sidebar fixed.

* Update Alert pages layout

* Update System status pages

* Update Queries and Dashboards list pages

* Update Query Source and Query View pages

* Use dark theme for mobile navbar

* Update Dashboard page: fix Add widget/textbox panel positioning

* Dashboard page: fix layout issues when container changes its size (fixes known issues: navbar expand/collapse, scrollbar appears/hides)

* Fix dashboard page sticky header (there was a 15px space above it)

* Fix embeds

* Extract desktop navbar component; move mobile navbar and its styles to ApplicationLayout folder

* Remove old app header

* Fix tests

* Restore version info block

* Make Percy capture entire page

* Make vertical navbar expand/collapse animation smoother (as it's currently impossible to disable it :-( )

* Fix misc UI issues (show Create label on expanded menu; fix some CSS; don't select items on click)

* Allow to override navbars with DynamicComponent

* Fix misc UI issues: expand/collapse button animation, menu items styles, menu expand/collapse animation

* Hide submenu arrow; show username when menu is expanded

* Refine CSS and make it more isolated; adjust colors

* Update tests

Co-authored-by: Arik Fraimovich <arik@arikfr.com>
2020-06-15 10:01:49 +03:00

82 lines
2.4 KiB
JavaScript

import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import ErrorBoundary, { ErrorBoundaryContext } from "@redash/viz/lib/components/ErrorBoundary";
import { Auth } from "@/services/auth";
import organizationStatus from "@/services/organizationStatus";
import ApplicationLayout from "./ApplicationLayout";
import ErrorMessage from "./ErrorMessage";
// This wrapper modifies `route.render` function and instead of passing `currentRoute` passes an object
// that contains:
// - `currentRoute.routeParams`
// - `pageTitle` field which is equal to `currentRoute.title`
// - `onError` field which is a `handleError` method of nearest error boundary
function UserSessionWrapper({ bodyClass, currentRoute, renderChildren }) {
const [isAuthenticated, setIsAuthenticated] = useState(!!Auth.isAuthenticated());
useEffect(() => {
let isCancelled = false;
Promise.all([Auth.requireSession(), organizationStatus.refresh()])
.then(() => {
if (!isCancelled) {
setIsAuthenticated(!!Auth.isAuthenticated());
}
})
.catch(() => {
if (!isCancelled) {
setIsAuthenticated(false);
}
});
return () => {
isCancelled = true;
};
}, []);
useEffect(() => {
if (bodyClass) {
document.body.classList.toggle(bodyClass, true);
return () => {
document.body.classList.toggle(bodyClass, false);
};
}
}, [bodyClass]);
if (!isAuthenticated) {
return null;
}
return (
<ApplicationLayout>
<React.Fragment key={currentRoute.key}>
<ErrorBoundary renderError={error => <ErrorMessage error={error} />}>
<ErrorBoundaryContext.Consumer>
{({ handleError }) =>
renderChildren({ ...currentRoute.routeParams, pageTitle: currentRoute.title, onError: handleError })
}
</ErrorBoundaryContext.Consumer>
</ErrorBoundary>
</React.Fragment>
</ApplicationLayout>
);
}
UserSessionWrapper.propTypes = {
bodyClass: PropTypes.string,
renderChildren: PropTypes.func,
};
UserSessionWrapper.defaultProps = {
bodyClass: null,
renderChildren: () => null,
};
export default function routeWithUserSession({ render, bodyClass, ...rest }) {
return {
...rest,
render: currentRoute => (
<UserSessionWrapper bodyClass={bodyClass} currentRoute={currentRoute} renderChildren={render} />
),
};
}