From dd877aa3c45c087869aa7d3907627990e6bd505e Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 8 Nov 2018 13:41:31 -0700 Subject: [PATCH 1/9] Job Info button in Reporting Listing --- .../public/components/report_info_button.tsx | 141 ++++++++++++++++++ .../public/components/report_listing.tsx | 6 + .../reporting/public/lib/job_queue_client.ts | 35 +++++ .../plugins/reporting/server/routes/jobs.js | 30 ++++ 4 files changed, 212 insertions(+) create mode 100644 x-pack/plugins/reporting/public/components/report_info_button.tsx diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx new file mode 100644 index 0000000000000..1f46bc61d9c09 --- /dev/null +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -0,0 +1,141 @@ +/* + * 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 { EuiButtonIcon, EuiCallOut, EuiPopover } from '@elastic/eui'; +import { get } from 'lodash'; +import React, { Component, Fragment } from 'react'; +import { JobInfo, jobQueueClient } from '../lib/job_queue_client'; + +interface Props { + jobId: string; +} + +interface State { + isLoading: boolean; + isPopoverOpen: boolean; + calloutTitle: string; + info: JobInfo | null; +} + +export class ReportInfoButton extends Component { + private mounted?: boolean; + + constructor(props: Props) { + super(props); + + this.state = { + isLoading: false, + isPopoverOpen: false, + calloutTitle: 'Job info', + info: null, + }; + } + + public renderInfo() { + const { info } = this.state; + if (!info) { + return null; + } + + const iGet = (path: string) => get(info, path, 'n/a'); + + // TODO browser type + return ( + +
    +
  • Created By: {iGet('created_by')}
  • +
  • Created At: {iGet('created_at')}
  • +
  • Started At: {iGet('started_at')}
  • +
  • Completed At: {iGet('completed_at')}
  • +
  • Browser Timezone: {iGet('payload.browserTimezone')}
  • +
+
    +
  • Title: {iGet('payload.title')}
  • +
  • Type: {iGet('payload.type')}
  • +
  • Layout: {iGet('meta.layout')}
  • +
  • + Width: {iGet('payload.layout.dimensions.width')} Height:{' '} + {iGet('payload.layout.dimensions.height')} +
  • +
  • Job Type: {iGet('jobtype')}
  • +
  • Content Type: {iGet('output.content_type')}
  • +
+
    +
  • Attempts: {iGet('attempts')}
  • +
  • Max Attempts: {iGet('max_attempts')}
  • +
  • Priority: {iGet('priority')}
  • +
  • Timeout: {iGet('timeout')}
  • +
  • Status: {iGet('status')}
  • +
+
+ ); + } + + public render() { + const button = ( + + ); + + return ( + + + {this.renderInfo()} + + + ); + } + + public componentWillUnmount() { + this.mounted = false; + } + + public componentDidMount() { + this.mounted = true; + } + + private togglePopover = () => { + this.setState(prevState => { + return { isPopoverOpen: !prevState.isPopoverOpen }; + }); + + if (!this.state.info) { + this.loadInfo(); + } + }; + + private closePopover = () => { + this.setState({ isPopoverOpen: false }); + }; + + private loadInfo = async () => { + this.setState({ isLoading: true }); + try { + const info: JobInfo = await jobQueueClient.getInfo(this.props.jobId); + if (this.mounted) { + this.setState({ isLoading: false, info }); + } + } catch (kfetchError) { + if (this.mounted) { + this.setState({ + isLoading: false, + calloutTitle: 'Unable to fetch report info', + info: kfetchError.message, + }); + } + } + }; +} diff --git a/x-pack/plugins/reporting/public/components/report_listing.tsx b/x-pack/plugins/reporting/public/components/report_listing.tsx index e109df0e03ba1..057e1dedf3f16 100644 --- a/x-pack/plugins/reporting/public/components/report_listing.tsx +++ b/x-pack/plugins/reporting/public/components/report_listing.tsx @@ -17,6 +17,7 @@ import { Poller } from '../../../../common/poller'; import { downloadReport } from '../lib/download_report'; import { jobQueueClient, JobQueueEntry } from '../lib/job_queue_client'; import { ReportErrorButton } from './report_error_button'; +import { ReportInfoButton } from './report_info_button'; import { EuiBasicTable, @@ -189,6 +190,7 @@ export class ReportListing extends Component {
{this.renderDownloadButton(record)} {this.renderReportErrorButton(record)} + {this.renderInfoButton(record)}
); }, @@ -249,6 +251,10 @@ export class ReportListing extends Component { return ; }; + private renderInfoButton = (record: Job) => { + return ; + }; + private onTableChange = ({ page }: { page: { index: number } }) => { const { index: pageIndex } = page; diff --git a/x-pack/plugins/reporting/public/lib/job_queue_client.ts b/x-pack/plugins/reporting/public/lib/job_queue_client.ts index 75080dd4474fd..5c979eebf21af 100644 --- a/x-pack/plugins/reporting/public/lib/job_queue_client.ts +++ b/x-pack/plugins/reporting/public/lib/job_queue_client.ts @@ -20,6 +20,33 @@ export interface JobContent { content_type: boolean; } +export interface JobInfo { + created_at: string; + priority: number; + jobtype: string; + created_by: string; + timeout: number; + output: { content_type: string }; + process_expiration: string; + completed_at: string; + payload: { + layout: { id: string; dimensions: { width: number; height: number } }; + objects: Array<{ relativeUrl: string }>; + type: string; + title: string; + forceNow: string; + browserTimezone: string; + }; + meta: { + layout: string; + objectType: string; + }; + max_attempts: number; + started_at: string; + attempts: number; + status: string; +} + class JobQueueClient { public list = (page = 0, jobIds?: string[]): Promise => { const query = { page } as any; @@ -50,6 +77,14 @@ class JobQueueClient { headers: addSystemApiHeader({}), }); } + + public getInfo(jobId: string): Promise { + return kfetch({ + method: 'GET', + pathname: `${API_BASE_URL}/info/${jobId}`, + headers: addSystemApiHeader({}), + }); + } } export const jobQueueClient = new JobQueueClient(); diff --git a/x-pack/plugins/reporting/server/routes/jobs.js b/x-pack/plugins/reporting/server/routes/jobs.js index f656ad1c7eb73..2639fc103bbde 100644 --- a/x-pack/plugins/reporting/server/routes/jobs.js +++ b/x-pack/plugins/reporting/server/routes/jobs.js @@ -81,6 +81,36 @@ export function jobs(server) { config: getRouteConfig(), }); + // return some info about the job + server.route({ + path: `${mainEntry}/info/{docId}`, + method: 'GET', + handler: (request) => { + const { docId } = request.params; + + return jobsQuery.get(request.pre.user, docId) + .then((doc) => { + if (!doc) { + return boom.notFound(); + } + + const { jobtype: jobType } = doc._source; + if (!request.pre.management.jobTypes.includes(jobType)) { + return boom.unauthorized(`Sorry, you are not authorized to view ${jobType} info`); + } + + const { payload } = doc._source; + payload.headers = 'not shown'; + + return { + ...doc._source, + payload + }; + }); + }, + config: getRouteConfig(), + }); + // trigger a download of the output from a job // NOTE: We're disabling range request for downloading the PDF. There's a bug in Firefox's PDF.js viewer // (https://github.com/mozilla/pdf.js/issues/8958) where they're using a range request to retrieve the From 2e28ea83fa184a8dfebff2bcfea1689fb58f0c5d Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 12 Nov 2018 12:58:03 -0700 Subject: [PATCH 2/9] use lodash directly --- .../public/components/report_info_button.tsx | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx index 1f46bc61d9c09..5a7feb736d365 100644 --- a/x-pack/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -20,6 +20,8 @@ interface State { info: JobInfo | null; } +const NA = 'n/a'; + export class ReportInfoButton extends Component { private mounted?: boolean; @@ -40,35 +42,33 @@ export class ReportInfoButton extends Component { return null; } - const iGet = (path: string) => get(info, path, 'n/a'); - // TODO browser type return (
    -
  • Created By: {iGet('created_by')}
  • -
  • Created At: {iGet('created_at')}
  • -
  • Started At: {iGet('started_at')}
  • -
  • Completed At: {iGet('completed_at')}
  • -
  • Browser Timezone: {iGet('payload.browserTimezone')}
  • +
  • Created By: {get(info, 'created_by', NA)}
  • +
  • Created At: {get(info, 'created_at', NA)}
  • +
  • Started At: {get(info, 'started_at', NA)}
  • +
  • Completed At: {get(info, 'completed_at', NA)}
  • +
  • Browser Timezone: {get(info, 'payload.browserTimezone', NA)}
    -
  • Title: {iGet('payload.title')}
  • -
  • Type: {iGet('payload.type')}
  • -
  • Layout: {iGet('meta.layout')}
  • +
  • Title: {get(info, 'payload.title', NA)}
  • +
  • Type: {get(info, 'payload.type', NA)}
  • +
  • Layout: {get(info, 'meta.layout', NA)}
  • - Width: {iGet('payload.layout.dimensions.width')} Height:{' '} - {iGet('payload.layout.dimensions.height')} + Width: {get(info, 'payload.layout.dimensions.width', NA)} Height:{' '} + {get(info, 'payload.layout.dimensions.height', NA)}
  • -
  • Job Type: {iGet('jobtype')}
  • -
  • Content Type: {iGet('output.content_type')}
  • +
  • Job Type: {get(info, 'jobtype', NA)}
  • +
  • Content Type: {get(info, 'output.content_type') || NA}
    -
  • Attempts: {iGet('attempts')}
  • -
  • Max Attempts: {iGet('max_attempts')}
  • -
  • Priority: {iGet('priority')}
  • -
  • Timeout: {iGet('timeout')}
  • -
  • Status: {iGet('status')}
  • +
  • Attempts: {get(info, 'attempts', NA)}
  • +
  • Max Attempts: {get(info, 'max_attempts', NA)}
  • +
  • Priority: {get(info, 'priority', NA)}
  • +
  • Timeout: {get(info, 'timeout', NA)}
  • +
  • Status: {get(info, 'status', NA)}
); From 9205896dda9858b031278ec15214fb2ff2e03d10 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 19 Nov 2018 10:40:42 -0700 Subject: [PATCH 3/9] start of flyout use --- .../public/components/report_info_button.tsx | 95 +++++++++++-------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx index 5a7feb736d365..b038847b2b2c6 100644 --- a/x-pack/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -4,7 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiButtonIcon, EuiCallOut, EuiPopover } from '@elastic/eui'; +import { + EuiButtonIcon, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiPortal, + EuiText, + EuiTitle, +} from '@elastic/eui'; import { get } from 'lodash'; import React, { Component, Fragment } from 'react'; import { JobInfo, jobQueueClient } from '../lib/job_queue_client'; @@ -15,7 +23,7 @@ interface Props { interface State { isLoading: boolean; - isPopoverOpen: boolean; + isFlyoutVisible: boolean; calloutTitle: string; info: JobInfo | null; } @@ -30,10 +38,13 @@ export class ReportInfoButton extends Component { this.state = { isLoading: false, - isPopoverOpen: false, + isFlyoutVisible: false, calloutTitle: 'Job info', info: null, }; + + this.closeFlyout = this.closeFlyout.bind(this); + this.showFlyout = this.showFlyout.bind(this); } public renderInfo() { @@ -74,31 +85,6 @@ export class ReportInfoButton extends Component { ); } - public render() { - const button = ( - - ); - - return ( - - - {this.renderInfo()} - - - ); - } - public componentWillUnmount() { this.mounted = false; } @@ -107,19 +93,38 @@ export class ReportInfoButton extends Component { this.mounted = true; } - private togglePopover = () => { - this.setState(prevState => { - return { isPopoverOpen: !prevState.isPopoverOpen }; - }); - - if (!this.state.info) { - this.loadInfo(); + public render() { + let flyout; + + if (this.state.isFlyoutVisible) { + flyout = ( + + + + +

{this.state.calloutTitle}

+
+
+ + {this.renderInfo()} + +
+
+ ); } - }; - private closePopover = () => { - this.setState({ isPopoverOpen: false }); - }; + return ( + + + {flyout} + + ); + } private loadInfo = async () => { this.setState({ isLoading: true }); @@ -138,4 +143,16 @@ export class ReportInfoButton extends Component { } } }; + + private closeFlyout = () => { + this.setState({ isFlyoutVisible: false }); + }; + + private showFlyout = () => { + this.setState({ isFlyoutVisible: true }); + + if (!this.state.info) { + this.loadInfo(); + } + }; } From 188615ad184be67659ab87b10caaa54d76adf015 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 19 Nov 2018 11:13:08 -0700 Subject: [PATCH 4/9] description list in flyout --- .../public/components/report_info_button.tsx | 133 ++++++++++++++---- 1 file changed, 108 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx index b038847b2b2c6..778ba7861d87b 100644 --- a/x-pack/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -6,10 +6,12 @@ import { EuiButtonIcon, + EuiDescriptionList, EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiPortal, + EuiSpacer, EuiText, EuiTitle, } from '@elastic/eui'; @@ -30,6 +32,18 @@ interface State { const NA = 'n/a'; +const getDimensions = (info: JobInfo) => { + const { width, height } = get(info, 'payload.layout.dimensions'); + if (info && info.payload) { + return ( + + Width: {width} x Height: {height} + + ); + } + return NA; +}; + export class ReportInfoButton extends Component { private mounted?: boolean; @@ -54,33 +68,102 @@ export class ReportInfoButton extends Component { } // TODO browser type + // TODO queue method (clicked UI, watcher, etc) + const jobInfoParts = { + datetimes: [ + { + title: 'Created By', + description: get(info, 'created_by', NA), + }, + { + title: 'Created At', + description: get(info, 'created_at', NA), + }, + { + title: 'Started At', + description: get(info, 'started_at', NA), + }, + { + title: 'Completed At', + description: get(info, 'completed_at', NA), + }, + { + title: 'Browser Timezone', + description: get(info, 'payload.browserTimezone', NA), + }, + ], + payload: [ + { + title: 'Title', + description: get(info, 'payload.title', NA), + }, + { + title: 'Type', + description: get(info, 'payload.type', NA), + }, + { + title: 'Layout', + description: get(info, 'meta.layout', NA), + }, + { + title: 'Dimensions', + description: getDimensions(info), + }, + { + title: 'Job Type', + description: get(info, 'jobtype', NA), + }, + { + title: 'Content Type', + description: get(info, 'output.content_type') || NA, + }, + ], + status: [ + { + title: 'Attempts', + description: get(info, 'attempts', NA), + }, + { + title: 'Max Attempts', + description: get(info, 'max_attempts', NA), + }, + { + title: 'Priority', + description: get(info, 'priority', NA), + }, + { + title: 'Timeout', + description: get(info, 'timeout', NA), + }, + { + title: 'Status', + description: get(info, 'status', NA), + }, + ], + }; + return ( -
    -
  • Created By: {get(info, 'created_by', NA)}
  • -
  • Created At: {get(info, 'created_at', NA)}
  • -
  • Started At: {get(info, 'started_at', NA)}
  • -
  • Completed At: {get(info, 'completed_at', NA)}
  • -
  • Browser Timezone: {get(info, 'payload.browserTimezone', NA)}
  • -
-
    -
  • Title: {get(info, 'payload.title', NA)}
  • -
  • Type: {get(info, 'payload.type', NA)}
  • -
  • Layout: {get(info, 'meta.layout', NA)}
  • -
  • - Width: {get(info, 'payload.layout.dimensions.width', NA)} Height:{' '} - {get(info, 'payload.layout.dimensions.height', NA)} -
  • -
  • Job Type: {get(info, 'jobtype', NA)}
  • -
  • Content Type: {get(info, 'output.content_type') || NA}
  • -
-
    -
  • Attempts: {get(info, 'attempts', NA)}
  • -
  • Max Attempts: {get(info, 'max_attempts', NA)}
  • -
  • Priority: {get(info, 'priority', NA)}
  • -
  • Timeout: {get(info, 'timeout', NA)}
  • -
  • Status: {get(info, 'status', NA)}
  • -
+ + + + +
); } From 99178a45895562e6230d08f538d878a8ed217203 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 19 Nov 2018 13:49:30 -0700 Subject: [PATCH 5/9] capitalize --- .../plugins/reporting/public/components/report_info_button.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx index 778ba7861d87b..5f7ecb404974a 100644 --- a/x-pack/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -53,7 +53,7 @@ export class ReportInfoButton extends Component { this.state = { isLoading: false, isFlyoutVisible: false, - calloutTitle: 'Job info', + calloutTitle: 'Job Info', info: null, }; From 0799ecc1b04cbe5a8dbbbc0e351bb7fd3d0f9841 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 19 Nov 2018 14:31:36 -0700 Subject: [PATCH 6/9] undefined guard --- .../reporting/public/components/report_info_button.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx index 5f7ecb404974a..a3020a5ee7f69 100644 --- a/x-pack/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -33,8 +33,9 @@ interface State { const NA = 'n/a'; const getDimensions = (info: JobInfo) => { - const { width, height } = get(info, 'payload.layout.dimensions'); - if (info && info.payload) { + const defaultDimensions = { width: null, height: null }; + const { width, height } = get(info, 'payload.layout.dimensions', defaultDimensions); + if (width && height) { return ( Width: {width} x Height: {height} From 1a3b4c6cec69e4dfe5768cd1bdb78e3ba69f6524 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 19 Nov 2018 14:33:23 -0700 Subject: [PATCH 7/9] expire info on close --- .../reporting/public/components/report_info_button.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx index a3020a5ee7f69..1f12130ca8ffa 100644 --- a/x-pack/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -229,7 +229,10 @@ export class ReportInfoButton extends Component { }; private closeFlyout = () => { - this.setState({ isFlyoutVisible: false }); + this.setState({ + isFlyoutVisible: false, + info: null, // force re-read for next click + }); }; private showFlyout = () => { From 81b3e244a53b26e120c9efd74d4dc0924245934b Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 20 Nov 2018 10:49:46 -0700 Subject: [PATCH 8/9] add jest test --- .../report_info_button.test.tsx.snap | 1385 +++++++++++++++++ .../components/report_info_button.test.tsx | 57 + .../public/components/report_info_button.tsx | 9 +- 3 files changed, 1450 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/reporting/public/components/__snapshots__/report_info_button.test.tsx.snap create mode 100644 x-pack/plugins/reporting/public/components/report_info_button.test.tsx diff --git a/x-pack/plugins/reporting/public/components/__snapshots__/report_info_button.test.tsx.snap b/x-pack/plugins/reporting/public/components/__snapshots__/report_info_button.test.tsx.snap new file mode 100644 index 0000000000000..eff50e4ea5ce5 --- /dev/null +++ b/x-pack/plugins/reporting/public/components/__snapshots__/report_info_button.test.tsx.snap @@ -0,0 +1,1385 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ReportInfoButton handles button click flyout on click 1`] = ` + +`; + +exports[`ReportInfoButton opens flyout with fetch error info 1`] = ` +Array [ + + + + + +
+
+ + + + +
+ +

+ Unable to fetch report info +

+
+
+
+ +
+ +
+ +
+ +
+ Created By +
+
+ +
+ n/a +
+
+ +
+ Created At +
+
+ +
+ n/a +
+
+ +
+ Started At +
+
+ +
+ n/a +
+
+ +
+ Completed At +
+
+ +
+ n/a +
+
+ +
+ Browser Timezone +
+
+ +
+ n/a +
+
+
+
+ +
+ + +
+ +
+ Title +
+
+ +
+ n/a +
+
+ +
+ Type +
+
+ +
+ n/a +
+
+ +
+ Layout +
+
+ +
+ n/a +
+
+ +
+ Dimensions +
+
+ +
+ n/a +
+
+ +
+ Job Type +
+
+ +
+ n/a +
+
+ +
+ Content Type +
+
+ +
+ n/a +
+
+
+
+ +
+ + +
+ +
+ Attempts +
+
+ +
+ n/a +
+
+ +
+ Max Attempts +
+
+ +
+ n/a +
+
+ +
+ Priority +
+
+ +
+ n/a +
+
+ +
+ Timeout +
+
+ +
+ n/a +
+
+ +
+ Status +
+
+ +
+ n/a +
+
+
+
+
+ +
+ +
+
+ + + , +
+ + + + +
+ +

+ Unable to fetch report info +

+
+
+
+ +
+ +
+ +
+ +
+ Created By +
+
+ +
+ n/a +
+
+ +
+ Created At +
+
+ +
+ n/a +
+
+ +
+ Started At +
+
+ +
+ n/a +
+
+ +
+ Completed At +
+
+ +
+ n/a +
+
+ +
+ Browser Timezone +
+
+ +
+ n/a +
+
+
+
+ +
+ + +
+ +
+ Title +
+
+ +
+ n/a +
+
+ +
+ Type +
+
+ +
+ n/a +
+
+ +
+ Layout +
+
+ +
+ n/a +
+
+ +
+ Dimensions +
+
+ +
+ n/a +
+
+ +
+ Job Type +
+
+ +
+ n/a +
+
+ +
+ Content Type +
+
+ +
+ n/a +
+
+
+
+ +
+ + +
+ +
+ Attempts +
+
+ +
+ n/a +
+
+ +
+ Max Attempts +
+
+ +
+ n/a +
+
+ +
+ Priority +
+
+ +
+ n/a +
+
+ +
+ Timeout +
+
+ +
+ n/a +
+
+ +
+ Status +
+
+ +
+ n/a +
+
+
+
+
+ +
+ +
, +] +`; + +exports[`ReportInfoButton opens flyout with info 1`] = ` +Array [ + + + + + +
+
+ + + + +
+ +

+ Job Info +

+
+
+
+ +
+ +
+ +
+ +
+
+ + + , +
+ + + + +
+ +

+ Job Info +

+
+
+
+ +
+ +
+ +
+ +
, +] +`; diff --git a/x-pack/plugins/reporting/public/components/report_info_button.test.tsx b/x-pack/plugins/reporting/public/components/report_info_button.test.tsx new file mode 100644 index 0000000000000..93ceed0f64a0e --- /dev/null +++ b/x-pack/plugins/reporting/public/components/report_info_button.test.tsx @@ -0,0 +1,57 @@ +/* + * 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. + */ + +const mockJobQueueClient = { getInfo: jest.fn() }; +jest.mock('../lib/job_queue_client', () => ({ jobQueueClient: mockJobQueueClient })); + +import React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { ReportInfoButton } from './report_info_button'; + +describe('ReportInfoButton', () => { + beforeEach(() => { + mockJobQueueClient.getInfo = jest.fn(() => ({ + payload: { title: 'Test Job' }, + })); + }); + + it('handles button click flyout on click', () => { + const wrapper = mountWithIntl(); + const input = wrapper.find('[data-test-subj="reportInfoButton"]').hostNodes(); + expect(input).toMatchSnapshot(); + }); + + it('opens flyout with info', () => { + const wrapper = mountWithIntl(); + const input = wrapper.find('[data-test-subj="reportInfoButton"]').hostNodes(); + + input.simulate('click'); + + const flyout = wrapper.find('[data-test-subj="reportInfoFlyout"]'); + expect(flyout).toMatchSnapshot(); + + expect(mockJobQueueClient.getInfo).toHaveBeenCalledTimes(1); + expect(mockJobQueueClient.getInfo).toHaveBeenCalledWith('abc-456'); + }); + + it('opens flyout with fetch error info', () => { + // simulate fetch failure + mockJobQueueClient.getInfo = jest.fn(() => { + throw new Error('Could not fetch the job info'); + }); + + const wrapper = mountWithIntl(); + const input = wrapper.find('[data-test-subj="reportInfoButton"]').hostNodes(); + + input.simulate('click'); + + const flyout = wrapper.find('[data-test-subj="reportInfoFlyout"]'); + expect(flyout).toMatchSnapshot(); + + expect(mockJobQueueClient.getInfo).toHaveBeenCalledTimes(1); + expect(mockJobQueueClient.getInfo).toHaveBeenCalledWith('abc-789'); + }); +}); diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx index 1f12130ca8ffa..5bf3237f08ae7 100644 --- a/x-pack/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -183,7 +183,13 @@ export class ReportInfoButton extends Component { if (this.state.isFlyoutVisible) { flyout = ( - +

{this.state.calloutTitle}

@@ -203,6 +209,7 @@ export class ReportInfoButton extends Component { onClick={this.showFlyout} iconType="iInCircle" color={'primary'} + data-test-subj="reportInfoButton" aria-label="Show report info" /> {flyout} From 9efb3f59b4e32b6db431930bde2accfceb8f399d Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 20 Nov 2018 13:49:49 -0700 Subject: [PATCH 9/9] better at error handling + messaging --- .../report_info_button.test.tsx.snap | 824 +----------------- .../public/components/report_info_button.tsx | 11 +- 2 files changed, 11 insertions(+), 824 deletions(-) diff --git a/x-pack/plugins/reporting/public/components/__snapshots__/report_info_button.test.tsx.snap b/x-pack/plugins/reporting/public/components/__snapshots__/report_info_button.test.tsx.snap index eff50e4ea5ce5..f211116c12a19 100644 --- a/x-pack/plugins/reporting/public/components/__snapshots__/report_info_button.test.tsx.snap +++ b/x-pack/plugins/reporting/public/components/__snapshots__/report_info_button.test.tsx.snap @@ -186,417 +186,7 @@ Array [
- -
- -
- Created By -
-
- -
- n/a -
-
- -
- Created At -
-
- -
- n/a -
-
- -
- Started At -
-
- -
- n/a -
-
- -
- Completed At -
-
- -
- n/a -
-
- -
- Browser Timezone -
-
- -
- n/a -
-
-
-
- -
- - -
- -
- Title -
-
- -
- n/a -
-
- -
- Type -
-
- -
- n/a -
-
- -
- Layout -
-
- -
- n/a -
-
- -
- Dimensions -
-
- -
- n/a -
-
- -
- Job Type -
-
- -
- n/a -
-
- -
- Content Type -
-
- -
- n/a -
-
-
-
- -
- - -
- -
- Attempts -
-
- -
- n/a -
-
- -
- Max Attempts -
-
- -
- n/a -
-
- -
- Priority -
-
- -
- n/a -
-
- -
- Timeout -
-
- -
- n/a -
-
- -
- Status -
-
- -
- n/a -
-
-
-
+ Could not fetch the job info
@@ -711,417 +301,7 @@ Array [
- -
- -
- Created By -
-
- -
- n/a -
-
- -
- Created At -
-
- -
- n/a -
-
- -
- Started At -
-
- -
- n/a -
-
- -
- Completed At -
-
- -
- n/a -
-
- -
- Browser Timezone -
-
- -
- n/a -
-
-
-
- -
- - -
- -
- Title -
-
- -
- n/a -
-
- -
- Type -
-
- -
- n/a -
-
- -
- Layout -
-
- -
- n/a -
-
- -
- Dimensions -
-
- -
- n/a -
-
- -
- Job Type -
-
- -
- n/a -
-
- -
- Content Type -
-
- -
- n/a -
-
-
-
- -
- - -
- -
- Attempts -
-
- -
- n/a -
-
- -
- Max Attempts -
-
- -
- n/a -
-
- -
- Priority -
-
- -
- n/a -
-
- -
- Timeout -
-
- -
- n/a -
-
- -
- Status -
-
- -
- n/a -
-
-
-
+ Could not fetch the job info
diff --git a/x-pack/plugins/reporting/public/components/report_info_button.tsx b/x-pack/plugins/reporting/public/components/report_info_button.tsx index 5bf3237f08ae7..4f8f330c6f5ee 100644 --- a/x-pack/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/plugins/reporting/public/components/report_info_button.tsx @@ -28,6 +28,7 @@ interface State { isFlyoutVisible: boolean; calloutTitle: string; info: JobInfo | null; + error: Error | null; } const NA = 'n/a'; @@ -56,6 +57,7 @@ export class ReportInfoButton extends Component { isFlyoutVisible: false, calloutTitle: 'Job Info', info: null, + error: null, }; this.closeFlyout = this.closeFlyout.bind(this); @@ -63,7 +65,10 @@ export class ReportInfoButton extends Component { } public renderInfo() { - const { info } = this.state; + const { info, error: err } = this.state; + if (err) { + return err.message; + } if (!info) { return null; } @@ -229,8 +234,10 @@ export class ReportInfoButton extends Component { this.setState({ isLoading: false, calloutTitle: 'Unable to fetch report info', - info: kfetchError.message, + info: null, + error: kfetchError, }); + throw kfetchError; } } };