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

added csv download functionality to pages

parent 4639b876
Branches
Tags
1 merge request!60added csv download functionality to pages
Showing with 180 additions and 93 deletions
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 ExternalPageNavBar from "./shared/ExternalPageNavBar";
import GeantFooter from "./components/global/GeantFooter";
......
......@@ -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 {
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 {
}
});
const budgetAPIResponse = {
return {
datasets: sets,
labels: labelsYear.map(year => year.toString())
}
return budgetAPIResponse;
};
}
......
......@@ -7,6 +7,7 @@ import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter";
import LineGraph from "../components/graphing/LineGraph";
import { Sections } from '../helpers/constants';
import DownloadCSVButton from "../components/DownloadCSVButton";
interface inputProps {
filterSelection: FilterSelection
......@@ -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
fluctuation of budget over years and with other NRENs.' category={Sections.Organisation} filter={filterNode}>
<>
<Row>
<DownloadCSVButton data={budgetResponse} filename="budget_data.csv"/>
</Row>
<Row>
<LineGraph data={budgetData} />
</Row>
......
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 { ChargingStructure, FilterSelection } from "../Schema";
......@@ -8,6 +8,7 @@ import ColorPill from "../components/ColorPill";
import DataPage from "../components/DataPage";
import Filter from "../components/graphing/Filter";
import { Sections } from "../helpers/constants";
import DownloadCSVButton from "../components/DownloadCSVButton";
ChartJS.register(
......@@ -50,46 +51,51 @@ function ChargingStructurePage({ filterSelection, setFilterSelection }: inputPro
/>
return (
<DataPage title="Charging Mechanism of NRENs per Year"
<DataPage title="Charging Mechanism of NRENs per Year"
description="The charging structure is the way in which NRENs charge their customers for the services they provide.
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."
category={Sections.Organisation} filter={filterNode}>
<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 >
<>
<Row>
<DownloadCSVButton data={chargingStructureData} filename="charging_mechanism_of_nrens_per_year.csv"/>
</Row>
<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>Combination flat fee & usage basedfee</th>
<th>No Direct Charge</th>
<th>Other</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
{Array.from(dataLookup.entries()).map(([nren, nrenMap]) => (
<tr key={nren}>
<td>{nren}</td>
{["flat_fee", "usage_based_fee", "combination", "no_charge", "other"].map(discriminator => (
<td key={discriminator}>
{Array.from(nrenMap.entries()).map(([year, chargingMechanism]) => (
<ColorPill key={year} year={year} active={chargingMechanism == discriminator} />
))}
</td>
))}
</tr>
))}
</tbody>
<tr key={nren}>
<td>{nren}</td>
{["flat_fee", "usage_based_fee", "combination", "no_charge", "other"].map(discriminator => (
<td key={discriminator}>
{Array.from(nrenMap.entries()).map(([year, chargingMechanism]) => (
<ColorPill key={year} year={year} active={chargingMechanism == discriminator}/>
))}
</td>
))}
</tr>
))}
</tbody>
</Table>
</Table>
</>
</DataPage>
);
}
......
import React, { useEffect, useMemo, useState } from 'react';
import { Table } from "react-bootstrap";
import {Row, Table} from "react-bootstrap";
import { ECProject, FilterSelection } from "../Schema";
import { createECProjectsDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from '../helpers/dataconversion';
import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants';
import DownloadCSVButton from "../components/DownloadCSVButton";
interface inputProps {
......@@ -59,18 +60,23 @@ function ECProjects({ filterSelection, setFilterSelection }: inputProps) {
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'
category={Sections.Organisation} filter={filterNode}>
<Table borderless className='compendium-table'>
<thead>
<>
<Row>
<DownloadCSVButton data={projectData} filename="nren_involvement_in_european_commission_projects.csv"/>
</Row>
<Table borderless className='compendium-table'>
<thead>
<tr>
<th className='nren-column'>NREN</th>
<th className='year-column'>Year</th>
<th className='blue-column'>EC Project Membership</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
{getJSXFromMap(projectDataByYear)}
</tbody>
</Table>
</tbody>
</Table>
</>
</DataPage>
)
}
......
......@@ -10,6 +10,7 @@ import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants';
import ColorBadge from '../components/ColorBadge';
import DownloadCSVButton from "../components/DownloadCSVButton";
export const chartOptions = {
maintainAspectRatio: false,
......@@ -150,21 +151,26 @@ function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps)
const height = numNrens * numYears * heightPerBar + 5;
return (
<DataPage title="Income Source Of NRENs per Year"
description='The graph shows the percentage share of their income that individual NRENs derived from different sources.
description='The graph shows the percentage share of their income that individual NRENs derived from different sources.
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.'
category={Sections.Organisation} filter={filterNode}>
<div>
<FundingSourceLegend />
<div className="chart-container" style={{ 'height': `${height}rem` }}>
<Bar
plugins={[ChartDataLabels]}
data={fundingSourceDataset}
options={chartOptions}
/>
</div>
<FundingSourceLegend />
</div>
<>
<Row>
<DownloadCSVButton data={fundingSourceData} filename="income_source_of_nren_per_year.csv"/>
</Row>
<div>
<FundingSourceLegend/>
<div className="chart-container" style={{'height': `${height}rem`}}>
<Bar
plugins={[ChartDataLabels]}
data={fundingSourceDataset}
options={chartOptions}
/>
</div>
<FundingSourceLegend/>
</div>
</>
</DataPage>
);
}
......
import React, { useEffect, useMemo, useState } from 'react';
import { Table } from "react-bootstrap";
import {Row, Table} from "react-bootstrap";
import { Organisation, FilterSelection } from "../Schema";
import { createOrganisationDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion";
import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants';
import DownloadCSVButton from "../components/DownloadCSVButton";
function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) {
......@@ -54,18 +55,23 @@ function ParentOrganisation({ filterSelection, setFilterSelection }: inputProps)
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.'
category={Sections.Organisation} filter={filterNode}>
<Table borderless className='compendium-table'>
<thead>
<>
<Row>
<DownloadCSVButton data={organisationData} filename="nren_parent_organisations.csv"/>
</Row>
<Table borderless className='compendium-table'>
<thead>
<tr>
<th className='nren-column'>NREN</th>
<th className='year-column'>Year</th>
<th className='blue-column'>Parent Organisation</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
{getJSXFromMap(organisationDataset)}
</tbody>
</Table>
</tbody>
</Table>
</>
</DataPage>
);
......
......@@ -9,6 +9,8 @@ import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants';
import WithLegend from '../components/WithLegend';
import htmlLegendPlugin from '../plugins/HTMLLegendPlugin';
import {Row} from "react-bootstrap";
import DownloadCSVButton from "../components/DownloadCSVButton";
ChartJS.register(
CategoryScale,
......@@ -150,20 +152,26 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu
const description = roles
? "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.";
const filename = roles ? "roles_of_nren_employees.csv" : "types_of_employment_for_nren.csv";
return (
<DataPage title={title}
description={description}
category={Sections.Organisation} filter={filterNode}>
<WithLegend>
<div className="chart-container" style={{ 'height': `${height}rem` }}>
<Bar
data={nrenStaffDataset}
options={chartOptions}
plugins={[htmlLegendPlugin]}
/>
</div>
</WithLegend>
<>
<Row>
<DownloadCSVButton data={staffData} filename={filename}/>
</Row>
<WithLegend>
<div className="chart-container" style={{'height': `${height}rem`}}>
<Bar
data={nrenStaffDataset}
options={chartOptions}
plugins={[htmlLegendPlugin]}
/>
</div>
</WithLegend>
</>
</DataPage>
);
}
......
import React, { useEffect, useMemo, useState } from 'react';
import { Table } from "react-bootstrap";
import {Row, Table} from "react-bootstrap";
import { Organisation, FilterSelection } from "../Schema";
import { createOrganisationDataLookup, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion";
import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants';
import DownloadCSVButton from "../components/DownloadCSVButton";
function getJSXFromMap(data: Map<string, Map<number, Organisation[]>>) {
......@@ -55,22 +56,27 @@ function SubOrganisation({ filterSelection, setFilterSelection }: inputProps) {
/>
return (
<DataPage title="NREN Suborganisations"
description='The table shows the NRENs suborganisations. You can select multiple years and NRENs to get a
<DataPage title="NREN Suborganisations"
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.'
category={Sections.Organisation} filter={filterNode}>
<Table borderless className='compendium-table'>
<thead>
<>
<Row>
<DownloadCSVButton data={organisationData} filename="nren_suborganisations.csv"/>
</Row>
<Table borderless className='compendium-table'>
<thead>
<tr>
<th className='nren-column'>NREN</th>
<th className='year-column'>Year</th>
<th className='blue-column'>Suborganisation and Role</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
{getJSXFromMap(organisationDataset)}
</tbody>
</Table>
</tbody>
</Table>
</>
</DataPage>
);
}
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment