parent
809ed940e6
commit
f618901048
@ -0,0 +1,11 @@
|
||||
import { AppSectionItemState } from 'App/State/AppSectionState';
|
||||
import { Filter } from 'App/State/AppState';
|
||||
import { IndexerStats } from 'typings/IndexerStats';
|
||||
|
||||
export interface IndexerStatsAppState
|
||||
extends AppSectionItemState<IndexerStats> {
|
||||
selectedFilterKey: string;
|
||||
filters: Filter[];
|
||||
}
|
||||
|
||||
export default IndexerStatsAppState;
|
@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'cell': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
@ -1,25 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import TableRowCell from './TableRowCell';
|
||||
import styles from './TableRowCellButton.css';
|
||||
|
||||
function TableRowCellButton({ className, ...otherProps }) {
|
||||
return (
|
||||
<Link
|
||||
className={className}
|
||||
component={TableRowCell}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
TableRowCellButton.propTypes = {
|
||||
className: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
TableRowCellButton.defaultProps = {
|
||||
className: styles.cell
|
||||
};
|
||||
|
||||
export default TableRowCellButton;
|
@ -0,0 +1,19 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import Link, { LinkProps } from 'Components/Link/Link';
|
||||
import TableRowCell from './TableRowCell';
|
||||
import styles from './TableRowCellButton.css';
|
||||
|
||||
interface TableRowCellButtonProps extends LinkProps {
|
||||
className?: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
function TableRowCellButton(props: TableRowCellButtonProps) {
|
||||
const { className = styles.cell, ...otherProps } = props;
|
||||
|
||||
return (
|
||||
<Link className={className} component={TableRowCell} {...otherProps} />
|
||||
);
|
||||
}
|
||||
|
||||
export default TableRowCellButton;
|
@ -0,0 +1,275 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import AppState from 'App/State/AppState';
|
||||
import IndexerStatsAppState from 'App/State/IndexerStatsAppState';
|
||||
import Alert from 'Components/Alert';
|
||||
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 PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import { align, kinds } from 'Helpers/Props';
|
||||
import {
|
||||
fetchIndexerStats,
|
||||
setIndexerStatsFilter,
|
||||
} from 'Store/Actions/indexerStatsActions';
|
||||
import {
|
||||
IndexerStatsHost,
|
||||
IndexerStatsIndexer,
|
||||
IndexerStatsUserAgent,
|
||||
} from 'typings/IndexerStats';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import IndexerStatsFilterMenu from './IndexerStatsFilterMenu';
|
||||
import styles from './IndexerStats.css';
|
||||
|
||||
function getAverageResponseTimeData(indexerStats: IndexerStatsIndexer[]) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.indexerName,
|
||||
value: indexer.averageResponseTime,
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getFailureRateData(indexerStats: IndexerStatsIndexer[]) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.indexerName,
|
||||
value:
|
||||
(indexer.numberOfFailedQueries +
|
||||
indexer.numberOfFailedRssQueries +
|
||||
indexer.numberOfFailedAuthQueries +
|
||||
indexer.numberOfFailedGrabs) /
|
||||
(indexer.numberOfQueries +
|
||||
indexer.numberOfRssQueries +
|
||||
indexer.numberOfAuthQueries +
|
||||
indexer.numberOfGrabs),
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getTotalRequestsData(indexerStats: IndexerStatsIndexer[]) {
|
||||
const data = {
|
||||
labels: indexerStats.map((indexer) => indexer.indexerName),
|
||||
datasets: [
|
||||
{
|
||||
label: translate('SearchQueries'),
|
||||
data: indexerStats.map((indexer) => indexer.numberOfQueries),
|
||||
},
|
||||
{
|
||||
label: translate('RssQueries'),
|
||||
data: indexerStats.map((indexer) => indexer.numberOfRssQueries),
|
||||
},
|
||||
{
|
||||
label: translate('AuthQueries'),
|
||||
data: indexerStats.map((indexer) => indexer.numberOfAuthQueries),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getNumberGrabsData(indexerStats: IndexerStatsIndexer[]) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.indexerName,
|
||||
value: indexer.numberOfGrabs - indexer.numberOfFailedGrabs,
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getUserAgentGrabsData(indexerStats: IndexerStatsUserAgent[]) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.userAgent ? indexer.userAgent : 'Other',
|
||||
value: indexer.numberOfGrabs,
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getUserAgentQueryData(indexerStats: IndexerStatsUserAgent[]) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.userAgent ? indexer.userAgent : 'Other',
|
||||
value: indexer.numberOfQueries,
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getHostGrabsData(indexerStats: IndexerStatsHost[]) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.host ? indexer.host : 'Other',
|
||||
value: indexer.numberOfGrabs,
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getHostQueryData(indexerStats: IndexerStatsHost[]) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.host ? indexer.host : 'Other',
|
||||
value: indexer.numberOfQueries,
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const indexerStatsSelector = () => {
|
||||
return createSelector(
|
||||
(state: AppState) => state.indexerStats,
|
||||
(indexerStats: IndexerStatsAppState) => {
|
||||
return indexerStats;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
function IndexerStats() {
|
||||
const { isFetching, isPopulated, item, error, filters, selectedFilterKey } =
|
||||
useSelector(indexerStatsSelector());
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchIndexerStats());
|
||||
}, [dispatch]);
|
||||
|
||||
const onFilterSelect = useCallback(
|
||||
(value: string) => {
|
||||
dispatch(setIndexerStatsFilter({ selectedFilterKey: value }));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const isLoaded = !error && isPopulated;
|
||||
|
||||
return (
|
||||
<PageContent>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection alignContent={align.RIGHT} collapseButtons={false}>
|
||||
<IndexerStatsFilterMenu
|
||||
selectedFilterKey={selectedFilterKey}
|
||||
filters={filters}
|
||||
onFilterSelect={onFilterSelect}
|
||||
isDisabled={false}
|
||||
/>
|
||||
</PageToolbarSection>
|
||||
</PageToolbar>
|
||||
<PageContentBody>
|
||||
{isFetching && !isPopulated && <LoadingIndicator />}
|
||||
|
||||
{!isFetching && !!error && (
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{getErrorMessage(error, 'Failed to load indexer stats from API')}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{isLoaded && (
|
||||
<div>
|
||||
<div className={styles.fullWidthChart}>
|
||||
<BarChart
|
||||
data={getAverageResponseTimeData(item.indexers)}
|
||||
title={translate('AverageResponseTimesMs')}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.fullWidthChart}>
|
||||
<BarChart
|
||||
data={getFailureRateData(item.indexers)}
|
||||
title={translate('IndexerFailureRate')}
|
||||
kind={kinds.WARNING}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<StackedBarChart
|
||||
data={getTotalRequestsData(item.indexers)}
|
||||
title={translate('TotalIndexerQueries')}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<BarChart
|
||||
data={getNumberGrabsData(item.indexers)}
|
||||
title={translate('TotalIndexerSuccessfulGrabs')}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<BarChart
|
||||
data={getUserAgentQueryData(item.userAgents)}
|
||||
title={translate('TotalUserAgentQueries')}
|
||||
horizontal={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<BarChart
|
||||
data={getUserAgentGrabsData(item.userAgents)}
|
||||
title={translate('TotalUserAgentGrabs')}
|
||||
horizontal={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<DoughnutChart
|
||||
data={getHostQueryData(item.hosts)}
|
||||
title={translate('TotalHostQueries')}
|
||||
horizontal={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<DoughnutChart
|
||||
data={getHostGrabsData(item.hosts)}
|
||||
title={translate('TotalHostGrabs')}
|
||||
horizontal={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default IndexerStats;
|
@ -0,0 +1,27 @@
|
||||
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;
|
@ -1,261 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
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 PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import { align, kinds } from 'Helpers/Props';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import StatsFilterMenu from './StatsFilterMenu';
|
||||
import styles from './Stats.css';
|
||||
|
||||
function getAverageResponseTimeData(indexerStats) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.indexerName,
|
||||
value: indexer.averageResponseTime
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getFailureRateData(indexerStats) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.indexerName,
|
||||
value: (indexer.numberOfFailedQueries + indexer.numberOfFailedRssQueries + indexer.numberOfFailedAuthQueries + indexer.numberOfFailedGrabs) /
|
||||
(indexer.numberOfQueries + indexer.numberOfRssQueries + indexer.numberOfAuthQueries + indexer.numberOfGrabs)
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getTotalRequestsData(indexerStats) {
|
||||
const data = {
|
||||
labels: indexerStats.map((indexer) => indexer.indexerName),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Search Queries',
|
||||
data: indexerStats.map((indexer) => indexer.numberOfQueries)
|
||||
},
|
||||
{
|
||||
label: 'Rss Queries',
|
||||
data: indexerStats.map((indexer) => indexer.numberOfRssQueries)
|
||||
},
|
||||
{
|
||||
label: 'Auth Queries',
|
||||
data: indexerStats.map((indexer) => indexer.numberOfAuthQueries)
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getNumberGrabsData(indexerStats) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.indexerName,
|
||||
value: indexer.numberOfGrabs - indexer.numberOfFailedGrabs
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getUserAgentGrabsData(indexerStats) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.userAgent ? indexer.userAgent : 'Other',
|
||||
value: indexer.numberOfGrabs
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getUserAgentQueryData(indexerStats) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.userAgent ? indexer.userAgent : 'Other',
|
||||
value: indexer.numberOfQueries
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getHostGrabsData(indexerStats) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.host ? indexer.host : 'Other',
|
||||
value: indexer.numberOfGrabs
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function getHostQueryData(indexerStats) {
|
||||
const data = indexerStats.map((indexer) => {
|
||||
return {
|
||||
label: indexer.host ? indexer.host : 'Other',
|
||||
value: indexer.numberOfQueries
|
||||
};
|
||||
});
|
||||
|
||||
data.sort((a, b) => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function Stats(props) {
|
||||
const {
|
||||
item,
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
filters,
|
||||
selectedFilterKey,
|
||||
onFilterSelect
|
||||
} = props;
|
||||
|
||||
const isLoaded = !!(!error && isPopulated);
|
||||
|
||||
return (
|
||||
<PageContent>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection
|
||||
alignContent={align.RIGHT}
|
||||
collapseButtons={false}
|
||||
>
|
||||
<StatsFilterMenu
|
||||
selectedFilterKey={selectedFilterKey}
|
||||
filters={filters}
|
||||
onFilterSelect={onFilterSelect}
|
||||
isDisabled={false}
|
||||
/>
|
||||
</PageToolbarSection>
|
||||
</PageToolbar>
|
||||
<PageContentBody>
|
||||
{
|
||||
isFetching && !isPopulated &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{getErrorMessage(error, 'Failed to load indexer stats from API')}
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
isLoaded &&
|
||||
<div>
|
||||
<div className={styles.fullWidthChart}>
|
||||
<BarChart
|
||||
data={getAverageResponseTimeData(item.indexers)}
|
||||
title={translate('AverageResponseTimesMs')}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.fullWidthChart}>
|
||||
<BarChart
|
||||
data={getFailureRateData(item.indexers)}
|
||||
title={translate('IndexerFailureRate')}
|
||||
kind={kinds.WARNING}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<StackedBarChart
|
||||
data={getTotalRequestsData(item.indexers)}
|
||||
title={translate('TotalIndexerQueries')}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<BarChart
|
||||
data={getNumberGrabsData(item.indexers)}
|
||||
title={translate('TotalIndexerSuccessfulGrabs')}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<BarChart
|
||||
data={getUserAgentQueryData(item.userAgents)}
|
||||
title={translate('TotalUserAgentQueries')}
|
||||
horizontal={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<BarChart
|
||||
data={getUserAgentGrabsData(item.userAgents)}
|
||||
title={translate('TotalUserAgentGrabs')}
|
||||
horizontal={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<DoughnutChart
|
||||
data={getHostQueryData(item.hosts)}
|
||||
title={translate('TotalHostQueries')}
|
||||
horizontal={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.halfWidthChart}>
|
||||
<DoughnutChart
|
||||
data={getHostGrabsData(item.hosts)}
|
||||
title={translate('TotalHostGrabs')}
|
||||
horizontal={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
||||
Stats.propTypes = {
|
||||
item: PropTypes.object.isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
selectedFilterKey: PropTypes.string.isRequired,
|
||||
onFilterSelect: PropTypes.func.isRequired,
|
||||
error: PropTypes.object,
|
||||
data: PropTypes.object
|
||||
};
|
||||
|
||||
export default Stats;
|
@ -1,51 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchIndexerStats, setIndexerStatsFilter } from 'Store/Actions/indexerStatsActions';
|
||||
import Stats from './Stats';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.indexerStats,
|
||||
(indexerStats) => indexerStats
|
||||
);
|
||||
}
|
||||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
onFilterSelect(selectedFilterKey) {
|
||||
dispatch(setIndexerStatsFilter({ selectedFilterKey }));
|
||||
},
|
||||
dispatchFetchIndexerStats() {
|
||||
dispatch(fetchIndexerStats());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class StatsConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatchFetchIndexerStats();
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Stats
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
StatsConnector.propTypes = {
|
||||
dispatchFetchIndexerStats: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(StatsConnector);
|
@ -1,37 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import FilterMenu from 'Components/Menu/FilterMenu';
|
||||
import { align } from 'Helpers/Props';
|
||||
|
||||
function StatsFilterMenu(props) {
|
||||
const {
|
||||
selectedFilterKey,
|
||||
filters,
|
||||
isDisabled,
|
||||
onFilterSelect
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FilterMenu
|
||||
alignMenu={align.RIGHT}
|
||||
isDisabled={isDisabled}
|
||||
selectedFilterKey={selectedFilterKey}
|
||||
filters={filters}
|
||||
customFilters={[]}
|
||||
onFilterSelect={onFilterSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
StatsFilterMenu.propTypes = {
|
||||
selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
isDisabled: PropTypes.bool.isRequired,
|
||||
onFilterSelect: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
StatsFilterMenu.defaultProps = {
|
||||
showCustomFilters: false
|
||||
};
|
||||
|
||||
export default StatsFilterMenu;
|
@ -1,24 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import FilterModal from 'Components/Filter/FilterModal';
|
||||
import { setIndexerStatsFilter } from 'Store/Actions/indexerStatsActions';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.indexerStats.items,
|
||||
(state) => state.indexerStats.filterBuilderProps,
|
||||
(sectionItems, filterBuilderProps) => {
|
||||
return {
|
||||
sectionItems,
|
||||
filterBuilderProps,
|
||||
customFilterType: 'indexerStats'
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchSetFilter: setIndexerStatsFilter
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(FilterModal);
|
@ -0,0 +1,31 @@
|
||||
export interface IndexerStatsIndexer {
|
||||
indexerId: number;
|
||||
indexerName: string;
|
||||
averageResponseTime: number;
|
||||
numberOfQueries: number;
|
||||
numberOfGrabs: number;
|
||||
numberOfRssQueries: number;
|
||||
numberOfAuthQueries: number;
|
||||
numberOfFailedQueries: number;
|
||||
numberOfFailedGrabs: number;
|
||||
numberOfFailedRssQueries: number;
|
||||
numberOfFailedAuthQueries: number;
|
||||
}
|
||||
|
||||
export interface IndexerStatsUserAgent {
|
||||
userAgent: string;
|
||||
numberOfQueries: number;
|
||||
numberOfGrabs: number;
|
||||
}
|
||||
|
||||
export interface IndexerStatsHost {
|
||||
host: string;
|
||||
numberOfQueries: number;
|
||||
numberOfGrabs: number;
|
||||
}
|
||||
|
||||
export interface IndexerStats {
|
||||
indexers: IndexerStatsIndexer[];
|
||||
userAgents: IndexerStatsUserAgent[];
|
||||
hosts: IndexerStatsHost[];
|
||||
}
|
Loading…
Reference in new issue