From 186263cc2d9cf90fbc8840c4ff9587b0afaec25e Mon Sep 17 00:00:00 2001
From: Bjarke Madsen <bjarke@nordu.net>
Date: Tue, 2 May 2023 21:12:54 +0200
Subject: [PATCH] Add sidebar to all organization pages
---
webapp/src/App.tsx | 37 ++--
webapp/src/components/OrganizationSidebar.tsx | 56 ++++++
webapp/src/components/SideBar.tsx | 25 +++
webapp/src/helpers/SidebarProvider.tsx | 31 +++
webapp/src/pages/ChargingStructure.tsx | 178 +++++++++---------
webapp/src/pages/DataAnalysis.tsx | 22 ++-
webapp/src/pages/ECProjects.tsx | 75 ++++----
webapp/src/pages/FundingSource.tsx | 61 +++---
webapp/src/pages/ParentOrganisation.tsx | 87 +++++----
webapp/src/pages/StaffGraph.tsx | 56 +++---
webapp/src/pages/SubOrganisation.tsx | 91 ++++-----
webapp/src/scss/layout/Sidebar.scss | 31 +++
webapp/src/scss/layout/_components.scss | 1 +
13 files changed, 461 insertions(+), 290 deletions(-)
create mode 100644 webapp/src/components/OrganizationSidebar.tsx
create mode 100644 webapp/src/components/SideBar.tsx
create mode 100644 webapp/src/helpers/SidebarProvider.tsx
create mode 100644 webapp/src/scss/layout/Sidebar.scss
diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx
index c3c119e1..cb7b57a9 100644
--- a/webapp/src/App.tsx
+++ b/webapp/src/App.tsx
@@ -1,10 +1,9 @@
-import React, { ReactElement, useState } from "react";
+import React, { ReactElement, useState, useContext } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Landing from "./pages/Landing";
import ExternalPageNavBar from "./components/global/ExternalPageNavBar";
import GeantFooter from "./components/global/GeantFooter";
import DataAnalysis from "./pages/DataAnalysis";
-import AnnualReport from "./pages/AnnualReport";
import CompendiumData from "./pages/CompendiumData";
import FundingSourcePage from "./pages/FundingSource";
import ChargingStructurePage from "./pages/ChargingStructure";
@@ -13,32 +12,34 @@ import { FilterSelection } from "./Schema";
import SubOrganisation from "./pages/SubOrganisation";
import ParentOrganisation from "./pages/ParentOrganisation";
import ECProjects from "./pages/ECProjects";
+import SidebarProvider from "./helpers/SidebarProvider";
function App(): ReactElement {
const [filterSelection, setFilterSelection] = useState<FilterSelection>({ selectedYears: [], selectedNrens: [] });
+
+
return (
<div className="app">
<Router>
<ExternalPageNavBar />
- <Routes>
- <Route path="/data" element={<CompendiumData />} />
- <Route path="/analysis" element={
- <DataAnalysis filterSelection={filterSelection} setFilterSelection={setFilterSelection} />}
- />
- <Route path="/report" element={<AnnualReport />} />
- <Route path="/funding" element={<FundingSourcePage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />}
- />
- <Route path="/data/employment" element={<StaffGraph filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
- <Route path="/data/roles" element={<StaffGraph roles filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
- <Route path="/charging" element={<ChargingStructurePage filterSelection={filterSelection} setFilterSelection={setFilterSelection}/>} />
- <Route path="/suborganisations" element={<SubOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
- <Route path="/parentorganisation" element={<ParentOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
- <Route path="/ec-projects" element={<ECProjects filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
- <Route path="*" element={<Landing />} />
- </Routes>
+ <SidebarProvider>
+ <Routes>
+ <Route path="/analysis" element={<DataAnalysis filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
+ <Route path="/funding" element={<FundingSourcePage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
+ <Route path="/data/employment" element={<StaffGraph filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
+ <Route path="/data/roles" element={<StaffGraph roles filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
+ <Route path="/charging" element={<ChargingStructurePage filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
+ <Route path="/suborganisations" element={<SubOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
+ <Route path="/parentorganisation" element={<ParentOrganisation filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
+ <Route path="/ec-projects" element={<ECProjects filterSelection={filterSelection} setFilterSelection={setFilterSelection} />} />
+ <Route path="/data" element={<CompendiumData />} />
+ <Route path="*" element={<Landing />} />
+ </Routes>
+ </SidebarProvider>
+
<GeantFooter />
</Router>
diff --git a/webapp/src/components/OrganizationSidebar.tsx b/webapp/src/components/OrganizationSidebar.tsx
new file mode 100644
index 00000000..3fac81c7
--- /dev/null
+++ b/webapp/src/components/OrganizationSidebar.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Row } from 'react-bootstrap';
+import Sidebar from './SideBar';
+
+const OrganizationSidebar = () => {
+ return (
+ <Sidebar>
+ <Row>
+ <Link to="/analysis" className="link-text-underline">
+ <span>Budget of NRENs per Year</span>
+ </Link>
+ </Row>
+
+ <Row>
+ <Link to="/funding" className="link-text-underline">
+ <span>Income Source of NRENs per Year</span>
+ </Link>
+ </Row>
+
+ <Row>
+ <Link to="/charging" className="link-text-underline">
+ <span>Charging Mechanism of NRENs per Year</span>
+ </Link>
+ </Row>
+
+ <Row>
+ <Link to="/data/roles" className="link-text-underline">
+ <span>Roles of NREN employees</span>
+ </Link>
+ </Row>
+ <Row>
+ <Link to="/data/employment" className="link-text-underline">
+ <span>Types of employment for NRENs</span>
+ </Link>
+ </Row>
+ <Row>
+ <Link to="/suborganisations" className="link-text-underline">
+ <span>NREN Suborganisations</span>
+ </Link>
+ </Row>
+ <Row>
+ <Link to="/parentorganisation" className="link-text-underline">
+ <span>NREN Parent Organisations</span>
+ </Link>
+ </Row>
+ <Row>
+ <Link to="/ec-projects" className="link-text-underline">
+ <span>NREN Involvement in European Commission Projects</span>
+ </Link>
+ </Row>
+ </Sidebar>
+ )
+}
+
+export default OrganizationSidebar
\ No newline at end of file
diff --git a/webapp/src/components/SideBar.tsx b/webapp/src/components/SideBar.tsx
new file mode 100644
index 00000000..ddcab7d4
--- /dev/null
+++ b/webapp/src/components/SideBar.tsx
@@ -0,0 +1,25 @@
+import React, { useContext } from 'react';
+import { sidebarContext } from "../helpers/SidebarProvider";
+
+
+interface Props {
+ children: React.ReactNode;
+}
+
+const Sidebar: React.FC<Props> = ({ children }) => {
+
+ const { show, toggle } = useContext(sidebarContext);
+
+ return (
+ <div className="sidebar-wrapper">
+ <nav className={show ? '' : 'no-sidebar'} id="sidebar">
+ <div className={`menu-items`}>{children}</div>
+ </nav>
+ <button className="toggle-btn" onClick={toggle}>
+ {show ? 'Hide Sidebar' : 'Show Sidebar'}
+ </button>
+ </div>
+ );
+};
+
+export default Sidebar;
\ No newline at end of file
diff --git a/webapp/src/helpers/SidebarProvider.tsx b/webapp/src/helpers/SidebarProvider.tsx
new file mode 100644
index 00000000..fdf631d1
--- /dev/null
+++ b/webapp/src/helpers/SidebarProvider.tsx
@@ -0,0 +1,31 @@
+import React, { createContext, useState } from 'react';
+
+interface Props {
+ children: React.ReactNode;
+}
+
+const sidebarContext = createContext<{
+ show: boolean;
+ toggle: React.Dispatch<any>;
+}>({
+ show: false,
+ toggle: () => { }
+});
+
+
+const SidebarProvider: React.FC<Props> = ({ children }) => {
+ const [show, setShow] = useState<boolean>(false);
+
+ const toggle = () => {
+ setShow(!show);
+ };
+
+ return (
+ <sidebarContext.Provider value={{ show, toggle }}>
+ {children}
+ </sidebarContext.Provider>
+ );
+};
+
+export { sidebarContext };
+export default SidebarProvider;
\ No newline at end of file
diff --git a/webapp/src/pages/ChargingStructure.tsx b/webapp/src/pages/ChargingStructure.tsx
index 800e10f4..660499a1 100644
--- a/webapp/src/pages/ChargingStructure.tsx
+++ b/webapp/src/pages/ChargingStructure.tsx
@@ -1,8 +1,6 @@
-import React, { useEffect, useState } from "react";
+import React, { useState } from "react";
import { Container, Row, Col, Table } from "react-bootstrap";
-import Chart, { ChartOptions, Plugin, ChartTypeRegistry, ScatterDataPoint } from 'chart.js';
-import { Bubble, Scatter } from "react-chartjs-2";
-import { ChargingStructure, ChargingStructureDataset, FilterSelection } from "../Schema";
+import { ChargingStructure, FilterSelection } from "../Schema";
import {
Chart as ChartJS,
@@ -11,12 +9,13 @@ import {
BarElement,
Title,
Tooltip,
- Legend,
- scales,
+ Legend
} from 'chart.js';
import Filter from "../components/graphing/Filter";
import { createChargingStructureDataLookup } from "../helpers/dataconversion";
import ColorPill from "../components/ColorPill";
+import OrganizationSidebar from "../components/OrganizationSidebar";
+
ChartJS.register(
CategoryScale,
LinearScale,
@@ -26,10 +25,6 @@ ChartJS.register(
Legend
);
-const EMPTY_DATASET = { datasets: [], labels: [] };
-
-
-
async function getData(): Promise<ChargingStructure[]> {
try {
const response = await fetch('/api/charging/');
@@ -61,89 +56,90 @@ function ChargingStructurePage({ filterSelection, setFilterSelection }: inputPro
return (
<>
- <Container fluid className="p-0">
- <Row>
- <h1>Charging Structure</h1>
- </Row>
- <Row>
- <Col xs={9}>
- <Table className="charging-struct-table" striped bordered responsive >
- <colgroup>
- <col span={1} style={{ width: "10%" }} />
- <col span={1} style={{ width: "18%" }} />
- <col span={1} style={{ width: "18%" }} />
- <col span={1} style={{ width: "18%" }} />
- <col span={1} style={{ width: "18%" }} />
- <col span={1} style={{ width: "18%" }} />
- </colgroup>
- <thead>
- <tr >
- <th></th>
- <th>Flat fee based on bandwidth</th>
- <th>Usage based fee</th>
- <th>Combination flat fee & usage basedfee </th>
- <th>No Direct Charge</th>
- <th>Other</th>
- </tr>
- </thead>
- <tbody>
- {filterSelection.selectedNrens
- .sort((a, b) => a>b? 1 : -1)
- .map((nren: string) => (
- <tr key={nren}>
- <td>{nren}</td>
- <td >
- {filterSelection.selectedYears
- .sort((a, b) => a>b? 1 : -1)
- .map((year: number, index) => (
- <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"flat_fee"}/>
- ))}
- </td>
- <td>
- {filterSelection.selectedYears
- .sort((a, b) => a>b? 1 : -1)
- .map((year: number, index) => (
- <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"usage_based_fee"}/>
- ))
- }
- </td>
- <td>
- {filterSelection.selectedYears
- .sort((a, b) => a>b? 1 : -1)
- .map((year: number, index) => (
- <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"combination"}/>
- ))}
- </td>
- <td>
- {filterSelection.selectedYears
- .sort((a, b) => a>b? 1 : -1)
- .map((year: number, index) => (
- <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"no_charge"}/>
- ))}
- </td>
- <td>
- {filterSelection.selectedYears
- .sort((a, b) => a>b? 1 : -1)
- .map((year: number, index) => (
- <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"other"}/>
- ))}
- </td>
- </tr>
+ <OrganizationSidebar />
+ <Container fluid className="p-0">
+ <Row>
+ <h1>Charging Structure</h1>
+ </Row>
+ <Row>
+ <Col xs={9}>
+ <Table className="charging-struct-table" striped bordered responsive >
+ <colgroup>
+ <col span={1} style={{ width: "10%" }} />
+ <col span={1} style={{ width: "18%" }} />
+ <col span={1} style={{ width: "18%" }} />
+ <col span={1} style={{ width: "18%" }} />
+ <col span={1} style={{ width: "18%" }} />
+ <col span={1} style={{ width: "18%" }} />
+ </colgroup>
+ <thead>
+ <tr >
+ <th></th>
+ <th>Flat fee based on bandwidth</th>
+ <th>Usage based fee</th>
+ <th>Combination flat fee & usage basedfee </th>
+ <th>No Direct Charge</th>
+ <th>Other</th>
+ </tr>
+ </thead>
+ <tbody>
+ {filterSelection.selectedNrens
+ .sort((a, b) => a > b ? 1 : -1)
+ .map((nren: string) => (
+ <tr key={nren}>
+ <td>{nren}</td>
+ <td >
+ {filterSelection.selectedYears
+ .sort((a, b) => a > b ? 1 : -1)
+ .map((year: number, index) => (
+ <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"flat_fee"} />
+ ))}
+ </td>
+ <td>
+ {filterSelection.selectedYears
+ .sort((a, b) => a > b ? 1 : -1)
+ .map((year: number, index) => (
+ <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"usage_based_fee"} />
+ ))
+ }
+ </td>
+ <td>
+ {filterSelection.selectedYears
+ .sort((a, b) => a > b ? 1 : -1)
+ .map((year: number, index) => (
+ <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"combination"} />
+ ))}
+ </td>
+ <td>
+ {filterSelection.selectedYears
+ .sort((a, b) => a > b ? 1 : -1)
+ .map((year: number, index) => (
+ <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"no_charge"} />
+ ))}
+ </td>
+ <td>
+ {filterSelection.selectedYears
+ .sort((a, b) => a > b ? 1 : -1)
+ .map((year: number, index) => (
+ <ColorPill key={year} nren={nren} year={year} index={index} dataLookup={dataLookup} discriminator={"other"} />
+ ))}
+ </td>
+ </tr>
- ))}
- </tbody>
+ ))}
+ </tbody>
- </Table>
- </Col>
- <Col xs={3}>
- <Filter
- filterOptions={{availableYears: [...labelsYear], availableNrens: [...labelsNREN]}}
- filterSelection={filterSelection}
- setFilterSelection={setFilterSelection}
- />
- </Col>
- </Row>
- </Container>
+ </Table>
+ </Col>
+ <Col xs={3}>
+ <Filter
+ filterOptions={{ availableYears: [...labelsYear], availableNrens: [...labelsNREN] }}
+ filterSelection={filterSelection}
+ setFilterSelection={setFilterSelection}
+ />
+ </Col>
+ </Row>
+ </Container>
</>
);
};
diff --git a/webapp/src/pages/DataAnalysis.tsx b/webapp/src/pages/DataAnalysis.tsx
index 29cb56db..53eb3a59 100644
--- a/webapp/src/pages/DataAnalysis.tsx
+++ b/webapp/src/pages/DataAnalysis.tsx
@@ -1,10 +1,11 @@
-import React, {ReactElement, useEffect, useState} from 'react';
+import React, { ReactElement, useEffect, useState } from 'react';
import { Col, Container, Row } from "react-bootstrap";
import LineGraph from "../components/graphing/LineGraph";
-
-import {Budget, FilterSelection} from "../Schema";
import Filter from "../components/graphing/Filter";
-import {createBudgetDataset} from "../helpers/dataconversion";
+import OrganizationSidebar from "../components/OrganizationSidebar";
+
+import { createBudgetDataset } from "../helpers/dataconversion";
+import { Budget, FilterSelection } from "../Schema";
function api<T>(url: string, options: RequestInit | undefined = undefined): Promise<T> {
return fetch(url, options)
@@ -35,7 +36,6 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac
budgetData.datasets.forEach(dataset => {
dataset.hidden = !filterSelection.selectedNrens.includes(dataset.label);
});
-
useEffect(() => {
const loadData = async () => {
@@ -61,6 +61,8 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac
return (
<div>
<h1>Data Analysis</h1>
+ <OrganizationSidebar />
+
<Container>
<Row>
<Col>
@@ -68,15 +70,15 @@ function DataAnalysis({ filterSelection, setFilterSelection }: inputProps): Reac
<LineGraph data={budgetData} />
</Row>
<Row>
-The numbers are based on 30 NRENs that reported their budgets continuously throughout this
-period. This means that some larger NRENs are not included and therefore the actual total budgets will
-have been higher. (For comparison, the total budget according to the 2021 survey results based on the data
-for all responding NRENs that year is €555 M). The percentage change is based on the previous year's budget.
+ The numbers are based on 30 NRENs that reported their budgets continuously throughout this
+ period. This means that some larger NRENs are not included and therefore the actual total budgets will
+ have been higher. (For comparison, the total budget according to the 2021 survey results based on the data
+ for all responding NRENs that year is €555 M). The percentage change is based on the previous year's budget.
</Row>
</Col>
<Col xs={3}>
<Filter
- filterOptions={{availableYears: [], availableNrens: [...nrens]}}
+ filterOptions={{ availableYears: [], availableNrens: [...nrens] }}
filterSelection={filterSelection}
setFilterSelection={setFilterSelection}
/>
diff --git a/webapp/src/pages/ECProjects.tsx b/webapp/src/pages/ECProjects.tsx
index 36ebd132..16748224 100644
--- a/webapp/src/pages/ECProjects.tsx
+++ b/webapp/src/pages/ECProjects.tsx
@@ -1,6 +1,7 @@
import React, { useEffect, useMemo, useState } from 'react';
import { Col, Container, Row, Table } from "react-bootstrap";
import Filter from "../components/graphing/Filter"
+import OrganizationSidebar from '../components/OrganizationSidebar';
import {
ECProject,
@@ -123,41 +124,45 @@ function ECProjects({ filterSelection, setFilterSelection }: inputProps) {
}, [setFilterSelection]);
return (
- <Container>
- <Row>
- <Col xs={9}>
- <Row>
- <h3>NREN Involvement in European Commission Projects</h3>
- </Row>
- <Row>
- <Table>
- <thead>
- <tr>
- <th>NREN</th>
- <th>Year</th>
- <th>EC Project Membership</th>
- </tr>
- </thead>
- <tbody className='table-bg-highlighted'>
- {getJSXFromMap(projectDataByYear)}
- </tbody>
- </Table>
- </Row>
- </Col>
- <Col xs={3}>
- <div className="sticky-top" style={{ top: '1rem' }}>
- {/* the sticky-top class makes the filter follow the user as they scroll down the page */}
- <Filter
- filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
- filterSelection={filterSelection}
- setFilterSelection={setFilterSelection}
- />
- </div>
-
-
- </Col>
- </Row>
- </Container>
+ <>
+ <OrganizationSidebar />
+ <Container>
+ <Row>
+ <Col xs={9}>
+ <Row>
+ <h3>NREN Involvement in European Commission Projects</h3>
+ </Row>
+ <Row>
+ <Table>
+ <thead>
+ <tr>
+ <th>NREN</th>
+ <th>Year</th>
+ <th>EC Project Membership</th>
+ </tr>
+ </thead>
+ <tbody className='table-bg-highlighted'>
+ {getJSXFromMap(projectDataByYear)}
+ </tbody>
+ </Table>
+ </Row>
+ </Col>
+ <Col xs={3}>
+ <div className="sticky-top" style={{ top: '1rem' }}>
+ {/* the sticky-top class makes the filter follow the user as they scroll down the page */}
+ <Filter
+ filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
+ filterSelection={filterSelection}
+ setFilterSelection={setFilterSelection}
+ />
+ </div>
+
+
+ </Col>
+ </Row>
+ </Container>
+ </>
+
);
}
export default ECProjects;
diff --git a/webapp/src/pages/FundingSource.tsx b/webapp/src/pages/FundingSource.tsx
index c0de4104..a6772232 100644
--- a/webapp/src/pages/FundingSource.tsx
+++ b/webapp/src/pages/FundingSource.tsx
@@ -1,8 +1,10 @@
-import React, {useEffect, useMemo, useState} from 'react';
-import {Col, Container, Row} from "react-bootstrap";
+import React, { useEffect, useMemo, useState } from 'react';
+import { Col, Container, Row } from "react-bootstrap";
import { Bar } from 'react-chartjs-2';
import { createFundingSourceDataset } from "../helpers/dataconversion";
import Filter from "../components/graphing/Filter"
+import OrganizationSidebar from "../components/OrganizationSidebar";
+
import {
Chart as ChartJS,
@@ -19,6 +21,7 @@ import {
} from "../Schema";
+
ChartJS.register(
CategoryScale,
LinearScale,
@@ -82,7 +85,7 @@ function getYearsAndNrens(sourceData: FundingSource[]) {
years.add(datapoint.YEAR);
nrens.add(datapoint.NREN);
});
- return {years: years, nrens: nrens};
+ return { years: years, nrens: nrens };
}
interface inputProps {
@@ -132,30 +135,34 @@ function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps)
}, [setFilterSelection]);
return (
- <Container>
- <Row>
- <Col xs={9}>
- <Row>
- <h1>Funding Source</h1>
- </Row>
- <Row>
- <div className="chart-container" style={{ 'minHeight': '100vh', 'width': '60vw', }}>
- <Bar
- data={fundingSourceDataset}
- options={chartOptions}
- />
- </div>
- </Row>
- </Col>
- <Col xs={3}>
- <Filter
- filterOptions={{availableYears: [...years], availableNrens: [...nrens]}}
- filterSelection={filterSelection}
- setFilterSelection={setFilterSelection}
- />
- </Col>
- </Row>
- </Container>
+ <>
+ <OrganizationSidebar />
+ <Container>
+ <Row>
+ <Col xs={9}>
+ <Row>
+ <h1>Funding Source</h1>
+ </Row>
+ <Row>
+ <div className="chart-container" style={{ 'minHeight': '100vh', 'width': '60vw', }}>
+ <Bar
+ data={fundingSourceDataset}
+ options={chartOptions}
+ />
+ </div>
+ </Row>
+ </Col>
+ <Col xs={3}>
+ <Filter
+ filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
+ filterSelection={filterSelection}
+ setFilterSelection={setFilterSelection}
+ />
+ </Col>
+ </Row>
+ </Container>
+ </>
+
);
}
export default FundingSourcePage;
diff --git a/webapp/src/pages/ParentOrganisation.tsx b/webapp/src/pages/ParentOrganisation.tsx
index 725428e5..32e3cbd5 100644
--- a/webapp/src/pages/ParentOrganisation.tsx
+++ b/webapp/src/pages/ParentOrganisation.tsx
@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import { Col, Container, Row, Table } from "react-bootstrap";
import { createOrganisationDataLookup } from "../helpers/dataconversion";
import Filter from "../components/graphing/Filter"
+import OrganizationSidebar from '../components/OrganizationSidebar';
import {
Organisation,
@@ -69,48 +70,52 @@ function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps)
}
return (
- <Container>
- <Row>
- <Col xs={9}>
- <Row>
- <h3>NREN Parent Organisations</h3>
- </Row>
- <Row>
- <Table>
- <thead>
- <tr>
- <th>NREN</th>
- <th>Year</th>
- <th>Parent Organisation</th>
- </tr>
- </thead>
- <tbody>
- {Array.from(organisationDataset).sort().map(([_, nrenEntry]) => (
- Array.from(nrenEntry).sort().map(([_, nrenDataList], yearIndex) => (
- nrenDataList.sort(sortOrganisation).map((nrenData, nrenDataIndex) => (
- <tr key={nrenData.nren + nrenData.year + nrenData.name}>
- <td>{yearIndex == 0 && nrenDataIndex == 0 && nrenData.nren}</td>
- <td>{nrenDataIndex == 0 && nrenData.year}</td>
- <td>{nrenData.name}</td>
- </tr>
- ))
- )
- )
+ <>
+ <OrganizationSidebar />
+ <Container>
+ <Row>
+ <Col xs={9}>
+ <Row>
+ <h3>NREN Parent Organisations</h3>
+ </Row>
+ <Row>
+ <Table>
+ <thead>
+ <tr>
+ <th>NREN</th>
+ <th>Year</th>
+ <th>Parent Organisation</th>
+ </tr>
+ </thead>
+ <tbody>
+ {Array.from(organisationDataset).sort().map(([_, nrenEntry]) => (
+ Array.from(nrenEntry).sort().map(([_, nrenDataList], yearIndex) => (
+ nrenDataList.sort(sortOrganisation).map((nrenData, nrenDataIndex) => (
+ <tr key={nrenData.nren + nrenData.year + nrenData.name}>
+ <td>{yearIndex == 0 && nrenDataIndex == 0 && nrenData.nren}</td>
+ <td>{nrenDataIndex == 0 && nrenData.year}</td>
+ <td>{nrenData.name}</td>
+ </tr>
+ ))
+ )
+ )
+
+ ))}
+ </tbody>
+ </Table>
+ </Row>
+ </Col>
+ <Col xs={3}>
+ <Filter
+ filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
+ filterSelection={filterSelection}
+ setFilterSelection={setFilterSelection}
+ />
+ </Col>
+ </Row>
+ </Container>
+ </>
- ))}
- </tbody>
- </Table>
- </Row>
- </Col>
- <Col xs={3}>
- <Filter
- filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
- filterSelection={filterSelection}
- setFilterSelection={setFilterSelection}
- />
- </Col>
- </Row>
- </Container>
);
}
export default ParentOrganisation;
diff --git a/webapp/src/pages/StaffGraph.tsx b/webapp/src/pages/StaffGraph.tsx
index acfc30b8..8a082c75 100644
--- a/webapp/src/pages/StaffGraph.tsx
+++ b/webapp/src/pages/StaffGraph.tsx
@@ -3,6 +3,8 @@ import { Col, Container, Row } from "react-bootstrap";
import { Bar } from 'react-chartjs-2';
import { createNRENStaffDataset } from "../helpers/dataconversion";
import Filter from "../components/graphing/Filter"
+import OrganizationSidebar from "../components/OrganizationSidebar";
+
import {
Chart as ChartJS,
@@ -141,31 +143,35 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu
const text = roles ? "Roles" : "Employment";
return (
- <Container>
- <Row>
- <Col xs={9}>
- <Row>
- <h3>NREN Staff {text}</h3>
- </Row>
- <Row>
- <div className="chart-container" style={{ 'minHeight': '60vh', 'width': '60vw', }}>
- <Bar
- data={nrenStaffDataset}
- options={chartOptions}
- />
- </div>
- </Row>
- </Col>
- <Col xs={3}>
- <Filter
- max1year
- filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
- filterSelection={filterSelection}
- setFilterSelection={setFilterSelection}
- />
- </Col>
- </Row>
- </Container>
+ <>
+ <OrganizationSidebar />
+ <Container>
+ <Row>
+ <Col xs={9}>
+ <Row>
+ <h3>NREN Staff {text}</h3>
+ </Row>
+ <Row>
+ <div className="chart-container" style={{ 'minHeight': '60vh', 'width': '60vw', }}>
+ <Bar
+ data={nrenStaffDataset}
+ options={chartOptions}
+ />
+ </div>
+ </Row>
+ </Col>
+ <Col xs={3}>
+ <Filter
+ max1year
+ filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
+ filterSelection={filterSelection}
+ setFilterSelection={setFilterSelection}
+ />
+ </Col>
+ </Row>
+ </Container>
+ </>
+
);
}
export default StaffGraph;
diff --git a/webapp/src/pages/SubOrganisation.tsx b/webapp/src/pages/SubOrganisation.tsx
index 6bc2602b..2d78a2a2 100644
--- a/webapp/src/pages/SubOrganisation.tsx
+++ b/webapp/src/pages/SubOrganisation.tsx
@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import { Col, Container, Row, Table } from "react-bootstrap";
import { createOrganisationDataLookup } from "../helpers/dataconversion";
import Filter from "../components/graphing/Filter"
+import OrganizationSidebar from '../components/OrganizationSidebar';
import {
Organisation,
@@ -69,50 +70,54 @@ function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) {
}
return (
- <Container>
- <Row>
- <Col xs={9}>
- <Row>
- <h3>NREN Suborganisations</h3>
- </Row>
- <Row>
- <Table>
- <thead>
- <tr>
- <th>NREN</th>
- <th>Year</th>
- <th>Suborganisation</th>
- <th>Role</th>
- </tr>
- </thead>
- <tbody>
- {Array.from(organisationDataset).sort().map(([_, nrenEntry]) => (
- Array.from(nrenEntry).sort().map(([_, nrenDataList], yearIndex) => (
- nrenDataList.sort(sortOrganisation).map((nrenData, nrenDataIndex) => (
- <tr key={nrenData.nren + nrenData.year + nrenData.name}>
- <td>{yearIndex == 0 && nrenDataIndex == 0 && nrenData.nren}</td>
- <td>{nrenDataIndex == 0 && nrenData.year}</td>
- <td>{nrenData.name}</td>
- <td>{nrenData.role}</td>
- </tr>
- ))
- )
- )
+ <>
+ <OrganizationSidebar />
+ <Container>
+ <Row>
+ <Col xs={9}>
+ <Row>
+ <h3>NREN Suborganisations</h3>
+ </Row>
+ <Row>
+ <Table>
+ <thead>
+ <tr>
+ <th>NREN</th>
+ <th>Year</th>
+ <th>Suborganisation</th>
+ <th>Role</th>
+ </tr>
+ </thead>
+ <tbody>
+ {Array.from(organisationDataset).sort().map(([_, nrenEntry]) => (
+ Array.from(nrenEntry).sort().map(([_, nrenDataList], yearIndex) => (
+ nrenDataList.sort(sortOrganisation).map((nrenData, nrenDataIndex) => (
+ <tr key={nrenData.nren + nrenData.year + nrenData.name}>
+ <td>{yearIndex == 0 && nrenDataIndex == 0 && nrenData.nren}</td>
+ <td>{nrenDataIndex == 0 && nrenData.year}</td>
+ <td>{nrenData.name}</td>
+ <td>{nrenData.role}</td>
+ </tr>
+ ))
+ )
+ )
+
+ ))}
+ </tbody>
+ </Table>
+ </Row>
+ </Col>
+ <Col xs={3}>
+ <Filter
+ filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
+ filterSelection={filterSelection}
+ setFilterSelection={setFilterSelection}
+ />
+ </Col>
+ </Row>
+ </Container>
+ </>
- ))}
- </tbody>
- </Table>
- </Row>
- </Col>
- <Col xs={3}>
- <Filter
- filterOptions={{ availableYears: [...years], availableNrens: [...nrens] }}
- filterSelection={filterSelection}
- setFilterSelection={setFilterSelection}
- />
- </Col>
- </Row>
- </Container>
);
}
export default SubOrganisation;
diff --git a/webapp/src/scss/layout/Sidebar.scss b/webapp/src/scss/layout/Sidebar.scss
new file mode 100644
index 00000000..f98618c4
--- /dev/null
+++ b/webapp/src/scss/layout/Sidebar.scss
@@ -0,0 +1,31 @@
+.sidebar-wrapper {
+ display: flex;
+ position: fixed;
+ top: calc(50vh - 10%);
+
+ .menu-items {
+ padding: 10px;
+ }
+}
+
+.sidebar-wrapper>nav {
+ transition: 0.25s;
+ // transition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
+ transition-property: margin-left;
+ margin-left: 0;
+ background-color: #fff;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
+
+ a {
+ text-decoration: none;
+ }
+
+ a:hover {
+ background-color: $yellow-orange;
+ text-decoration: none;
+ }
+}
+
+nav.no-sidebar {
+ margin-left: -79%;
+}
\ No newline at end of file
diff --git a/webapp/src/scss/layout/_components.scss b/webapp/src/scss/layout/_components.scss
index 04c4ae23..3239df40 100644
--- a/webapp/src/scss/layout/_components.scss
+++ b/webapp/src/scss/layout/_components.scss
@@ -1,4 +1,5 @@
@import '../abstracts/variables';
+@import '../layout/Sidebar';
.rounded-border {
border-radius: 25px;
--
GitLab