From c5a46f4487d1f2d90b29ce932575bd1ee03b54f7 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Wed, 18 Jun 2025 08:47:16 -0700 Subject: [PATCH] [9.0] [Canvas/PDF report] Allow canvas to generate PDF report (#224309) (#224338) # Backport This will backport the following commits from `main` to `9.0`: - [[Canvas/PDF report] Allow canvas to generate PDF report (#224309)](https://github.com/elastic/kibana/pull/224309) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) --- .../private/kbn-reporting/common/constants.ts | 2 ++ .../shared/deeplinks/analytics/constants.ts | 2 ++ .../shared/deeplinks/analytics/index.ts | 1 + .../plugins/private/canvas/common/index.ts | 1 - .../plugins/private/canvas/common/locator.ts | 3 +- .../workpad_header/share_menu/utils.ts | 3 +- .../plugins/private/canvas/tsconfig.json | 3 +- .../public/notifier/job_download_button.tsx | 1 + x-pack/test/functional/apps/canvas/reports.ts | 6 ++++ .../functional/page_objects/reporting_page.ts | 32 ++++++++++++++++++- 10 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/platform/packages/private/kbn-reporting/common/constants.ts b/src/platform/packages/private/kbn-reporting/common/constants.ts index 1a73a2ed39a5..d4bf17798bf0 100644 --- a/src/platform/packages/private/kbn-reporting/common/constants.ts +++ b/src/platform/packages/private/kbn-reporting/common/constants.ts @@ -8,6 +8,7 @@ */ import { + CANVAS_APP_LOCATOR, DASHBOARD_APP_LOCATOR, LENS_APP_LOCATOR, VISUALIZE_APP_LOCATOR, @@ -53,6 +54,7 @@ export const JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY = // Allowed locator types for reporting: the "reportable" analytical apps we expect to redirect to during screenshotting export const REPORTING_REDIRECT_ALLOWED_LOCATOR_TYPES = [ + CANVAS_APP_LOCATOR, DASHBOARD_APP_LOCATOR, LENS_APP_LOCATOR, VISUALIZE_APP_LOCATOR, diff --git a/src/platform/packages/shared/deeplinks/analytics/constants.ts b/src/platform/packages/shared/deeplinks/analytics/constants.ts index 9b905accdb12..32c8c6ab6398 100644 --- a/src/platform/packages/shared/deeplinks/analytics/constants.ts +++ b/src/platform/packages/shared/deeplinks/analytics/constants.ts @@ -7,6 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +export const CANVAS_APP_LOCATOR = 'CANVAS_APP_LOCATOR'; + export const DISCOVER_APP_ID = 'discover'; export const DASHBOARD_APP_ID = 'dashboards'; diff --git a/src/platform/packages/shared/deeplinks/analytics/index.ts b/src/platform/packages/shared/deeplinks/analytics/index.ts index 83333964742b..1507cfd4d219 100644 --- a/src/platform/packages/shared/deeplinks/analytics/index.ts +++ b/src/platform/packages/shared/deeplinks/analytics/index.ts @@ -8,6 +8,7 @@ */ export { + CANVAS_APP_LOCATOR, DASHBOARD_APP_ID, DISCOVER_APP_ID, VISUALIZE_APP_ID, diff --git a/x-pack/platform/plugins/private/canvas/common/index.ts b/x-pack/platform/plugins/private/canvas/common/index.ts index 51a661f6e8d1..8c0d47143990 100644 --- a/x-pack/platform/plugins/private/canvas/common/index.ts +++ b/x-pack/platform/plugins/private/canvas/common/index.ts @@ -10,4 +10,3 @@ export const UI_SETTINGS = { }; export type { CanvasAppLocator, CanvasAppLocatorParams } from './locator'; -export { CANVAS_APP_LOCATOR } from './locator'; diff --git a/x-pack/platform/plugins/private/canvas/common/locator.ts b/x-pack/platform/plugins/private/canvas/common/locator.ts index 6fd9d4440932..0f5425113a1b 100644 --- a/x-pack/platform/plugins/private/canvas/common/locator.ts +++ b/x-pack/platform/plugins/private/canvas/common/locator.ts @@ -6,6 +6,7 @@ */ import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/common'; +import { CANVAS_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { CANVAS_APP } from './lib/constants'; @@ -18,8 +19,6 @@ export type CanvasAppLocatorParams = { export type CanvasAppLocator = LocatorPublic; -export const CANVAS_APP_LOCATOR = 'CANVAS_APP_LOCATOR'; - export class CanvasAppLocatorDefinition implements LocatorDefinition { id = CANVAS_APP_LOCATOR; diff --git a/x-pack/platform/plugins/private/canvas/public/components/workpad_header/share_menu/utils.ts b/x-pack/platform/plugins/private/canvas/public/components/workpad_header/share_menu/utils.ts index d535d7dceaf0..2ce6b4f52db3 100644 --- a/x-pack/platform/plugins/private/canvas/public/components/workpad_header/share_menu/utils.ts +++ b/x-pack/platform/plugins/private/canvas/public/components/workpad_header/share_menu/utils.ts @@ -7,7 +7,8 @@ import type { RedirectOptions } from '@kbn/share-plugin/public'; import { JobAppParamsPDFV2 } from '@kbn/reporting-export-types-pdf-common'; -import { CanvasAppLocatorParams, CANVAS_APP_LOCATOR } from '../../../../common/locator'; +import { CANVAS_APP_LOCATOR } from '@kbn/deeplinks-analytics'; +import { CanvasAppLocatorParams } from '../../../../common/locator'; import { CanvasWorkpad } from '../../../../types'; export interface CanvasWorkpadSharingData { diff --git a/x-pack/platform/plugins/private/canvas/tsconfig.json b/x-pack/platform/plugins/private/canvas/tsconfig.json index 1c372fabda1d..5b5d1f004b62 100644 --- a/x-pack/platform/plugins/private/canvas/tsconfig.json +++ b/x-pack/platform/plugins/private/canvas/tsconfig.json @@ -89,7 +89,8 @@ "@kbn/presentation-containers", "@kbn/presentation-publishing", "@kbn/react-kibana-context-render", - "@kbn/search-types" + "@kbn/search-types", + "@kbn/deeplinks-analytics" ], "exclude": ["target/**/*"] } diff --git a/x-pack/platform/plugins/private/reporting/public/notifier/job_download_button.tsx b/x-pack/platform/plugins/private/reporting/public/notifier/job_download_button.tsx index 5b7cd42f78a1..0219f8a38790 100644 --- a/x-pack/platform/plugins/private/reporting/public/notifier/job_download_button.tsx +++ b/x-pack/platform/plugins/private/reporting/public/notifier/job_download_button.tsx @@ -21,6 +21,7 @@ export const DownloadButton = ({ getUrl, job }: Props) => { diff --git a/x-pack/test/functional/apps/canvas/reports.ts b/x-pack/test/functional/apps/canvas/reports.ts index 880a8573991d..b26a67f90e00 100644 --- a/x-pack/test/functional/apps/canvas/reports.ts +++ b/x-pack/test/functional/apps/canvas/reports.ts @@ -63,6 +63,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(res.get('content-disposition')).to.equal( 'attachment; filename=The%20Very%20Cool%20Workpad%20for%20PDF%20Tests.pdf' ); + + const jobId = await reporting.getReportJobId(60000); + const reportInfo = await reporting.getReportInfo(jobId); + + // verify "completed" status (no warnings) + expect(reportInfo).to.have.property('status', 'completed'); }); }); }); diff --git a/x-pack/test/functional/page_objects/reporting_page.ts b/x-pack/test/functional/page_objects/reporting_page.ts index 5cdc37efd5e6..2141869635c5 100644 --- a/x-pack/test/functional/page_objects/reporting_page.ts +++ b/x-pack/test/functional/page_objects/reporting_page.ts @@ -12,7 +12,7 @@ import type SuperTest from 'supertest'; import { format as formatUrl } from 'url'; import { promisify } from 'util'; -import { REPORT_TABLE_ID, REPORT_TABLE_ROW_ID } from '@kbn/reporting-common'; +import { INTERNAL_ROUTES, REPORT_TABLE_ID, REPORT_TABLE_ROW_ID } from '@kbn/reporting-common'; import { FtrService } from '../ftr_provider_context'; const writeFileAsync = promisify(fs.writeFile); @@ -37,6 +37,30 @@ export class ReportingPageObject extends FtrService { `); } + async getReportJobId(timeout: number): Promise { + this.log.debug('getReportJobId'); + + try { + // get the report job id from a data attribute on the download button + const jobIdElement = await this.find.byCssSelector('[data-test-jobId]', timeout); + if (!jobIdElement) { + throw new Error('Failed to find report job id.'); + } + const jobId = await jobIdElement.getAttribute('data-test-jobId'); + if (!jobId) { + throw new Error('Failed to find report job id.'); + } + return jobId; + } catch (err) { + let errorText = 'Unknown error'; + if (await this.find.existsByCssSelector('[data-test-errorText]')) { + const errorTextEl = await this.find.byCssSelector('[data-test-errorText]'); + errorText = (await errorTextEl.getAttribute('data-test-errorText')) ?? errorText; + } + throw new Error(`Test report failed: ${errorText}: ${err}`, { cause: err }); + } + } + async getReportURL(timeout: number) { this.log.debug('getReportURL'); @@ -77,6 +101,12 @@ export class ReportingPageObject extends FtrService { return res ?? ''; } + async getReportInfo(jobId: string) { + this.log.debug(`getReportInfo for ${jobId}`); + const response = await this.getResponse(INTERNAL_ROUTES.JOBS.INFO_PREFIX + `/${jobId}`); + return response.body; + } + async getRawReportData(url: string): Promise { this.log.debug(`getRawReportData for ${url}`); const response = await this.getResponse(url);