Skip to content
Snippets Groups Projects
Commit ffd9a43c authored by Mohammad Torkashvand's avatar Mohammad Torkashvand :wolf:
Browse files

added csv download functionality to pages

parent 4639b876
No related branches found
No related tags found
1 merge request!60added csv download functionality to pages
Showing with 180 additions and 93 deletions
import React, { ReactElement, useState } from "react"; import React, { ReactElement, useState } from "react";
import { BrowserRouter as Router, Routes, Route, useNavigate } from "react-router-dom"; import { BrowserRouter as Router, Routes, Route,} from "react-router-dom";
import Landing from "./pages/Landing"; import Landing from "./pages/Landing";
import ExternalPageNavBar from "./shared/ExternalPageNavBar"; import ExternalPageNavBar from "./shared/ExternalPageNavBar";
import GeantFooter from "./components/global/GeantFooter"; import GeantFooter from "./components/global/GeantFooter";
... ...
......
...@@ -82,19 +82,6 @@ export interface FundingSourceDataset { ...@@ -82,19 +82,6 @@ export interface FundingSourceDataset {
}[] }[]
} }
export interface ChargingStructureDataset {
labels: string[],
datasets: {
label: string,
data: { x: number | null; y: number | null; }[],
borderRadius: number,
borderSkipped: boolean,
barPercentage: number,
borderWidth: number,
categoryPercentage: number,
}[]
}
export interface NrenStaffDataset { export interface NrenStaffDataset {
labels: string[], labels: string[],
... ...
......
import React from 'react';
interface DownloadCSVProps {
data: any[];
filename?: string;
}
function createCSVRows(jsonData: any[], header: string[]): string[] {
return jsonData.map(obj => {
return header.map(fieldName => {
const value = obj[fieldName];
if (value === null) {
return "";
}
// Always wrap strings in double quotes and escape internal double quotes
if (typeof value === 'string') {
return `"${value.replace(/"/g, '""')}"`;
}
return value;
}).join(',');
});
}
function convertToCSV(jsonData: any[]): string {
if (!jsonData.length) return "";
const header = Object.keys(jsonData[0]);
const rows = createCSVRows(jsonData, header);
// Combine header and rows with newline characters
return [header.join(','), ...rows].join('\r\n');
}
const DownloadCSVButton: React.FC<DownloadCSVProps> = ({ data, filename = 'data.csv' }) => {
const downloadCSV = () => {
const csv = convertToCSV(data);
const blob = new Blob([csv], { type: 'text/csv' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
return (
<>
<button onClick={downloadCSV}>Download CSV</button>
</>
);
}
export default DownloadCSVButton;
...@@ -188,12 +188,10 @@ export function createBudgetDataset(budgetEntries: Budget[]): BasicDataset { ...@@ -188,12 +188,10 @@ export function createBudgetDataset(budgetEntries: Budget[]): BasicDataset {
} }
}); });
const budgetAPIResponse = { return {
datasets: sets, datasets: sets,
labels: labelsYear.map(year => year.toString()) labels: labelsYear.map(year => year.toString())
} };
return budgetAPIResponse;
} }
... ...
......
...@@ -7,6 +7,7 @@ import DataPage from '../components/DataPage'; ...@@ -7,6 +7,7 @@ import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter"; import Filter from "../components/graphing/Filter";
import LineGraph from "../components/graphing/LineGraph"; import LineGraph from "../components/graphing/LineGraph";
import { Sections } from '../helpers/constants'; import { Sections } from '../helpers/constants';
import DownloadCSVButton from "../components/DownloadCSVButton";
interface inputProps { interface inputProps {
filterSelection: FilterSelection filterSelection: FilterSelection
...@@ -44,6 +45,9 @@ function BudgetPage({ filterSelection, setFilterSelection }: inputProps): ReactE ...@@ -44,6 +45,9 @@ function BudgetPage({ filterSelection, setFilterSelection }: inputProps): ReactE
On hovering over the graphs data points will give NRENs budget share in that year. This graph can be used to compare, selecting multiple NRENs to see the On hovering over the graphs data points will give NRENs budget share in that year. This graph can be used to compare, selecting multiple NRENs to see the
fluctuation of budget over years and with other NRENs.' category={Sections.Organisation} filter={filterNode}> fluctuation of budget over years and with other NRENs.' category={Sections.Organisation} filter={filterNode}>
<> <>
<Row>
<DownloadCSVButton data={budgetResponse} filename="budget_data.csv"/>
</Row>
<Row> <Row>
<LineGraph data={budgetData} /> <LineGraph data={budgetData} />
</Row> </Row>
... ...
......
import React, { useMemo, useState } from "react"; import React, { useMemo, useState } from "react";
import { Table } from "react-bootstrap"; import {Row, Table} from "react-bootstrap";
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js'; import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js';
import { ChargingStructure, FilterSelection } from "../Schema"; import { ChargingStructure, FilterSelection } from "../Schema";
...@@ -8,6 +8,7 @@ import ColorPill from "../components/ColorPill"; ...@@ -8,6 +8,7 @@ import ColorPill from "../components/ColorPill";
import DataPage from "../components/DataPage"; import DataPage from "../components/DataPage";
import Filter from "../components/graphing/Filter"; import Filter from "../components/graphing/Filter";
import { Sections } from "../helpers/constants"; import { Sections } from "../helpers/constants";
import DownloadCSVButton from "../components/DownloadCSVButton";
ChartJS.register( ChartJS.register(
...@@ -55,6 +56,10 @@ function ChargingStructurePage({ filterSelection, setFilterSelection }: inputPro ...@@ -55,6 +56,10 @@ function ChargingStructurePage({ filterSelection, setFilterSelection }: inputPro
The charging structure can be based on a flat fee, usage based fee, a combination of both, or no direct charge. The charging structure can be based on a flat fee, usage based fee, a combination of both, or no direct charge.
By selecting multiple years and NRENs, the table can be used to compare the charging structure of NRENs." By selecting multiple years and NRENs, the table can be used to compare the charging structure of NRENs."
category={Sections.Organisation} filter={filterNode}> category={Sections.Organisation} filter={filterNode}>
<>
<Row>
<DownloadCSVButton data={chargingStructureData} filename="charging_mechanism_of_nrens_per_year.csv"/>
</Row>
<Table className="charging-struct-table" striped bordered responsive> <Table className="charging-struct-table" striped bordered responsive>
<colgroup> <colgroup>
<col span={1} style={{width: "10%"}}/> <col span={1} style={{width: "10%"}}/>
...@@ -90,6 +95,7 @@ function ChargingStructurePage({ filterSelection, setFilterSelection }: inputPro ...@@ -90,6 +95,7 @@ function ChargingStructurePage({ filterSelection, setFilterSelection }: inputPro
</tbody> </tbody>
</Table> </Table>
</>
</DataPage> </DataPage>
); );
} }
... ...
......
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { Table } from "react-bootstrap"; import {Row, Table} from "react-bootstrap";
import { ECProject, FilterSelection } from "../Schema"; import { ECProject, FilterSelection } from "../Schema";
import { createECProjectsDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from '../helpers/dataconversion'; import { createECProjectsDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from '../helpers/dataconversion';
import DataPage from '../components/DataPage'; import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants'; import { Sections } from '../helpers/constants';
import DownloadCSVButton from "../components/DownloadCSVButton";
interface inputProps { interface inputProps {
...@@ -59,6 +60,10 @@ function ECProjects({ filterSelection, setFilterSelection }: inputProps) { ...@@ -59,6 +60,10 @@ function ECProjects({ filterSelection, setFilterSelection }: inputProps) {
description='The table shows the NRENs involvement in European Commission Projects Membership. By selecting multiple description='The table shows the NRENs involvement in European Commission Projects Membership. By selecting multiple
year and NRENs, the table can be used to compare the NRENs involvement in European Commission Projects Membership' year and NRENs, the table can be used to compare the NRENs involvement in European Commission Projects Membership'
category={Sections.Organisation} filter={filterNode}> category={Sections.Organisation} filter={filterNode}>
<>
<Row>
<DownloadCSVButton data={projectData} filename="nren_involvement_in_european_commission_projects.csv"/>
</Row>
<Table borderless className='compendium-table'> <Table borderless className='compendium-table'>
<thead> <thead>
<tr> <tr>
...@@ -71,6 +76,7 @@ function ECProjects({ filterSelection, setFilterSelection }: inputProps) { ...@@ -71,6 +76,7 @@ function ECProjects({ filterSelection, setFilterSelection }: inputProps) {
{getJSXFromMap(projectDataByYear)} {getJSXFromMap(projectDataByYear)}
</tbody> </tbody>
</Table> </Table>
</>
</DataPage> </DataPage>
) )
} }
... ...
......
...@@ -10,6 +10,7 @@ import DataPage from '../components/DataPage'; ...@@ -10,6 +10,7 @@ import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants'; import { Sections } from '../helpers/constants';
import ColorBadge from '../components/ColorBadge'; import ColorBadge from '../components/ColorBadge';
import DownloadCSVButton from "../components/DownloadCSVButton";
export const chartOptions = { export const chartOptions = {
maintainAspectRatio: false, maintainAspectRatio: false,
...@@ -154,6 +155,10 @@ function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps) ...@@ -154,6 +155,10 @@ function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps)
On hovering over the graphs will give income share in that year. This can be used to compare selecting multiple years to see how the On hovering over the graphs will give income share in that year. This can be used to compare selecting multiple years to see how the
share has changed between the years.' share has changed between the years.'
category={Sections.Organisation} filter={filterNode}> category={Sections.Organisation} filter={filterNode}>
<>
<Row>
<DownloadCSVButton data={fundingSourceData} filename="income_source_of_nren_per_year.csv"/>
</Row>
<div> <div>
<FundingSourceLegend/> <FundingSourceLegend/>
<div className="chart-container" style={{'height': `${height}rem`}}> <div className="chart-container" style={{'height': `${height}rem`}}>
...@@ -165,6 +170,7 @@ function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps) ...@@ -165,6 +170,7 @@ function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps)
</div> </div>
<FundingSourceLegend/> <FundingSourceLegend/>
</div> </div>
</>
</DataPage> </DataPage>
); );
} }
... ...
......
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { Table } from "react-bootstrap"; import {Row, Table} from "react-bootstrap";
import { Organisation, FilterSelection } from "../Schema"; import { Organisation, FilterSelection } from "../Schema";
import { createOrganisationDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion"; import { createOrganisationDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion";
import DataPage from '../components/DataPage'; import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants'; import { Sections } from '../helpers/constants';
import DownloadCSVButton from "../components/DownloadCSVButton";
function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) { function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) {
...@@ -54,6 +55,10 @@ function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps) ...@@ -54,6 +55,10 @@ function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps)
description='The table shows the NRENs parent organisation. You can select only one year at a time description='The table shows the NRENs parent organisation. You can select only one year at a time
and multiple NRENs. This table can be used to compare the parent organisation of NRENs.' and multiple NRENs. This table can be used to compare the parent organisation of NRENs.'
category={Sections.Organisation} filter={filterNode}> category={Sections.Organisation} filter={filterNode}>
<>
<Row>
<DownloadCSVButton data={organisationData} filename="nren_parent_organisations.csv"/>
</Row>
<Table borderless className='compendium-table'> <Table borderless className='compendium-table'>
<thead> <thead>
<tr> <tr>
...@@ -66,6 +71,7 @@ function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps) ...@@ -66,6 +71,7 @@ function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps)
{getJSXFromMap(organisationDataset)} {getJSXFromMap(organisationDataset)}
</tbody> </tbody>
</Table> </Table>
</>
</DataPage> </DataPage>
); );
... ...
......
...@@ -9,6 +9,8 @@ import Filter from "../components/graphing/Filter" ...@@ -9,6 +9,8 @@ import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants'; import { Sections } from '../helpers/constants';
import WithLegend from '../components/WithLegend'; import WithLegend from '../components/WithLegend';
import htmlLegendPlugin from '../plugins/HTMLLegendPlugin'; import htmlLegendPlugin from '../plugins/HTMLLegendPlugin';
import {Row} from "react-bootstrap";
import DownloadCSVButton from "../components/DownloadCSVButton";
ChartJS.register( ChartJS.register(
CategoryScale, CategoryScale,
...@@ -151,10 +153,15 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu ...@@ -151,10 +153,15 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu
? "The graph shows the roles of NREN employees. On hovering over the graph will give the percentage of employees in that role. This graph can be used to compare, selecting multiple NRENs to see the fluctuation of roles over selected year and with other NRENs." ? "The graph shows the roles of NREN employees. On hovering over the graph will give the percentage of employees in that role. This graph can be used to compare, selecting multiple NRENs to see the fluctuation of roles over selected year and with other NRENs."
: "The graph shows the types of employment for NREN employees. On hovering over the graphs will give the percentage of employees in that type of employment. This graph can be used to compare, selecting multiple NRENs to see the fluctuation of types of employment over selected year and with other NRENs."; : "The graph shows the types of employment for NREN employees. On hovering over the graphs will give the percentage of employees in that type of employment. This graph can be used to compare, selecting multiple NRENs to see the fluctuation of types of employment over selected year and with other NRENs.";
const filename = roles ? "roles_of_nren_employees.csv" : "types_of_employment_for_nren.csv";
return ( return (
<DataPage title={title} <DataPage title={title}
description={description} description={description}
category={Sections.Organisation} filter={filterNode}> category={Sections.Organisation} filter={filterNode}>
<>
<Row>
<DownloadCSVButton data={staffData} filename={filename}/>
</Row>
<WithLegend> <WithLegend>
<div className="chart-container" style={{'height': `${height}rem`}}> <div className="chart-container" style={{'height': `${height}rem`}}>
<Bar <Bar
...@@ -164,6 +171,7 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu ...@@ -164,6 +171,7 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu
/> />
</div> </div>
</WithLegend> </WithLegend>
</>
</DataPage> </DataPage>
); );
} }
... ...
......
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { Table } from "react-bootstrap"; import {Row, Table} from "react-bootstrap";
import { Organisation, FilterSelection } from "../Schema"; import { Organisation, FilterSelection } from "../Schema";
import { createOrganisationDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion"; import { createOrganisationDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion";
import DataPage from '../components/DataPage'; import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter" import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants'; import { Sections } from '../helpers/constants';
import DownloadCSVButton from "../components/DownloadCSVButton";
function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) { function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) {
...@@ -59,6 +60,10 @@ function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) { ...@@ -59,6 +60,10 @@ function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) {
description='The table shows the NRENs suborganisations. You can select multiple years and NRENs to get a description='The table shows the NRENs suborganisations. You can select multiple years and NRENs to get a
tabular view of NRENs suborganisations over the years.' tabular view of NRENs suborganisations over the years.'
category={Sections.Organisation} filter={filterNode}> category={Sections.Organisation} filter={filterNode}>
<>
<Row>
<DownloadCSVButton data={organisationData} filename="nren_suborganisations.csv"/>
</Row>
<Table borderless className='compendium-table'> <Table borderless className='compendium-table'>
<thead> <thead>
<tr> <tr>
...@@ -71,6 +76,7 @@ function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) { ...@@ -71,6 +76,7 @@ function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) {
{getJSXFromMap(organisationDataset)} {getJSXFromMap(organisationDataset)}
</tbody> </tbody>
</Table> </Table>
</>
</DataPage> </DataPage>
); );
} }
... ...
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment