diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.container.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.container.js index 95a48eabd3c70..2b1b0641c1528 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.container.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.container.js @@ -5,13 +5,23 @@ */ import { connect } from 'react-redux'; -import { JobActionMenu as JobActionMenuComponent } from './job_action_menu'; + +import { isUpdating } from '../../../store/selectors'; + import { startJobs, stopJobs, deleteJobs, } from '../../../store/actions'; +import { JobActionMenu as JobActionMenuComponent } from './job_action_menu'; + +const mapStateToProps = (state) => { + return { + isUpdating: isUpdating(state), + }; +}; + const mapDispatchToProps = (dispatch, { jobs }) => { const jobIds = jobs.map(job => job.id); return { @@ -27,4 +37,4 @@ const mapDispatchToProps = (dispatch, { jobs }) => { }; }; -export const JobActionMenu = connect(undefined, mapDispatchToProps)(JobActionMenuComponent); +export const JobActionMenu = connect(mapStateToProps, mapDispatchToProps)(JobActionMenuComponent); diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.js index 6e7a7de948d3d..acdd44882b9ca 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.js @@ -6,13 +6,17 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { injectI18n } from '@kbn/i18n/react'; +import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiContextMenu, + EuiFlexGroup, + EuiFlexItem, EuiIcon, + EuiLoadingSpinner, EuiPopover, + EuiText, } from '@elastic/eui'; import { ConfirmDeleteModal } from './confirm_delete_modal'; @@ -23,6 +27,7 @@ class JobActionMenuUi extends Component { startJobs: PropTypes.func.isRequired, stopJobs: PropTypes.func.isRequired, deleteJobs: PropTypes.func.isRequired, + isUpdating: PropTypes.bool.isRequired, iconSide: PropTypes.string, anchorPosition: PropTypes.string, label: PropTypes.node, @@ -89,19 +94,21 @@ class JobActionMenuUi extends Component { }); } - items.push({ - name: intl.formatMessage({ - id: 'xpack.rollupJobs.jobActionMenu.deleteJobLabel', - defaultMessage: 'Delete {isSingleSelection, plural, one {job} other {jobs}}', - }, { - isSingleSelection, - }), - icon: , - onClick: () => { - this.closePopover(); - this.openDeleteConfirmationModal(); - }, - }); + if (this.canDeleteJobs()) { + items.push({ + name: intl.formatMessage({ + id: 'xpack.rollupJobs.jobActionMenu.deleteJobLabel', + defaultMessage: 'Delete {isSingleSelection, plural, one {job} other {jobs}}', + }, { + isSingleSelection, + }), + icon: , + onClick: () => { + this.closePopover(); + this.openDeleteConfirmationModal(); + }, + }); + } const panelTree = { id: 0, @@ -145,6 +152,12 @@ class JobActionMenuUi extends Component { return jobs.some(job => job.status === 'started'); } + canDeleteJobs() { + const { jobs } = this.props; + const areAllJobsStopped = jobs.findIndex(job => job.status === 'started') === -1; + return areAllJobsStopped; + } + confirmDeleteModal = () => { const { showDeleteConfirmation } = this.state; @@ -179,7 +192,27 @@ class JobActionMenuUi extends Component { }; render() { - const { intl } = this.props; + const { intl, isUpdating } = this.props; + + if (isUpdating) { + return ( + + + + + + + + + + + + ); + } + const jobCount = this.props.jobs.length; const { diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_create/navigation/navigation.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/navigation/navigation.js index 94814bd0b5957..25d4968a44868 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_create/navigation/navigation.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/navigation/navigation.js @@ -6,6 +6,7 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, @@ -16,7 +17,7 @@ import { EuiLoadingSpinner, } from '@elastic/eui'; -export const Navigation = ({ +const NavigationUi = ({ isSaving, hasNextStep, hasPreviousStep, @@ -33,7 +34,12 @@ export const Navigation = ({ - Saving + + + ); @@ -47,7 +53,10 @@ export const Navigation = ({ iconType="arrowLeft" onClick={goToPreviousStep} > - Back + ); @@ -64,7 +73,10 @@ export const Navigation = ({ isDisabled={!canGoToNextStep} fill > - Next + ); @@ -77,7 +89,10 @@ export const Navigation = ({ onClick={save} fill > - Save + ); @@ -91,7 +106,7 @@ export const Navigation = ({ ); }; -Navigation.propTypes = { +NavigationUi.propTypes = { hasNextStep: PropTypes.bool.isRequired, hasPreviousStep: PropTypes.bool.isRequired, isSaving: PropTypes.bool.isRequired, @@ -100,3 +115,5 @@ Navigation.propTypes = { save: PropTypes.func.isRequired, canGoToNextStep: PropTypes.bool.isRequired, }; + +export const Navigation = injectI18n(NavigationUi); diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.container.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.container.js index b0281994b55a5..e728a58313a0c 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.container.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.container.js @@ -5,7 +5,6 @@ */ import { connect } from 'react-redux'; -import { JobList as JobListView } from './job_list'; import { getPageOfJobs, @@ -20,6 +19,8 @@ import { closeDetailPanel, } from '../../store/actions'; +import { JobList as JobListView } from './job_list'; + const mapStateToProps = (state) => { return { jobs: getPageOfJobs(state), diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js index 7c292181e76da..d9b4ce1bf5ba7 100644 --- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js @@ -87,6 +87,7 @@ export class JobListUi extends Component { // this page. this.props.closeDetailPanel(); } + getHeaderSection() { return ( @@ -101,6 +102,7 @@ export class JobListUi extends Component { ); } + renderNoPermission() { const { intl } = this.props; const title = intl.formatMessage({ @@ -124,10 +126,11 @@ export class JobListUi extends Component { ); } + renderEmpty() { return ( setTimeout(() => { + resolve(); + }, 300)); + + return Promise.all([promise, noticeableDelay]); +} diff --git a/x-pack/plugins/rollup/public/crud_app/store/action_types.js b/x-pack/plugins/rollup/public/crud_app/store/action_types.js index 81ebb45278354..9c3235d3ac427 100644 --- a/x-pack/plugins/rollup/public/crud_app/store/action_types.js +++ b/x-pack/plugins/rollup/public/crud_app/store/action_types.js @@ -22,6 +22,11 @@ export const CREATE_JOB_SUCCESS = 'CREATE_JOB_SUCCESS'; export const CREATE_JOB_FAILURE = 'CREATE_JOB_FAILURE'; export const CLEAR_CREATE_JOB_ERRORS = 'CLEAR_CREATE_JOB_ERRORS'; +// Update job (start, stop, delete) +export const UPDATE_JOB_START = 'UPDATE_JOB_START'; +export const UPDATE_JOB_SUCCESS = 'UPDATE_JOB_SUCCESS'; +export const UPDATE_JOB_FAILURE = 'UPDATE_JOB_FAILURE'; + // Table state export const FILTER_CHANGED = 'FILTER_CHANGED'; export const PAGE_CHANGED = 'PAGE_CHANGED'; diff --git a/x-pack/plugins/rollup/public/crud_app/store/actions/change_job_status.js b/x-pack/plugins/rollup/public/crud_app/store/actions/change_job_status.js index 9174869187335..fe26807944569 100644 --- a/x-pack/plugins/rollup/public/crud_app/store/actions/change_job_status.js +++ b/x-pack/plugins/rollup/public/crud_app/store/actions/change_job_status.js @@ -8,25 +8,57 @@ import { toastNotifications } from 'ui/notify'; import { startJobs as sendStartJobsRequest, stopJobs as sendStopJobsRequest, + createNoticeableDelay, } from '../../services'; + +import { + UPDATE_JOB_START, + UPDATE_JOB_SUCCESS, + UPDATE_JOB_FAILURE, +} from '../action_types'; + import { refreshJobs } from './refresh_jobs'; export const startJobs = (jobIds) => async (dispatch) => { + dispatch({ + type: UPDATE_JOB_START, + }); + try { - await sendStartJobsRequest(jobIds); + await createNoticeableDelay(sendStartJobsRequest(jobIds)); } catch (error) { + dispatch({ + type: UPDATE_JOB_FAILURE, + }); + return toastNotifications.addDanger(error.data.message); } + dispatch({ + type: UPDATE_JOB_SUCCESS, + }); + dispatch(refreshJobs()); }; export const stopJobs = (jobIds) => async (dispatch) => { + dispatch({ + type: UPDATE_JOB_START, + }); + try { - await sendStopJobsRequest(jobIds); + await createNoticeableDelay(sendStopJobsRequest(jobIds)); } catch (error) { + dispatch({ + type: UPDATE_JOB_FAILURE, + }); + return toastNotifications.addDanger(error.data.message); } + dispatch({ + type: UPDATE_JOB_SUCCESS, + }); + dispatch(refreshJobs()); }; diff --git a/x-pack/plugins/rollup/public/crud_app/store/actions/delete_jobs.js b/x-pack/plugins/rollup/public/crud_app/store/actions/delete_jobs.js index 2404ab3a02c93..6ab2913870b66 100644 --- a/x-pack/plugins/rollup/public/crud_app/store/actions/delete_jobs.js +++ b/x-pack/plugins/rollup/public/crud_app/store/actions/delete_jobs.js @@ -6,16 +6,30 @@ import { toastNotifications } from 'ui/notify'; -import { deleteJobs as sendDeleteJobsRequest } from '../../services'; +import { deleteJobs as sendDeleteJobsRequest, createNoticeableDelay } from '../../services'; import { getDetailPanelJob } from '../selectors'; +import { + UPDATE_JOB_START, + UPDATE_JOB_SUCCESS, + UPDATE_JOB_FAILURE, +} from '../action_types'; + import { refreshJobs } from './refresh_jobs'; import { closeDetailPanel } from './detail_panel'; export const deleteJobs = (jobIds) => async (dispatch, getState) => { + dispatch({ + type: UPDATE_JOB_START, + }); + try { - await sendDeleteJobsRequest(jobIds); + await createNoticeableDelay(sendDeleteJobsRequest(jobIds)); } catch (error) { + dispatch({ + type: UPDATE_JOB_FAILURE, + }); + return toastNotifications.addDanger(error.data.message); } @@ -31,5 +45,9 @@ export const deleteJobs = (jobIds) => async (dispatch, getState) => { dispatch(closeDetailPanel()); } + dispatch({ + type: UPDATE_JOB_SUCCESS, + }); + dispatch(refreshJobs()); }; diff --git a/x-pack/plugins/rollup/public/crud_app/store/reducers/index.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/index.js index 2fa141a50ab27..1653adae82ea5 100644 --- a/x-pack/plugins/rollup/public/crud_app/store/reducers/index.js +++ b/x-pack/plugins/rollup/public/crud_app/store/reducers/index.js @@ -9,10 +9,12 @@ import { jobs } from './jobs'; import { tableState } from './table_state'; import { detailPanel } from './detail_panel'; import { createJob } from './create_job'; +import { updateJob } from './update_job'; export const rollupJobs = combineReducers({ jobs, tableState, detailPanel, createJob, + updateJob, }); diff --git a/x-pack/plugins/rollup/public/crud_app/store/reducers/update_job.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/update_job.js new file mode 100644 index 0000000000000..3be9857bba18f --- /dev/null +++ b/x-pack/plugins/rollup/public/crud_app/store/reducers/update_job.js @@ -0,0 +1,40 @@ +/* + * 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 { + UPDATE_JOB_START, + UPDATE_JOB_SUCCESS, + UPDATE_JOB_FAILURE, +} from '../action_types'; + +const initialState = { + isUpdating: false, + error: undefined, +}; + +export function updateJob(state = initialState, action) { + const { type } = action; + + switch (type) { + case UPDATE_JOB_START: + return { + isUpdating: true, + }; + + case UPDATE_JOB_SUCCESS: + return { + isUpdating: false, + }; + + case UPDATE_JOB_FAILURE: + return { + isUpdating: false, + }; + + default: + return state; + } +} diff --git a/x-pack/plugins/rollup/public/crud_app/store/selectors/index.js b/x-pack/plugins/rollup/public/crud_app/store/selectors/index.js index 5a6072e5e3d8a..5a0de43c8c8d6 100644 --- a/x-pack/plugins/rollup/public/crud_app/store/selectors/index.js +++ b/x-pack/plugins/rollup/public/crud_app/store/selectors/index.js @@ -24,6 +24,7 @@ export const isLoading = (state) => state.jobs.isLoading; export const jobLoadError = (state) => state.jobs.jobLoadError; export const isSaving = (state) => state.createJob.isSaving; export const getCreateJobError = (state) => state.createJob.error; +export const isUpdating = (state) => state.updateJob.isUpdating; export const getJobStatusByJobName = (state, jobName) => { const jobs = getJobs(state);