Skip to content

Commit

Permalink
[ML] Adding filter bar to jobs list (elastic#20415)
Browse files Browse the repository at this point in the history
* [ML] Adding filter bar to jobs list

* fixing page index when filtering

* refreshing job selection after actions have happened

* adding job counts to groups

* catching multi-select start datafeed errors

* style tweaks

* more style tweaks

* changes based on review

* refactoring search logic
  • Loading branch information
jgowdyelastic committed Jul 4, 2018
1 parent 1002aed commit d65ae02
Show file tree
Hide file tree
Showing 15 changed files with 365 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export class JobDetails extends Component {

this.state = {
description: '',
groups: [],
selectedGroups: [],
mml: '',
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/


export { JobFilterBar } from './job_filter_bar';
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/


import PropTypes from 'prop-types';
import React, {
Component
} from 'react';

import { ml } from 'plugins/ml/services/ml_api_service';
import { JobGroup } from '../job_group';

import './styles/main.less';

import {
EuiSearchBar,
} from '@elastic/eui';

function loadGroups() {
return ml.jobs.groups()
.then((groups) => {
return groups.map(g => ({
value: g.id,
view: (
<div className="group-item">
<JobGroup name={g.id} /> <span>({g.jobIds.length} job{(g.jobIds.length === 1) ? '' : 's'})</span>
</div>
)
}));
})
.catch((error) => {
console.log(error);
return [];
});
}

export class JobFilterBar extends Component {
constructor(props) {
super(props);

this.setFilters = props.setFilters;
}

onChange = ({ query }) => {
const clauses = query.ast.clauses;
this.setFilters(clauses);
};

render() {
const filters = [
{
type: 'field_value_toggle_group',
field: 'job_state',
items: [
{
value: 'opened',
name: 'Opened'
},
{
value: 'closed',
name: 'Closed'
},
{
value: 'failed',
name: 'Failed'
}
]
},
{
type: 'field_value_toggle_group',
field: 'datafeed_state',
items: [
{
value: 'started',
name: 'Started'
},
{
value: 'stopped',
name: 'Stopped'
}
]
},
{
type: 'field_value_selection',
field: 'groups',
name: 'Group',
multiSelect: 'or',
cache: 10000,
options: () => loadGroups()
}

];

return (
<EuiSearchBar
box={{
incremental: true,
}}
filters={filters}
onChange={this.onChange}
/>
);
}
}
JobFilterBar.propTypes = {
setFilters: PropTypes.func.isRequired,
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.euiFilterGroup {
max-width: 500px;

.euiPopover .euiPanel {
.group-item {
padding: 6px 12px;
}

.inline-group {
border: 1px solid #FFFFFF;
border-radius: 3px;
}

.euiFilterSelectItem:hover, .euiFilterSelectItem:focus {
text-decoration: none;
.inline-group {
border: 1px solid #555555;
box-shadow: 0px 1px 2px #999;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/


export { JobGroup } from './job_group';
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/


import PropTypes from 'prop-types';
import React from 'react';

import './styles/main.less';

const COLORS = [
'#00B3A4', // euiColorVis0
'#3185FC', // euiColorVis1
'#DB1374', // euiColorVis2
'#490092', // euiColorVis3
// '#FEB6DB', // euiColorVis4 light pink, too hard to read with white text
'#E6C220', // euiColorVis5
'#BFA180', // euiColorVis6
'#F98510', // euiColorVis7
'#461A0A', // euiColorVis8
'#920000', // euiColorVis9

'#666666', // euiColorDarkShade
'#0079A5', // euiColorPrimary
];

const colorMap = {};

export function JobGroup({ name }) {
return (
<div
className="inline-group"
style={{ backgroundColor: tabColor(name) }}
>
{name}
</div>
);
}
JobGroup.propTypes = {
name: PropTypes.string.isRequired,
};

// to ensure the same color is always used for a group name
// the color choice is based on a hash of the group name
function tabColor(name) {
if (colorMap[name] === undefined) {
const n = stringHash(name);
const color = COLORS[(n % COLORS.length)];
colorMap[name] = color;
return color;
} else {
return colorMap[name];
}
}

function stringHash(str) {
let hash = 0;
let chr = '';
if (str.length === 0) {
return hash;
}
for (let i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
return hash < 0 ? hash * -2 : hash;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.inline-group {
font-size: 12px;
background-color: #D9D9D9;
padding: 2px 5px;
border-radius: 2px;
display: inline-block;
margin: 0px 3px;
color: #FFFFFF;
vertical-align: text-top;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,7 @@
import PropTypes from 'prop-types';
import React from 'react';

const COLORS = [
'#00B3A4', // euiColorVis0
'#3185FC', // euiColorVis1
'#DB1374', // euiColorVis2
'#490092', // euiColorVis3
// '#FEB6DB', // euiColorVis4 light pink, too hard to read with white text
'#E6C220', // euiColorVis5
'#BFA180', // euiColorVis6
'#F98510', // euiColorVis7
'#461A0A', // euiColorVis8
'#920000', // euiColorVis9

'#666666', // euiColorDarkShade
'#0079A5', // euiColorPrimary
];

const colorMap = {};
import { JobGroup } from '../job_group';

export function JobDescription({ job }) {
return (
Expand All @@ -42,44 +26,3 @@ export function JobDescription({ job }) {
JobDescription.propTypes = {
job: PropTypes.object.isRequired,
};

function JobGroup({ name }) {
return (
<div
className="inline-group"
style={{ backgroundColor: tabColor(name) }}
>
{name}
</div>
);
}
JobGroup.propTypes = {
name: PropTypes.string.isRequired,
};

// to ensure the same color is always used for a group name
// the color choice is based on a hash of the group name
function tabColor(name) {
if (colorMap[name] === undefined) {
const n = stringHash(name);
const color = COLORS[(n % COLORS.length)];
colorMap[name] = color;
return color;
} else {
return colorMap[name];
}
}

function stringHash(str) {
let hash = 0;
let chr = '';
if (str.length === 0) {
return hash;
}
for (let i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
return hash < 0 ? hash * -2 : hash;
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,18 @@ export class JobsList extends Component {
list = sortBy(this.state.jobsSummaryList, (item) => item[sortField]);
list = (sortDirection === 'asc') ? list : list.reverse();

const pageStart = (index * size);
let pageStart = (index * size);
if (pageStart >= list.length) {
// if the page start is larger than the number of items
// due to filters being applied, calculate a new page start
pageStart = Math.floor(list.length / size) * size;
// set the state out of the render cycle
setTimeout(() => {
this.setState({
pageIndex: (pageStart / size)
});
}, 0);
}
return {
pageOfItems: list.slice(pageStart, (pageStart + size)),
totalItemCount: list.length,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,6 @@
display: inline-block;
}

.inline-group {
font-size: 12px;
background-color: #D9D9D9;
padding: 2px 5px;
border-radius: 2px;
display: inline-block;
margin: 0px 3px;
color: #FFFFFF;
vertical-align: text-top;
}

.job-loading-spinner {
text-align: center;
}
Expand Down
Loading

0 comments on commit d65ae02

Please sign in to comment.