Skip to content

Commit

Permalink
Merge pull request #4276 from beyondessential/release-2022-49
Browse files Browse the repository at this point in the history
Release 2022-49
  • Loading branch information
avaek authored Dec 5, 2022
2 parents 3e693f0 + 119cc26 commit 823e586
Show file tree
Hide file tree
Showing 58 changed files with 1,518 additions and 298 deletions.
9 changes: 6 additions & 3 deletions packages/admin-panel/src/VizBuilderApp/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Main } from './views/Main';
import { CreateNew } from './views/CreateNew';
import { useUser } from './api/queries';
import { VizConfigProvider as StateProvider } from './context';
import { useVizBuilderBasePath } from './utils';

const Container = styled.main`
display: flex;
Expand All @@ -22,12 +23,14 @@ const Container = styled.main`
export const App = ({ Navbar, Footer }) => {
const { data, isLoading: isUserLoading, isBESAdmin } = useUser();

const basePath = useVizBuilderBasePath();

if (isUserLoading) {
return <FullPageLoader />;
}

if (!isBESAdmin) {
return <Redirect to="/" />;
return <Redirect to={basePath} />;
}

const user = { ...data, name: `${data.firstName} ${data.lastName}` };
Expand All @@ -37,10 +40,10 @@ export const App = ({ Navbar, Footer }) => {
<Container>
{Navbar && <Navbar user={user} isBESAdmin={isBESAdmin} />}
<Switch>
<Route path="/viz-builder/:vizType/new" exact>
<Route path={`${basePath}/viz-builder/:vizType/new`} exact>
<CreateNew />
</Route>
<Route path="/viz-builder/:vizType/:visualisationId?">
<Route path={`${basePath}/viz-builder/:vizType/:visualisationId?`}>
<Main />
</Route>
</Switch>
Expand Down
2 changes: 1 addition & 1 deletion packages/admin-panel/src/VizBuilderApp/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import axios from 'axios';
import { saveAs } from 'file-saver';
import FetchError from './fetchError';

const baseUrl = process.env.REACT_APP_API_URL;
const baseUrl = process.env.REACT_APP_VIZ_BUILDER_API_URL;
const timeout = 45 * 1000; // 45 seconds

// withCredentials needs to be set for cookies to save @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import { MODAL_STATUS, VIZ_TYPE_PARAM } from '../../constants';
import { useVizConfig, useVisualisation } from '../../context';
import { useSaveDashboardVisualisation, useSaveMapOverlayVisualisation } from '../../api';
import { useVizBuilderBasePath } from '../../utils';

const TickIcon = styled(CheckCircle)`
font-size: 2.5rem;
Expand All @@ -41,6 +42,7 @@ export const SaveVisualisationModal = ({ isOpen, onClose }) => {
const [_, { setVisualisationValue }] = useVizConfig();
const { visualisation } = useVisualisation();

const basePath = useVizBuilderBasePath();
const { vizType } = useParams();

const useSaveViz = () => {
Expand Down Expand Up @@ -71,11 +73,11 @@ export const SaveVisualisationModal = ({ isOpen, onClose }) => {
onClose();
});

let backLink = '/';
let backLink = basePath;
if (vizType === VIZ_TYPE_PARAM.DASHBOARD_ITEM) {
backLink = '/dashboard-items';
backLink = backLink.concat('/visualisations');
} else if (vizType === VIZ_TYPE_PARAM.MAP_OVERLAY) {
backLink = '/dashboard-items/map-overlays';
backLink = backLink.concat('/visualisations/map-overlays');
}

if (status === MODAL_STATUS.SUCCESS) {
Expand Down
6 changes: 6 additions & 0 deletions packages/admin-panel/src/VizBuilderApp/utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Tupaia
* Copyright (c) 2017 - 2022 Beyond Essential Systems Pty Ltd
*/

export { useVizBuilderBasePath } from './useVizBuilderBasePath';
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Tupaia
* Copyright (c) 2017 - 2022 Beyond Essential Systems Pty Ltd
*/

import { useLocation } from 'react-router-dom';

export const useVizBuilderBasePath = () => {
const { pathname } = useLocation();
return pathname.substring(0, pathname.indexOf('/viz-builder/')) || '';
};
4 changes: 3 additions & 1 deletion packages/admin-panel/src/VizBuilderApp/views/CreateNew.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Button, FlexEnd } from '@tupaia/ui-components';
import { DashboardMetadataForm } from '../components';
import { VIZ_TYPE_PARAM } from '../constants';
import { MapOverlayMetadataForm } from '../components/MapOverlay';
import { useVizBuilderBasePath } from '../utils';

const Container = styled(MuiContainer)`
flex: 1;
Expand Down Expand Up @@ -58,9 +59,10 @@ export const CreateNew = () => {
const { vizType } = useParams();

const history = useHistory();
const basePath = useVizBuilderBasePath();

const handleCreate = () => {
history.push(`/viz-builder/${vizType}/`);
history.push(`${basePath}/viz-builder/${vizType}/`);
};

const MetadataFormComponent = getMetadataFormComponent(vizType);
Expand Down
6 changes: 4 additions & 2 deletions packages/admin-panel/src/authentication/PrivateRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { getIsUserAuthenticated } from './selectors';
* A wrapper for <Route> that redirects to the login
* screen if you're not yet authenticated.
*/
export const PrivateRouteComponent = ({ isLoggedIn, children, ...props }) => {
export const PrivateRouteComponent = ({ loginPath, isLoggedIn, children, ...props }) => {
return (
<Route
{...props}
Expand All @@ -22,7 +22,7 @@ export const PrivateRouteComponent = ({ isLoggedIn, children, ...props }) => {
) : (
<Redirect
to={{
pathname: '/login',
pathname: loginPath,
state: { from: location },
}}
/>
Expand All @@ -35,10 +35,12 @@ export const PrivateRouteComponent = ({ isLoggedIn, children, ...props }) => {
PrivateRouteComponent.propTypes = {
children: PropTypes.node.isRequired,
isLoggedIn: PropTypes.bool,
loginPath: PropTypes.string,
};

PrivateRouteComponent.defaultProps = {
isLoggedIn: false,
loginPath: '/login',
};

const mapStateToProps = state => ({
Expand Down
37 changes: 24 additions & 13 deletions packages/admin-panel/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import React, { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
import { render as renderReactApp } from 'react-dom';
import { ThemeProvider } from 'styled-components';
import CssBaseline from '@material-ui/core/CssBaseline';
import { MuiThemeProvider, StylesProvider } from '@material-ui/core/styles';
import 'react-table/react-table.css';
import { EnvBanner } from '@tupaia/ui-components';
import AdminPanel from './App';
Expand All @@ -13,6 +16,7 @@ import { AdminPanelProviders } from './utilities/AdminPanelProviders';
import { StoreProvider } from './utilities/StoreProvider';
import { Footer, Navbar } from './widgets';
import { TupaiaApi } from './api';
import { theme } from './theme';

const VizBuilder = lazy(() => import('./VizBuilderApp'));

Expand All @@ -24,19 +28,26 @@ renderReactApp(
{/* Store provider applied above routes so that it always persists auth state */}
<StoreProvider api={api} persist>
<EnvBanner />
<Switch>
<Route path="/viz-builder">
<VizBuilderProviders>
<VizBuilder Navbar={Navbar} Footer={Footer} />
</VizBuilderProviders>
</Route>
<Route path="/">
<AdminPanelProviders>
<AdminPanel />
</AdminPanelProviders>
</Route>
<Redirect to="/login" />
</Switch>
<StylesProvider injectFirst>
<MuiThemeProvider theme={theme}>
<ThemeProvider theme={theme}>
<CssBaseline />
<Switch>
<Route path="/viz-builder">
<VizBuilderProviders>
<VizBuilder Navbar={Navbar} Footer={Footer} />
</VizBuilderProviders>
</Route>
<Route path="/">
<AdminPanelProviders>
<AdminPanel />
</AdminPanelProviders>
</Route>
<Redirect to="/login" />
</Switch>
</ThemeProvider>
</MuiThemeProvider>
</StylesProvider>
</StoreProvider>
</Suspense>
</Router>,
Expand Down
4 changes: 4 additions & 0 deletions packages/admin-panel/src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
*/
import 'react-table/react-table.css';

export { LoginPage, LogoutPage } from './pages';
export { PrivateRoute } from './authentication';
export * from './pages/resources';
export { IconButton } from './widgets';
export { AdminPanelDataProviders } from './utilities/AdminPanelProviders';
export { DataChangeAction } from './editor';
export { App as VizBuilderApp } from './VizBuilderApp/App';
export { VizBuilderProviders } from './utilities/VizBuilderProviders';
15 changes: 12 additions & 3 deletions packages/admin-panel/src/pages/LoginPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,17 @@ const StyledLink = styled(MuiLink)`

const requestAnAccountUrl = 'https://info.tupaia.org/contact';

const LoginPageComponent = ({ isLoggedIn }) => {
const Logo = () => <StyledImg src="/admin-panel-logo.svg" alt="psss-logo" />;

const LoginPageComponent = ({ isLoggedIn, redirectTo, LogoComponent }) => {
if (isLoggedIn) {
return <Redirect to="/" />;
return <Redirect to={redirectTo} />;
}

return (
<Main>
<Container>
<StyledImg src="/admin-panel-logo.svg" alt="psss-logo" />
<LogoComponent />
<StyledCard>
<LoginForm />
</StyledCard>
Expand All @@ -82,6 +84,13 @@ const LoginPageComponent = ({ isLoggedIn }) => {

LoginPageComponent.propTypes = {
isLoggedIn: PropTypes.bool.isRequired,
redirectTo: PropTypes.string,
LogoComponent: PropTypes.element,
};

LoginPageComponent.defaultProps = {
redirectTo: '/',
LogoComponent: Logo,
};

const mapStateToProps = state => ({
Expand Down
6 changes: 4 additions & 2 deletions packages/admin-panel/src/pages/LogoutPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,26 @@ import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { getIsUserAuthenticated, logout } from '../authentication';

const LogoutPageComponent = ({ onLogout, isLoggedIn }) => {
const LogoutPageComponent = ({ redirectTo, onLogout, isLoggedIn }) => {
useEffect(() => {
onLogout();
}, [onLogout]);

if (!isLoggedIn) {
return <Redirect to="/login" />;
return <Redirect to={redirectTo} />;
}

return <div>Logging out...</div>;
};

LogoutPageComponent.propTypes = {
redirectTo: PropTypes.string,
isLoggedIn: PropTypes.bool,
onLogout: PropTypes.func.isRequired,
};

LogoutPageComponent.defaultProps = {
redirectTo: '/login',
isLoggedIn: true,
};

Expand Down
7 changes: 7 additions & 0 deletions packages/admin-panel/src/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Tupaia
* Copyright (c) 2017 - 2022 Beyond Essential Systems Pty Ltd
*/

export { LoginPage } from './LoginPage';
export { LogoutPage } from './LogoutPage';
62 changes: 33 additions & 29 deletions packages/admin-panel/src/pages/resources/DashboardItemsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,33 +49,7 @@ const FIELDS = [
},
];

const IMPORT_CONFIG = {
title: 'Import Dashboard Visualisation',
subtitle: 'Please upload one or more .json files with visualisations to be imported:',
actionConfig: {
importEndpoint: 'dashboardVisualisations',
multiple: true,
},
getFinishedMessage: response => (
<>
<span>{response.message}</span>
{response.importedVizes.map(({ code, id }) => (
<p>
<span>{`${code}: `}</span>
<Link to={`/viz-builder/dashboard-item/${id}`}>View in Visualisation Builder</Link>
</p>
))}
</>
),
};

const renderNewDashboardVizButton = () => (
<StyledLink to="/viz-builder/dashboard-item/new">
<LightOutlinedButton startIcon={<AddCircleIcon />}>New</LightOutlinedButton>
</StyledLink>
);

export const DashboardItemsPage = ({ getHeaderEl, isBESAdmin, ...props }) => {
export const DashboardItemsPage = ({ getHeaderEl, isBESAdmin, vizBuilderBaseUrl, ...props }) => {
const extraEditFields = [
// ID field for constructing viz-builder path only, not for showing or editing
{
Expand All @@ -90,7 +64,7 @@ export const DashboardItemsPage = ({ getHeaderEl, isBESAdmin, ...props }) => {
editConfig: {
type: 'link',
linkOptions: {
path: '/viz-builder/dashboard-item/:id',
path: `${vizBuilderBaseUrl}/viz-builder/dashboard-item/:id`,
parameters: { id: 'id' },
},
visibilityCriteria: {
Expand Down Expand Up @@ -131,12 +105,40 @@ export const DashboardItemsPage = ({ getHeaderEl, isBESAdmin, ...props }) => {
},
];

const importConfig = {
title: 'Import Dashboard Visualisation',
subtitle: 'Please upload one or more .json files with visualisations to be imported:',
actionConfig: {
importEndpoint: 'dashboardVisualisations',
multiple: true,
},
getFinishedMessage: response => (
<>
<span>{response.message}</span>
{response.importedVizes.map(({ code, id }) => (
<p>
<span>{`${code}: `}</span>
<Link to={`${vizBuilderBaseUrl}/viz-builder/dashboard-item/${id}`}>
View in Visualisation Builder
</Link>
</p>
))}
</>
),
};

const renderNewDashboardVizButton = () => (
<StyledLink to={`${vizBuilderBaseUrl}/viz-builder/dashboard-item/new`}>
<LightOutlinedButton startIcon={<AddCircleIcon />}>New</LightOutlinedButton>
</StyledLink>
);

return (
<ResourcePage
title="Dashboard Items"
endpoint={DASHBOARD_ITEMS_ENDPOINT}
columns={columns}
importConfig={IMPORT_CONFIG}
importConfig={importConfig}
LinksComponent={renderNewDashboardVizButton}
getHeaderEl={getHeaderEl}
{...props}
Expand All @@ -147,8 +149,10 @@ export const DashboardItemsPage = ({ getHeaderEl, isBESAdmin, ...props }) => {
DashboardItemsPage.propTypes = {
getHeaderEl: PropTypes.func.isRequired,
isBESAdmin: PropTypes.bool,
vizBuilderBaseUrl: PropTypes.string,
};

DashboardItemsPage.defaultProps = {
isBESAdmin: false,
vizBuilderBaseUrl: '',
};
Loading

0 comments on commit 823e586

Please sign in to comment.