Skip to content

Commit

Permalink
[ML] Add button for refreshing job list without full page refresh. (e…
Browse files Browse the repository at this point in the history
…lastic#24084)

* Add refresh button for job list

* Show load icon while refreshing

* Move view build logic to jobsListView

* Align job action buttons in ui

* Extract RefreshJobsListButton component

* update jobStatsBar to take list as prop
  • Loading branch information
alvarezmelissa87 committed Oct 18, 2018
1 parent 691f6c4 commit 1a73029
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,21 @@ import { DeleteJobModal } from '../delete_job_modal';
import { StartDatafeedModal } from '../start_datafeed_modal';
import { CreateWatchFlyout } from '../create_watch_flyout';
import { MultiJobActions } from '../multi_job_actions';
import { NewJobButton } from '../new_job_button';
import { JobStatsBar } from '../jobs_stats_bar';
import { NodeAvailableWarning } from '../node_available_warning';
import { RefreshJobsListButton } from '../refresh_jobs_list_button';

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

import {
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
} from '@elastic/eui';

const DEFAULT_REFRESH_INTERVAL_MS = 30000;
const MINIMUM_REFRESH_INTERVAL_MS = 5000;
let jobsRefreshInterval = null;
Expand All @@ -33,6 +42,7 @@ export class JobsListView extends Component {
super(props);

this.state = {
isRefreshing: false,
jobsSummaryList: [],
filteredJobsSummaryList: [],
fullJobsList: {},
Expand Down Expand Up @@ -204,7 +214,6 @@ export class JobsListView extends Component {
return this.showCreateWatchFlyout;
}


selectJobChange = (selectedJobs) => {
this.setState({ selectedJobs });
}
Expand All @@ -229,6 +238,14 @@ export class JobsListView extends Component {
});
}

onRefreshClick = () => {
this.setState({ isRefreshing: true });
this.refreshJobSummaryList(true);
}
isDoneRefreshing = () => {
this.setState({ isRefreshing: false });
}

refreshJobSummaryList(forceRefresh = false) {
if (forceRefresh === true || this.blockRefresh === false) {
const expandedJobsIds = Object.keys(this.state.itemIdToExpandedRowMap);
Expand All @@ -246,20 +263,21 @@ export class JobsListView extends Component {
const filteredJobsSummaryList = filterJobs(jobsSummaryList, this.state.filterClauses);
this.setState({ jobsSummaryList, filteredJobsSummaryList, fullJobsList }, () => {
this.refreshSelectedJobs();
this.props.updateJobStats(jobsSummaryList);
});

Object.keys(this.updateFunctions).forEach((j) => {
this.updateFunctions[j].setState({ job: fullJobsList[j] });
});

this.isDoneRefreshing();
})
.catch((error) => {
console.error(error);
});
}
}

render() {
renderJobsListComponents() {
const jobIds = this.state.jobsSummaryList.map(j => j.id);
return (
<div>
Expand Down Expand Up @@ -310,7 +328,41 @@ export class JobsListView extends Component {
</div>
);
}

render() {
const { isRefreshing, jobsSummaryList } = this.state;

return (
<React.Fragment>
<JobStatsBar
jobsSummaryList={jobsSummaryList}
/>
<div className="job-management">
<NodeAvailableWarning />
<header>
<div className="job-buttons-container">
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<RefreshJobsListButton
onRefreshClick={this.onRefreshClick}
isRefreshing={isRefreshing}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<NewJobButton />
</EuiFlexItem>
</EuiFlexGroup>
</div>
</header>

<div className="clear" />

<EuiSpacer size="s" />

{ this.renderJobsListComponents() }
</ div>
</React.Fragment>
);
}
}
JobsListView.propTypes = {
updateJobStats: PropTypes.func.isRequired,
};

Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,15 @@
& > div:nth-child(2) {
}
}

.job-management {
padding: 20px;
}

