Skip to content

Commit

Permalink
multi-delete
Browse files Browse the repository at this point in the history
  • Loading branch information
tsullivan committed Mar 14, 2020
1 parent 4e8ba19 commit 1974aac
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,35 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
import React from 'react';
import { JobStatuses } from '../../../constants';
import { Job as ListingJob, Props as ListingProps } from '../report_listing';
import { ReportInfoButton } from './report_info_button';
import { EuiButton } from '@elastic/eui';
import React, { FunctionComponent } from 'react';
import { Job, Props as ListingProps } from '../report_listing';

const { COMPLETED, FAILED } = JobStatuses;
type DeleteHandler = () => Promise<void>;
type DeleteFn = () => Promise<void>;
type Props = { jobsToDelete: Job[]; performDelete: DeleteFn } & ListingProps;

export const DeleteButton = ({
record,
handleDelete,
...props
}: { record: ListingJob; handleDelete: DeleteHandler } & ListingProps) => {
if (!([COMPLETED, FAILED] as string[]).includes(record.status)) {
return null;
}
export const ReportDeleteButton: FunctionComponent<Props> = (props: Props) => {
const { jobsToDelete, performDelete, intl } = props;

const { intl } = props;
const button = (
<EuiButtonIcon
onClick={handleDelete}
iconType="trash"
color={'danger'}
aria-label={intl.formatMessage({
id: 'xpack.reporting.listing.table.deleteReportButton',
defaultMessage: 'Delete report',
})}
/>
);
return (
<EuiToolTip
position="top"
content={intl.formatMessage({
id: 'xpack.reporting.listing.table.deleteReportAriaLabel',
defaultMessage: 'Delete report',
})}
>
{button}
</EuiToolTip>
);
};
if (jobsToDelete.length === 0) return null;

const message =
jobsToDelete.length > 1
? intl.formatMessage(
{
id: 'xpack.reporting.listing.table.deleteReportButton',
defaultMessage: `Delete {num} reports`,
},
{ num: jobsToDelete.length }
)
: intl.formatMessage({
id: 'xpack.reporting.listing.table.deleteReportButton',
defaultMessage: `Delete report`,
});

export const InfoButton = ({ record, ...props }: { record: ListingJob } & ListingProps) => {
const { intl } = props;
return (
<EuiToolTip
position="top"
content={intl.formatMessage({
id: 'xpack.reporting.listing.table.infoButtonAriaLabel',
defaultMessage: 'Download report',
})}
>
<ReportInfoButton apiClient={props.apiClient} jobId={record.id} />
</EuiToolTip>
<EuiButton onClick={performDelete} iconType="trash" color={'danger'}>
{message}
</EuiButton>
);
};
148 changes: 89 additions & 59 deletions x-pack/plugins/reporting/public/components/report_listing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import { get } from 'lodash';
import moment from 'moment';
import React, { Component } from 'react';
import React, { Component, Fragment } from 'react';
import { Subscription } from 'rxjs';

import {
EuiBasicTable,
EuiLoadingSpinner,
EuiInMemoryTable,
EuiPageContent,
EuiSpacer,
EuiText,
Expand All @@ -27,7 +26,12 @@ import { Poller } from '../../common/poller';
import { JobStatuses, JOB_COMPLETION_NOTIFICATIONS_POLLER_CONFIG } from '../../constants';
import { ReportingAPIClient, JobQueueEntry } from '../lib/reporting_api_client';
import { checkLicense } from '../lib/license_check';
import { DeleteButton, DownloadButton, ReportInfoButton, ReportErrorButton } from './buttons';
import {
ReportDeleteButton,
ReportDownloadButton,
ReportInfoButton,
ReportErrorButton,
} from './buttons';

export interface Job {
id: string;
Expand Down Expand Up @@ -60,6 +64,7 @@ interface State {
page: number;
total: number;
jobs: Job[];
selectedJobs: Job[];
isLoading: boolean;
showLinks: boolean;
enableLinks: boolean;
Expand Down Expand Up @@ -112,6 +117,7 @@ class ReportListingUi extends Component<Props, State> {
page: 0,
total: 0,
jobs: [],
selectedJobs: [],
isLoading: false,
showLinks: false,
enableLinks: false,
Expand Down Expand Up @@ -181,10 +187,8 @@ class ReportListingUi extends Component<Props, State> {
});
};

private removeRecord = (record: Job) => {
const { jobs } = this.state;
const filtered = jobs.filter(j => j.id !== record.id);
this.setState(current => ({ ...current, jobs: filtered }));
private onSelectionChange = (jobs: Job[]) => {
this.setState(current => ({ ...current, selectedJobs: jobs }));
};

private renderTable() {
Expand Down Expand Up @@ -320,13 +324,11 @@ class ReportListingUi extends Component<Props, State> {
actions: [
{
render: (record: Job) => {
const canDelete = !record.is_deleting;
return (
<div>
<DownloadButton {...this.props} record={record} />
<ReportDownloadButton {...this.props} record={record} />
<ReportErrorButton {...this.props} record={record} />
<ReportInfoButton {...this.props} jobId={record.id} />
{canDelete ? this.renderDeleteButton(record) : <EuiLoadingSpinner size="m" />}
</div>
);
},
Expand All @@ -342,60 +344,88 @@ class ReportListingUi extends Component<Props, State> {
hidePerPageOptions: true,
};

const selection = {
itemId: 'id',
onSelectionChange: this.onSelectionChange,
};

return (
<EuiBasicTable
itemId={'id'}
items={this.state.jobs}
loading={this.state.isLoading}
columns={tableColumns}
noItemsMessage={
this.state.isLoading
? intl.formatMessage({
id: 'xpack.reporting.listing.table.loadingReportsDescription',
defaultMessage: 'Loading reports',
})
: intl.formatMessage({
id: 'xpack.reporting.listing.table.noCreatedReportsDescription',
defaultMessage: 'No reports have been created',
})
}
pagination={pagination}
onChange={this.onTableChange}
data-test-subj="reportJobListing"
/>
<Fragment>
{this.renderDeleteButton()}
<EuiSpacer size="m" />
<EuiInMemoryTable
itemId="id"
items={this.state.jobs}
loading={this.state.isLoading}
columns={tableColumns}
message={
this.state.isLoading
? intl.formatMessage({
id: 'xpack.reporting.listing.table.loadingReportsDescription',
defaultMessage: 'Loading reports',
})
: intl.formatMessage({
id: 'xpack.reporting.listing.table.noCreatedReportsDescription',
defaultMessage: 'No reports have been created',
})
}
pagination={pagination}
selection={selection}
isSelectable={true}
onChange={this.onTableChange}
data-test-subj="reportJobListing"
/>
</Fragment>
);
}

private renderDeleteButton = (record: Job) => {
const handleDelete = async () => {
try {
// TODO present a modal to verify: this can not be undone
this.setState(current => ({ ...current, is_deleting: true }));
await this.props.apiClient.deleteReport(record.id);
this.removeRecord(record);
this.props.toasts.addSuccess(
this.props.intl.formatMessage(
{
id: 'xpack.reporting.listing.table.deleteConfim',
defaultMessage: `The {reportTitle} report was deleted`,
},
{ reportTitle: record.object_title }
)
);
} catch (error) {
this.props.toasts.addDanger(
this.props.intl.formatMessage(
{
id: 'xpack.reporting.listing.table.deleteFailedErrorMessage',
defaultMessage: `The report was not deleted: {error}`,
},
{ error }
)
);
throw error;
private removeRecord = (record: Job) => {
const { jobs } = this.state;
const filtered = jobs.filter(j => j.id !== record.id);
this.setState(current => ({ ...current, jobs: filtered }));
};

private renderDeleteButton = () => {
const { selectedJobs } = this.state;
if (selectedJobs.length === 0) return null;

const performDelete = async () => {
for (const record of selectedJobs) {
try {
this.setState(current => ({ ...current, is_deleting: true }));
await this.props.apiClient.deleteReport(record.id);
this.removeRecord(record);
this.props.toasts.addSuccess(
this.props.intl.formatMessage(
{
id: 'xpack.reporting.listing.table.deleteConfim',
defaultMessage: `The {reportTitle} report was deleted`,
},
{ reportTitle: record.object_title }
)
);
} catch (error) {
this.props.toasts.addDanger(
this.props.intl.formatMessage(
{
id: 'xpack.reporting.listing.table.deleteFailedErrorMessage',
defaultMessage: `The report was not deleted: {error}`,
},
{ error }
)
);
throw error;
}
}
};
return <DeleteButton handleDelete={handleDelete} record={record} {...this.props} />;

return (
<ReportDeleteButton
jobsToDelete={selectedJobs}
performDelete={performDelete}
{...this.props}
/>
);
};

private onTableChange = ({ page }: { page: { index: number } }) => {
Expand Down

0 comments on commit 1974aac

Please sign in to comment.