Skip to content

Commit

Permalink
GUI Runs info charts: top-N settings
Browse files Browse the repository at this point in the history
  • Loading branch information
rodichenko committed Jul 22, 2024
1 parent ede0df4 commit c95ef66
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 51 deletions.
156 changes: 113 additions & 43 deletions client/src/components/runs/runs-info/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {inject, observer} from 'mobx-react';
import {computed, observable} from 'mobx';
import {computed} from 'mobx';
import {
Select,
message,
Expand All @@ -33,17 +33,29 @@ import {
formatDockerImages,
formatDockerImage,
formatUserName,
extractDatasets
extractDatasets,
extractMaxEntriesCount
} from './utils';

const LABELS_THRESHOLD = 25;

function getTopEntriesFilters (maxEntriesCount = 0, thresholds = [10, 25, 50]) {
const filteredThresholds = thresholds.filter((tr) => maxEntriesCount > tr);
return [...filteredThresholds, undefined];
}

@inject('reportThemes', 'usersInfo')
@observer
class RunsInfo extends React.PureComponent {
@observable _filteredStatistics;
@observable _filtersConfiguration;
@observable _pending = false;
state = {
statistics: {},
pending: false,
filtersConfiguration: {},
filtersConfigurationPending: false,
maxEntries: 0,
topEntries: undefined,
topEntriesFilters: getTopEntriesFilters(0)
};

componentDidMount () {
(this.fetchFiltersConfiguration)();
Expand All @@ -56,19 +68,8 @@ class RunsInfo extends React.PureComponent {
}
}

@computed
get filtersConfiguration () {
return this._filtersConfiguration || {};
}

@computed
get filteredStatistics () {
return this._filteredStatistics || {};
}

@computed
get pending () {
return this._pending;
return this.state.pending;
}

@computed
Expand Down Expand Up @@ -102,27 +103,37 @@ class RunsInfo extends React.PureComponent {

fetchFiltersConfiguration = async () => {
const request = new RunsChartsInfo();
this._pending = true;
this.setState({
filtersConfigurationPending: true
});
await request.send({});
if (request.error) {
return message.error(request.error, 5);
this.setState({
filtersConfigurationPending: false
});
message.error(request.error, 5);
return;
}
this._filtersConfiguration = Object
.entries(request.value || {})
.reduce((acc, [key, value = {}]) => {
acc[key] = [...new Set([
...Object.keys(value.PAUSED || {}),
...Object.keys(value.RUNNING || {})
])];
return acc;
}, {});
this._pending = false;
this.setState({
filtersConfigurationPending: false,
filtersConfiguration: Object
.entries(request.value || {})
.reduce((acc, [key, value = {}]) => {
acc[key] = [...new Set([
...Object.keys(value.PAUSED || {}),
...Object.keys(value.RUNNING || {})
])];
return acc;
}, {})
});
};

fetchStatistics = async () => {
const {
filters = {}
} = this.props;
this._token = {};
const token = this._token;
const {
owners,
instanceTypes,
Expand All @@ -131,19 +142,44 @@ class RunsInfo extends React.PureComponent {
statuses
} = filters;
const request = new RunsChartsInfo();
this._pending = true;
await request.send({
owners,
instanceTypes,
tags,
dockerImages,
statuses
});
if (request.error) {
return message.error(request.error, 5);
}
this._filteredStatistics = request.value;
this._pending = false;
const commit = (fn) => {
if (token === this._token) {
fn();
}
};
const updateTopEntriesFilters = (statistics) => {
const max = extractMaxEntriesCount(statistics);
const filters = getTopEntriesFilters(max);
return {
maxEntries: max,
topEntries: filters[0],
topEntriesFilters: filters
};
};
commit(() => {
if (request.error) {
this.setState({
pending: false
});
message.error(request.error, 5);
return;
}
const _filteredStatistics = request.value;
this.setState({
statistics: _filteredStatistics || {},
...updateTopEntriesFilters(_filteredStatistics),
pending: false
}, () => {
console.log(this.state.maxEntries);
});
});
};

clearFilters = () => {
Expand All @@ -158,12 +194,26 @@ class RunsInfo extends React.PureComponent {
filters = {},
onFiltersChange
} = this.props;
const {
filtersConfiguration,
filtersConfigurationPending,
pending: dataPending,
topEntries,
topEntriesFilters
} = this.state;
const pending = dataPending || filtersConfigurationPending;
const {
owners = [],
dockerImages = [],
instanceTypes = [],
tags = []
} = this.filtersConfiguration;
} = filtersConfiguration;
const getTopValue = (top) => top ? `${top}` : 'all';
const getTopLabel = (top) => top ? `Display top ${top}` : 'Display all';
const parseTopValue = (topValue) => topValue === 'all' ? undefined : Number(topValue);
const onChangeTop = (value) => this.setState({
topEntries: parseTopValue(value)
});
const onChangeFilter = (filterKey) => (values) => {
if (typeof onFiltersChange === 'function') {
onFiltersChange({
Expand Down Expand Up @@ -261,12 +311,28 @@ class RunsInfo extends React.PureComponent {
Clear filters
</a>
) : null}
<Button
onClick={this.fetchStatistics}
style={{marginLeft: 'auto'}}
>
Refresh
</Button>
<div style={{marginLeft: 'auto'}}>
{topEntriesFilters.length > 1 && (
<Select
style={{minWidth: 200, marginLeft: 'auto'}}
value={getTopValue(topEntries)}
onChange={onChangeTop}
disabled={pending}
>
{topEntriesFilters.map((top) => (
<Select.Option key={getTopValue(top)} value={getTopValue(top)}>
{getTopLabel(top)}
</Select.Option>
))}
</Select>
)}
<Button
onClick={this.fetchStatistics}
style={{marginLeft: 5}}
>
Refresh
</Button>
</div>
</div>
);
};
Expand Down Expand Up @@ -295,12 +361,16 @@ class RunsInfo extends React.PureComponent {

render () {
const {reportThemes, className, style} = this.props;
const {
statistics,
topEntries
} = this.state;
const {
owners,
dockerImages,
instanceTypes,
tags
} = extractDatasets(this.filteredStatistics);
} = extractDatasets(statistics, topEntries);
const determineWidth = (labels = []) => labels.length > LABELS_THRESHOLD
? '100%'
: '50%';
Expand Down
40 changes: 32 additions & 8 deletions client/src/components/runs/runs-info/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ function getDatasetStyles (key, reportThemes, b) {
showDataLabel (item) {
return typeof item === 'number' && item !== 0;
},
maxBarThickness: 50
maxBarThickness: 50,
showFlag: false,
textColor: reportThemes.textColor,
};
if (key === 'RUNNING') {
return {
Expand Down Expand Up @@ -78,7 +80,7 @@ function formatUserName (user, users = []) {
return (userInstance ? getUserDisplayName(userInstance) : undefined) || user;
}

function extractDatasetByField (field, data = {}) {
function extractDatasetByField (field, data = {}, top = undefined) {
const dataField = data[field];
if (!dataField) {
return {
Expand All @@ -97,6 +99,7 @@ function extractDatasetByField (field, data = {}) {
value: getLabelSum(label)
}))
.sort((a, b) => b.value - a.value)
.filter((a, idx) => top === undefined || top > idx)
.map((a) => a.label);
const dataSets = categoriesKeys.reduce((acc, key) => ({
...acc,
Expand All @@ -108,20 +111,41 @@ function extractDatasetByField (field, data = {}) {
};
}

function extractDatasets (data = {}) {
function extractMaxEntriesCountByField (field, data = {}) {
const dataField = data[field];
if (!dataField) {
return 0;
}
return [...new Set(Object
.values(dataField)
.reduce((acc, cur) => [...acc, ...Object.keys(cur)], [])
)].length;
}

function extractDatasets (data = {}, top = undefined) {
return {
owners: extractDatasetByField('owners', data),
dockerImages: extractDatasetByField('dockerImages', data),
instanceTypes: extractDatasetByField('instanceTypes', data),
tags: extractDatasetByField('tags', data)
owners: extractDatasetByField('owners', data, top),
dockerImages: extractDatasetByField('dockerImages', data, top),
instanceTypes: extractDatasetByField('instanceTypes', data, top),
tags: extractDatasetByField('tags', data, top)
};
}

function extractMaxEntriesCount (data = {}) {
return Math.max(
extractMaxEntriesCountByField('owners', data),
extractMaxEntriesCountByField('dockerImages', data),
extractMaxEntriesCountByField('instanceTypes', data),
extractMaxEntriesCountByField('tags', data),
);
}

export {
getDatasetStyles,
STATUSES,
formatDockerImages,
formatDockerImage,
formatUserName,
extractDatasets
extractDatasets,
extractMaxEntriesCount
};

0 comments on commit c95ef66

Please sign in to comment.