New: Custom Filters for Stats

This commit is contained in:
Qstick
2023-09-03 10:56:43 -05:00
parent c873b3ffac
commit b608e38454
12 changed files with 214 additions and 97 deletions
+8 -3
View File
@@ -1,20 +1,25 @@
.fullWidthChart {
display: inline-block;
padding: 15px 25px;
width: 100%;
height: 300px;
}
.halfWidthChart {
display: inline-block;
padding: 15px 25px;
width: 50%;
}
.chartContainer {
margin: 5px;
padding: 15px 25px;
height: 300px;
border-radius: 10px;
background-color: var(--chartBackgroundColor);
}
@media only screen and (max-width: $breakpointSmall) {
.halfWidthChart {
display: inline-block;
margin: 5px;
padding: 15px 25px;
width: 100%;
height: 300px;
+1
View File
@@ -1,6 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'chartContainer': string;
'fullWidthChart': string;
'halfWidthChart': string;
}
+75 -43
View File
@@ -8,6 +8,7 @@ import BarChart from 'Components/Chart/BarChart';
import DoughnutChart from 'Components/Chart/DoughnutChart';
import StackedBarChart from 'Components/Chart/StackedBarChart';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
@@ -17,6 +18,7 @@ import {
fetchIndexerStats,
setIndexerStatsFilter,
} from 'Store/Actions/indexerStatsActions';
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
import {
IndexerStatsHost,
IndexerStatsIndexer,
@@ -24,7 +26,7 @@ import {
} from 'typings/IndexerStats';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import IndexerStatsFilterMenu from './IndexerStatsFilterMenu';
import IndexerStatsFilterModal from './IndexerStatsFilterModal';
import styles from './IndexerStats.css';
function getAverageResponseTimeData(indexerStats: IndexerStatsIndexer[]) {
@@ -165,15 +167,26 @@ function getHostQueryData(indexerStats: IndexerStatsHost[]) {
const indexerStatsSelector = () => {
return createSelector(
(state: AppState) => state.indexerStats,
(indexerStats: IndexerStatsAppState) => {
return indexerStats;
createCustomFiltersSelector('indexerStats'),
(indexerStats: IndexerStatsAppState, customFilters) => {
return {
...indexerStats,
customFilters,
};
}
);
};
function IndexerStats() {
const { isFetching, isPopulated, item, error, filters, selectedFilterKey } =
useSelector(indexerStatsSelector());
const {
isFetching,
isPopulated,
item,
error,
filters,
customFilters,
selectedFilterKey,
} = useSelector(indexerStatsSelector());
const dispatch = useDispatch();
useEffect(() => {
@@ -193,10 +206,13 @@ function IndexerStats() {
<PageContent>
<PageToolbar>
<PageToolbarSection alignContent={align.RIGHT} collapseButtons={false}>
<IndexerStatsFilterMenu
<FilterMenu
alignMenu={align.RIGHT}
selectedFilterKey={selectedFilterKey}
filters={filters}
customFilters={customFilters}
onFilterSelect={onFilterSelect}
filterModalConnectorComponent={IndexerStatsFilterModal}
isDisabled={false}
/>
</PageToolbarSection>
@@ -213,57 +229,73 @@ function IndexerStats() {
{isLoaded && (
<div>
<div className={styles.fullWidthChart}>
<BarChart
data={getAverageResponseTimeData(item.indexers)}
title={translate('AverageResponseTimesMs')}
/>
<div className={styles.chartContainer}>
<BarChart
data={getAverageResponseTimeData(item.indexers)}
title={translate('AverageResponseTimesMs')}
/>
</div>
</div>
<div className={styles.fullWidthChart}>
<BarChart
data={getFailureRateData(item.indexers)}
title={translate('IndexerFailureRate')}
kind={kinds.WARNING}
/>
<div className={styles.chartContainer}>
<BarChart
data={getFailureRateData(item.indexers)}
title={translate('IndexerFailureRate')}
kind={kinds.WARNING}
/>
</div>
</div>
<div className={styles.halfWidthChart}>
<StackedBarChart
data={getTotalRequestsData(item.indexers)}
title={translate('TotalIndexerQueries')}
/>
<div className={styles.chartContainer}>
<StackedBarChart
data={getTotalRequestsData(item.indexers)}
title={translate('TotalIndexerQueries')}
/>
</div>
</div>
<div className={styles.halfWidthChart}>
<BarChart
data={getNumberGrabsData(item.indexers)}
title={translate('TotalIndexerSuccessfulGrabs')}
/>
<div className={styles.chartContainer}>
<BarChart
data={getNumberGrabsData(item.indexers)}
title={translate('TotalIndexerSuccessfulGrabs')}
/>
</div>
</div>
<div className={styles.halfWidthChart}>
<BarChart
data={getUserAgentQueryData(item.userAgents)}
title={translate('TotalUserAgentQueries')}
horizontal={true}
/>
<div className={styles.chartContainer}>
<BarChart
data={getUserAgentQueryData(item.userAgents)}
title={translate('TotalUserAgentQueries')}
horizontal={true}
/>
</div>
</div>
<div className={styles.halfWidthChart}>
<BarChart
data={getUserAgentGrabsData(item.userAgents)}
title={translate('TotalUserAgentGrabs')}
horizontal={true}
/>
<div className={styles.chartContainer}>
<BarChart
data={getUserAgentGrabsData(item.userAgents)}
title={translate('TotalUserAgentGrabs')}
horizontal={true}
/>
</div>
</div>
<div className={styles.halfWidthChart}>
<DoughnutChart
data={getHostQueryData(item.hosts)}
title={translate('TotalHostQueries')}
horizontal={true}
/>
<div className={styles.chartContainer}>
<DoughnutChart
data={getHostQueryData(item.hosts)}
title={translate('TotalHostQueries')}
horizontal={true}
/>
</div>
</div>
<div className={styles.halfWidthChart}>
<DoughnutChart
data={getHostGrabsData(item.hosts)}
title={translate('TotalHostGrabs')}
horizontal={true}
/>
<div className={styles.chartContainer}>
<DoughnutChart
data={getHostGrabsData(item.hosts)}
title={translate('TotalHostGrabs')}
horizontal={true}
/>
</div>
</div>
</div>
)}
@@ -1,27 +0,0 @@
import React from 'react';
import FilterMenu from 'Components/Menu/FilterMenu';
import { align } from 'Helpers/Props';
interface IndexerStatsFilterMenuProps {
selectedFilterKey: string | number;
filters: object[];
isDisabled: boolean;
onFilterSelect(filterName: string): unknown;
}
function IndexerStatsFilterMenu(props: IndexerStatsFilterMenuProps) {
const { selectedFilterKey, filters, isDisabled, onFilterSelect } = props;
return (
<FilterMenu
alignMenu={align.RIGHT}
isDisabled={isDisabled}
selectedFilterKey={selectedFilterKey}
filters={filters}
customFilters={[]}
onFilterSelect={onFilterSelect}
/>
);
}
export default IndexerStatsFilterMenu;
@@ -0,0 +1,56 @@
import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import FilterModal from 'Components/Filter/FilterModal';
import { setIndexerStatsFilter } from 'Store/Actions/indexerStatsActions';
function createIndexerStatsSelector() {
return createSelector(
(state: AppState) => state.indexerStats.item,
(indexerStats) => {
return indexerStats;
}
);
}
function createFilterBuilderPropsSelector() {
return createSelector(
(state: AppState) => state.indexerStats.filterBuilderProps,
(filterBuilderProps) => {
return filterBuilderProps;
}
);
}
interface IndexerStatsFilterModalProps {
isOpen: boolean;
}
export default function IndexerStatsFilterModal(
props: IndexerStatsFilterModalProps
) {
const sectionItems = [useSelector(createIndexerStatsSelector())];
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
const customFilterType = 'indexerStats';
const dispatch = useDispatch();
const dispatchSetFilter = useCallback(
(payload: unknown) => {
dispatch(setIndexerStatsFilter(payload));
},
[dispatch]
);
return (
<FilterModal
// TODO: Don't spread all the props
{...props}
sectionItems={sectionItems}
filterBuilderProps={filterBuilderProps}
customFilterType={customFilterType}
dispatchSetFilter={dispatchSetFilter}
/>
);
}