mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[ML] Add button for refreshing job list without full page refresh. (#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
This commit is contained in:
parent
688795f166
commit
36025138ea
7 changed files with 128 additions and 114 deletions
|
@ -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;
|
||||
|
@ -33,6 +42,7 @@ export class JobsListView extends Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
isRefreshing: false,
|
||||
jobsSummaryList: [],
|
||||
filteredJobsSummaryList: [],
|
||||
fullJobsList: {},
|
||||
|
@ -204,7 +214,6 @@ export class JobsListView extends Component {
|
|||
return this.showCreateWatchFlyout;
|
||||
}
|
||||
|
||||
|
||||
selectJobChange = (selectedJobs) => {
|
||||
this.setState({ selectedJobs });
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -246,12 +263,13 @@ 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);
|
||||
|
@ -259,7 +277,7 @@ export class JobsListView extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
renderJobsListComponents() {
|
||||
const jobIds = this.state.jobsSummaryList.map(j => j.id);
|
||||
return (
|
||||
<div>
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -8,3 +8,15 @@
|
|||
& > div:nth-child(2) {
|
||||
}
|
||||
}
|
||||
|
||||
.job-management {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.job-buttons-container {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
@ -76,46 +74,20 @@ Stat.propTypes = {
|
|||
stat: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export class JobStatsBar extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
jobsSummaryList: [],
|
||||
jobStats: {},
|
||||
};
|
||||
}
|
||||
export const JobStatsBar = ({ jobsSummaryList }) => {
|
||||
const jobStats = createJobStats(jobsSummaryList);
|
||||
const stats = Object.keys(jobStats).map(k => jobStats[k]);
|
||||
|
||||
updateJobStats = (jobsSummaryList) => {
|
||||
const jobStats = createJobStats(jobsSummaryList);
|
||||
this.setState({
|
||||
jobsSummaryList,
|
||||
jobStats,
|
||||
});
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.setUpdateJobStats(this.updateJobStats);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.unsetUpdateJobStats();
|
||||
}
|
||||
|
||||
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,
|
||||
return (
|
||||
<div className="jobs-stats-bar">
|
||||
{
|
||||
stats.filter(s => (s.show)).map(s => <Stat key={s.label} stat={s} />)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
JobStatsBar.propTypes = {
|
||||
jobsSummaryList: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
|
|
|
@ -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';
|
|
@ -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
|
||||
};
|
|
@ -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, {
|
||||
Component
|
||||
} from 'react';
|
||||
|
||||
import {
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
export class JobsPage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
jobsSummaryList: [],
|
||||
updateJobStats: () => {},
|
||||
};
|
||||
}
|
||||
export const JobsPage = () => (
|
||||
<JobsListView />
|
||||
);
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
.job-management {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.new-job-button-container {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue