Skip to content

Commit

Permalink
reintroduced pdfv2 export type, see https://github.com/elastic/kibana…
Browse files Browse the repository at this point in the history
  • Loading branch information
jloleysens committed Jun 1, 2021
1 parent af84716 commit e582439
Show file tree
Hide file tree
Showing 29 changed files with 1,058 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ export function ShowShareModal({
objectType: 'dashboard',
sharingData: {
title: savedDashboard.title,
body: {
locator: {
version: '1',
id: 'test', // TODO: Use real dashboard locator ID
value: dashboardStateManager.appState,
},
},
Expand Down
6 changes: 4 additions & 2 deletions x-pack/plugins/reporting/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,18 @@ export const CSV_REPORT_TYPE = 'CSV';
export const CSV_JOB_TYPE = 'csv_searchsource';

export const PDF_REPORT_TYPE = 'printablePdf';
export const PDF_REPORT_TYPE_V2 = 'printablePdfV2';
export const PDF_JOB_TYPE = 'printable_pdf';
export const PDF_JOB_TYPE_V2 = 'printable_pdf_v2';

export const PNG_REPORT_TYPE = 'PNG';
export const PNG_REPORT_TYPE_V2 = 'PNGV2';
export const PNG_JOB_TYPE = 'PNG';
export const PNG_JOB_TYPE_V2 = 'PNG_v2';
export const PNG_JOB_TYPE_V2 = 'PNGV2';

export const CSV_SEARCHSOURCE_IMMEDIATE_TYPE = 'csv_searchsource_immediate';

export const REPORT_BODY_STORE_KEY = '__reportBodyStore__';
export const REPORT_LOCATOR_STORE_KEY = '__reportLocatorStore__';

// This is deprecated because it lacks support for runtime fields
// but the extension points are still needed for pre-existing scripted automation, until 8.0
Expand Down
13 changes: 13 additions & 0 deletions x-pack/plugins/reporting/common/job_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { isObject } from 'lodash';

// TODO: Remove this code once everyone is using the new PDF format, then we can also remove the legacy
// export type entirely
export const isJobV2Params = ({ sharingData }: { sharingData: Record<string, unknown> }): boolean =>
isObject(sharingData.locator);
7 changes: 7 additions & 0 deletions x-pack/plugins/reporting/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,10 @@ export type DownloadReportFn = (jobId: JobId) => DownloadLink;

type ManagementLink = string;
export type ManagementLinkFn = () => ManagementLink;

// TODO: review once real locator types are available
export interface Locator {
id: string;
version?: string;
params: object;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import type { IUiSettingsClient, ToastsSetup } from 'src/core/public';
import { CoreStart } from 'src/core/public';
import type { ShareContext } from '../../../../../src/plugins/share/public';
import type { LicensingPluginSetup } from '../../../licensing/public';
import type { LayoutParams } from '../../common/types';
import type { LayoutParams, Locator } from '../../common/types';
import { isJobV2Params } from '../../common/job_utils';
import type { JobParamsPNG } from '../../server/export_types/png/types';
import type { JobParamsPDF } from '../../server/export_types/printable_pdf/types';
import type { JobParamsPDF, JobParamsPDFV2 } from '../../server/export_types/printable_pdf/types';
import { ScreenCapturePanelContent } from '../components/screen_capture_panel_content_lazy';
import { checkLicense } from '../lib/license_check';
import type { ReportingAPIClient } from '../lib/reporting_api_client';
Expand All @@ -26,10 +27,6 @@ interface JobParamsProviderOptions {
objectType: string;
browserTimezone: string;
sharingData: Record<string, unknown>;
body?: {
version?: string;
value: object;
};
}

const jobParamsProvider = ({
Expand All @@ -42,11 +39,10 @@ const jobParamsProvider = ({
browserTimezone,
layout: sharingData.layout as LayoutParams,
title: sharingData.title as string,
body: sharingData.body as { version?: string; value: object },
};
};

const getPdfJobParams = (opts: JobParamsProviderOptions) => (): JobParamsPDF => {
const getPdfV1JobParams = (opts: JobParamsProviderOptions) => (): JobParamsPDF => {
// Relative URL must have URL prefix (Spaces ID prefix), but not server basePath
// Replace hashes with original RISON values.
const relativeUrl = opts.shareableUrl.replace(
Expand All @@ -60,6 +56,17 @@ const getPdfJobParams = (opts: JobParamsProviderOptions) => (): JobParamsPDF =>
};
};

const getPdfV2JobParams = (opts: JobParamsProviderOptions) => (): JobParamsPDFV2 => {
const locator = opts.sharingData.locator as Locator;
return {
...jobParamsProvider(opts),
locator,
};
};

const getPdfJobParams = (opts: JobParamsProviderOptions) =>
isJobV2Params(opts) ? getPdfV2JobParams(opts) : getPdfV1JobParams(opts);

const getPngJobParams = (opts: JobParamsProviderOptions) => (): JobParamsPNG => {
// Replace hashes with original RISON values.
const relativeUrl = opts.shareableUrl.replace(
Expand Down Expand Up @@ -154,6 +161,14 @@ export const reportingScreenshotShareProvider = ({
defaultMessage: 'PNG Reports',
});

const jobProviderOptions: JobParamsProviderOptions = {
shareableUrl,
apiClient,
objectType,
browserTimezone,
sharingData,
};

const panelPng = {
shareMenuItem: {
name: pngPanelTitle,
Expand All @@ -172,13 +187,7 @@ export const reportingScreenshotShareProvider = ({
toasts={toasts}
reportType="png"
objectId={objectId}
getJobParams={getPngJobParams({
shareableUrl,
apiClient,
objectType,
browserTimezone,
sharingData,
})}
getJobParams={getPngJobParams(jobProviderOptions)}
isDirty={isDirty}
onClose={onClose}
/>
Expand Down Expand Up @@ -206,15 +215,9 @@ export const reportingScreenshotShareProvider = ({
<ScreenCapturePanelContent
apiClient={apiClient}
toasts={toasts}
reportType="printablePdf"
reportType={isJobV2Params(jobProviderOptions) ? 'printablePdfV2' : 'printablePdf'}
objectId={objectId}
getJobParams={getPdfJobParams({
shareableUrl,
apiClient,
objectType,
browserTimezone,
sharingData,
})}
getJobParams={getPdfJobParams(jobProviderOptions)}
isDirty={isDirty}
onClose={onClose}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import { parse as parseUrl } from 'url';
import { getDisallowedOutgoingUrlError } from '../';
import { ReportingCore } from '../../..';
import { KBN_SCREENSHOT_MODE_HEADER } from '../../../../../../../src/plugins/screenshot_mode/server';
import { REPORT_BODY_STORE_KEY } from '../../../../common/constants';
import { REPORT_LOCATOR_STORE_KEY } from '../../../../common/constants';
import { ConditionalHeaders, ConditionalHeadersConditions } from '../../../export_types/common';
import { Locator } from '../../../../common/types';
import { LevelLogger } from '../../../lib';
import { ViewZoomWidthHeight } from '../../../lib/layouts/layout';
import { ElementPosition } from '../../../lib/screenshots';
Expand Down Expand Up @@ -95,12 +96,12 @@ export class HeadlessChromiumDriver {
conditionalHeaders,
waitForSelector: pageLoadSelector,
timeout,
body,
locator,
}: {
conditionalHeaders: ConditionalHeaders;
waitForSelector: string;
timeout: number;
body?: object;
locator?: Locator;
},
logger: LevelLogger
): Promise<void> {
Expand All @@ -115,22 +116,24 @@ export class HeadlessChromiumDriver {
*/
await this.page.evaluateOnNewDocument(this.core.getEnableScreenshotMode());

/**
* Create the "body" store in the page's context. This value is provided by the client and
* should be considered fully opaque to us.
*/
await this.page.evaluateOnNewDocument(
(storeName: string, value?: object) => {
Object.defineProperty(window, storeName, {
enumerable: true,
writable: false,
configurable: false,
value,
});
},
REPORT_BODY_STORE_KEY,
body
);
if (locator) {
/**
* Create the "locator" store in the page's context. This value is provided by the client and
* should be considered fully opaque to us.
*/
await this.page.evaluateOnNewDocument(
(storeName: string, value?: object) => {
Object.defineProperty(window, storeName, {
enumerable: true,
writable: false,
configurable: false,
value,
});
},
REPORT_LOCATOR_STORE_KEY,
locator
);
}

await this.page.setRequestInterception(true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const createJobFnFactory: CreateJobFnFactory<
const crypto = cryptoFactory(config.get('encryptionKey'));

return async function createJob(
{ title, relativeUrls, browserTimezone, layout, objectType, body },
{ title, relativeUrls, browserTimezone, layout, objectType },
context,
req
) {
Expand All @@ -33,7 +33,6 @@ export const createJobFnFactory: CreateJobFnFactory<
layout,
relativeUrls,
title,
body,
objectType,
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const runTaskFnFactory: RunTaskFnFactory<
mergeMap(({ logo, conditionalHeaders }) => {
const urls = getFullUrls(config, job);

const { browserTimezone, layout, title, body } = job;
const { browserTimezone, layout, title } = job;

if (apmGetAssets) apmGetAssets.end();

Expand All @@ -57,8 +57,7 @@ export const runTaskFnFactory: RunTaskFnFactory<
browserTimezone,
conditionalHeaders,
layout,
logo,
body
logo
);
}),
map(({ buffer, warnings }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ export async function generatePdfObservableFactory(reporting: ReportingCore) {
browserTimezone: string | undefined,
conditionalHeaders: ConditionalHeaders,
layoutParams: LayoutParams,
logo?: string,
body?: object
logo?: string
): Rx.Observable<{ buffer: Buffer | null; warnings: string[] }> {
const tracker = getTracker();
tracker.startLayout();
Expand All @@ -52,7 +51,6 @@ export async function generatePdfObservableFactory(reporting: ReportingCore) {
const screenshots$ = getScreenshots({
logger,
urls,
body,
conditionalHeaders,
layout,
browserTimezone,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,17 @@
import { LayoutParams } from '../../lib/layouts';
import { BaseParams, BasePayload } from '../../types';

interface BaseParamsPDF<B extends object = object> {
interface BaseParamsPDF {
layout: LayoutParams;
forceNow?: string;
// TODO: Add comment explaining this field
relativeUrls: string[];

/**
* An optional value that will provided to the renderer (browser).
*
* This provides a way for capturing and forwarding any unsaved state from the consumer requesting a report to the
* server-side report generator.
*
* Please note: this value will be stored and re-used whenever a specific report is generated. Therefore it is
* advisable to assign a version to the body value or to implement some way of migrating values for use over time
* as a report may be requested again in future with a body value created in legacy versions of the reporting consumer.
*/
body?: {
version?: string;
/**
* This value must be serializable for sending over the wire.
*/
value: B;
};
}

// Job params: structure of incoming user request data, after being parsed from RISON
export type JobParamsPDF = BaseParamsPDF & BaseParams;

// Job payload: structure of stored job data provided by create_job
export type TaskPayloadPDF = BaseParamsPDF & BasePayload;

export * from './v2/types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { cryptoFactory } from '../../../lib';
import { CreateJobFn, CreateJobFnFactory } from '../../../types';
import { JobParamsPDFV2, TaskPayloadPDFV2 } from './types';

export const createJobFnFactory: CreateJobFnFactory<
CreateJobFn<JobParamsPDFV2, TaskPayloadPDFV2>
> = function createJobFactoryFn(reporting, logger) {
const config = reporting.getConfig();
const crypto = cryptoFactory(config.get('encryptionKey'));

return async function createJob(
{ title, locator, browserTimezone, layout, objectType },
context,
req
) {
const serializedEncryptedHeaders = await crypto.encrypt(req.headers);

return {
headers: serializedEncryptedHeaders,
spaceId: reporting.getSpaceId(req, logger),
browserTimezone,
forceNow: new Date().toISOString(),
layout,
locator,
title,
objectType,
};
};
};
Loading

0 comments on commit e582439

Please sign in to comment.