Skip to content
Snippets Groups Projects
Select Git revision
  • 5cb65eee5f23ae45bdadc2905a7dc34b7d2e5129
  • develop default protected
  • master protected
  • feature/POL1-813-error-report-sensu-check
  • 0.23
  • 0.22
  • 0.21
  • 0.20
  • 0.19
  • 0.18
  • 0.17
  • 0.16
  • 0.15
  • 0.14
  • 0.13
  • 0.12
  • 0.11
  • 0.10
  • 0.9
  • 0.8
  • 0.7
  • 0.6
  • 0.5
  • 0.4
24 results

sensu.py

Blame
  • StaffGraph.tsx 6.53 KiB
    import React, { useEffect, useMemo, useState } from 'react';
    import { Bar } from 'react-chartjs-2';
    import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js';
    
    import { NrenStaff, FilterSelection } from "../Schema";
    import { createNRENStaffDataset, getYearsAndNrens, loadDataWithFilterSelectionFallback } from "../helpers/dataconversion";
    import DataPage from '../components/DataPage';
    import Filter from "../components/graphing/Filter"
    import {ExportType, Sections} from '../helpers/constants';
    import WithLegend from '../components/WithLegend';
    import htmlLegendPlugin from '../plugins/HTMLLegendPlugin';
    import {Row} from "react-bootstrap";
    import DownloadDataButton from "../components/DownloadDataButton";
    
    ChartJS.register(
        CategoryScale,
        LinearScale,
        BarElement,
        Title,
        Tooltip,
        Legend
    );
    
    const chartOptions = {
        maintainAspectRatio: false,
        animation: {
            duration: 0
        },
        plugins: {
            htmlLegend: {
                // ID of the container(s) to put the legend in
                containerIDs: ['legendtop', 'legendbottom'],
            },
            legend: {
                display: false,
            },
            tooltip: {
                callbacks: {
                    label: function (tooltipItem) {
                        let label = tooltipItem.dataset.label || '';
    
                        if (tooltipItem.parsed.x !== null) {
                            label += `: ${tooltipItem.parsed.x}%`
                        }
                        return label;
                    }
                },
    
            },
        },
        scales: {
            x: {
                position: 'top' as const,
                stacked: true,
                ticks: {
                    callback: (value: string | number, index: number) => {
                        return `${index * 10}%`;
                    },
                },
            },
            x2: {
                ticks: {
                    callback: (value: string | number) => {
                        if (typeof value === 'number') {
                            return `${value}%`;
                        }
                        return value;
                    },
                },
                grid: {
                    drawOnChartArea: false
                },
                afterDataLimits: function (axis) {
                    const indices = Object.keys(ChartJS.instances)
    
                    // initial values should be far outside possible range
                    let max = -999999
                    let min = 999999
    
                    for (const index of indices) {
                        if (ChartJS.instances[index] && axis.chart.scales.x2) {
                            min = Math.min(ChartJS.instances[index].scales.x.min, min);
                            max = Math.max(ChartJS.instances[index].scales.x.max, max);
                        }
                    }
    
                    axis.chart.scales.x2.options.min = min;
                    axis.chart.scales.x2.options.max = max;
                    axis.chart.scales.x2.min = min;
                    axis.chart.scales.x2.max = max;
                },
            },
            y: {
                stacked: true,
                ticks: {
                    autoSkip: false,
                },
            },
        },
        indexAxis: "y" as const
    };
    
    interface inputProps {
        filterSelection: FilterSelection
        setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>>
        roles?: boolean
    }
    
    function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inputProps) {
        const [staffData, setStaffData] = useState<NrenStaff[]>([]);
    
        const { years, nrens } = useMemo(
            () => getYearsAndNrens(staffData),
            [staffData]
        );
        const nrenStaffDataset = createNRENStaffDataset(staffData, roles, filterSelection.selectedYears[0]);
    
        nrenStaffDataset.datasets.forEach(dataset => {
            dataset.hidden = !filterSelection.selectedYears.includes(parseInt(dataset.stack));
        });
    
        // remove the datapoints and labels for the nrens that aren't selected
        // unfortunately we cannot just hide them because graph.js doesn't want
        // to create a stack from a single dataset
        nrenStaffDataset.datasets.forEach(dataset => {
            dataset.data = dataset.data.filter((e, i) => {
                return filterSelection.selectedNrens.includes(nrenStaffDataset.labels[i]);
            });
        });
        nrenStaffDataset.labels = nrenStaffDataset.labels.filter((e) => filterSelection.selectedNrens.includes(e));
    
        useEffect(() => {
            loadDataWithFilterSelectionFallback('/api/staff/', setStaffData, setFilterSelection);
        }, [setFilterSelection]);
    
        const filterNode = <Filter
            max1year
            filterOptions={{ availableYears: [...years], availableNrens: [...nrens.values()] }}
            filterSelection={filterSelection}
            setFilterSelection={setFilterSelection}
        />
    
        const numNrens = filterSelection.selectedNrens.length;
        const heightPerBar = 1.5; // every added bar should give this much additional height
    
        // set a minimum height of 20rem
        const height = Math.max(numNrens * heightPerBar, 20);
    
        const title = roles
        ? "Roles of NREN employees"
        : "Types of employment for NRENs";
        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" : "types_of_employment_for_nrens";
        return (
            <DataPage title={title} 
            description={description}
            category={Sections.Organisation} filter={filterNode}>
                <>
                    <Row>
                        <DownloadDataButton data={staffData} filename={filename} exportType={ExportType.CSV}/>
                        <DownloadDataButton data={staffData} filename={filename} exportType={ExportType.EXCEL}/>
                    </Row>
                    <WithLegend>
                        <div className="chart-container" style={{'height': `${height}rem`}}>
                            <Bar
                                data={nrenStaffDataset}
                                options={chartOptions}
                                plugins={[htmlLegendPlugin]}
                            />
                        </div>
                    </WithLegend>
                </>
            </DataPage>
        );
    }
    export default StaffGraph;