.job-buttons-container {
float: right;
}

.clear {
clear: both;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import './styles/main.less';
import { JOB_STATE, DATAFEED_STATE } from 'plugins/ml/../common/constants/states';

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

function createJobStats(jobsSummaryList) {

Expand Down Expand Up @@ -76,46 +74,20 @@ Stat.propTypes = {
stat: PropTypes.object.isRequired,
};

export class JobStatsBar extends Component {
constructor(props) {
super(props);
this.state = {
jobsSummaryList: [],
jobStats: {},
};
}

updateJobStats = (jobsSummaryList) => {
const jobStats = createJobStats(jobsSummaryList);
this.setState({
jobsSummaryList,
jobStats,
});
};
export const JobStatsBar = ({ jobsSummaryList }) => {
const jobStats = createJobStats(jobsSummaryList);
const stats = Object.keys(jobStats).map(k => jobStats[k]);

componentDidMount() {
this.props.setUpdateJobStats(this.updateJobStats);
}

componentWillUnmount() {
this.props.unsetUpdateJobStats();
}
return (
<div className="jobs-stats-bar">
{
stats.filter(s => (s.show)).map(s => <Stat key={s.label} stat={s} />)
}
</div>
);
};

render() {
const { jobStats } = this.state;
const stats = Object.keys(jobStats).map(k => jobStats[k]);

return (
<div className="jobs-stats-bar">
{
stats.filter(s => (s.show)).map(s => <Stat key={s.label} stat={s} />)
}
</div>
);
}
}
JobStatsBar.propTypes = {
setUpdateJobStats: PropTypes.func.isRequired,
unsetUpdateJobStats: PropTypes.func.isRequired,
jobsSummaryList: PropTypes.array.isRequired,
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 { RefreshJobsListButton } from './refresh_jobs_list_button';
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 React from 'react';
import PropTypes from 'prop-types';

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


export const RefreshJobsListButton = ({ onRefreshClick, isRefreshing }) => (
<EuiButtonEmpty
onClick={onRefreshClick}
isLoading={isRefreshing}
>
Refresh
</EuiButtonEmpty>
);

RefreshJobsListButton.propTypes = {
onRefreshClick: PropTypes.func.isRequired,
isRefreshing: PropTypes.bool.isRequired
};
57 changes: 4 additions & 53 deletions x-pack/plugins/ml/public/jobs/jobs_list/jobs.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,11 @@
*/


import './styles/main.less';
import { NewJobButton } from './components/new_job_button';
import { JobsListView } from './components/jobs_list_view';
import { JobStatsBar } from './components/jobs_stats_bar';
import { NodeAvailableWarning } from './components/node_available_warning';
import React from 'react';

import React, {
Component
} from 'react';

import {
EuiSpacer,
} from '@elastic/eui';
export const JobsPage = () => (
<JobsListView />
);


export class JobsPage extends Component {
constructor(props) {
super(props);
this.state = {
jobsSummaryList: [],
updateJobStats: () => {},
};
}

setUpdateJobStats = (updateJobStats) => {
this.setState({ updateJobStats });
}

unsetUpdateJobStats = () => {
this.setUpdateJobStats(() => {});
}

render() {
return (
<React.Fragment>
<JobStatsBar
setUpdateJobStats={this.setUpdateJobStats}
unsetUpdateJobStats={this.unsetUpdateJobStats}
/>
<div className="job-management">
<NodeAvailableWarning />
<header>
<div className="new-job-button-container">
<NewJobButton />
</div>
</header>

<div className="clear" />

<EuiSpacer size="s" />

<JobsListView updateJobStats={this.state.updateJobStats} />
</div>
</React.Fragment>
);
}
}
11 changes: 0 additions & 11 deletions x-pack/plugins/ml/public/jobs/jobs_list/styles/main.less

This file was deleted.

0 comments on commit 1a73029

Please sign in to comment.