From 75cc43c9f0862a99e3b8131d263d132a664b7926 Mon Sep 17 00:00:00 2001 From: Corey Robertson Date: Thu, 16 Jan 2020 14:31:20 -0500 Subject: [PATCH] [Canvas] Fixes the Copy Post Url link (#54831) * Fixes the Copy Post Url link * Adds tests Co-authored-by: Elastic Machine --- .../workpad_header/workpad_export/index.ts | 4 +- .../workpad_export/utils.test.ts | 37 +++++++ .../workpad_header/workpad_export/utils.ts | 14 ++- x-pack/legacy/plugins/canvas/public/legacy.ts | 62 +++++++++++ .../legacy/plugins/canvas/public/plugin.tsx | 102 ++++++++++++++++++ 5 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/utils.test.ts create mode 100644 x-pack/legacy/plugins/canvas/public/legacy.ts create mode 100644 x-pack/legacy/plugins/canvas/public/plugin.tsx diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/index.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/index.ts index f677f84362da7f..c56340de10da67 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/index.ts +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/index.ts @@ -58,8 +58,8 @@ export const WorkpadExport = compose( enabled, getExportUrl: type => { if (type === 'pdf') { - const { createPdfUri } = getPdfUrl(workpad, { pageCount }); - return getAbsoluteUrl(createPdfUri); + const pdfUrl = getPdfUrl(workpad, { pageCount }); + return getAbsoluteUrl(pdfUrl); } throw new Error(strings.getUnknownExportErrorMessage(type)); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/utils.test.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/utils.test.ts new file mode 100644 index 00000000000000..ceaf82c1c07d62 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/utils.test.ts @@ -0,0 +1,37 @@ +/* + * 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. + */ + +jest.mock('../../../../common/lib/fetch'); + +import { getPdfUrl, createPdf } from './utils'; +import { workpads } from '../../../../__tests__/fixtures/workpads'; +import { fetch } from '../../../../common/lib/fetch'; + +const addBasePath = jest.fn().mockImplementation(s => `basepath/${s}`); +const workpad = workpads[0]; + +test('getPdfUrl returns the correct url', () => { + const url = getPdfUrl(workpad, { pageCount: 2 }, addBasePath); + + expect(url).toMatchInlineSnapshot( + `"basepath//api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FPhoenix,layout:(dimensions:(height:0,width:0),id:preserve_layout),objectType:'canvas%20workpad',relativeUrls:!(%2Fapp%2Fcanvas%23%2Fexport%2Fworkpad%2Fpdf%2Fbase-workpad%2Fpage%2F1,%2Fapp%2Fcanvas%23%2Fexport%2Fworkpad%2Fpdf%2Fbase-workpad%2Fpage%2F2),title:'base%20workpad')"` + ); +}); + +test('createPdf posts to create the pdf', () => { + createPdf(workpad, { pageCount: 2 }, addBasePath); + + expect(fetch.post).toBeCalled(); + + const args = (fetch.post as jest.MockedFunction).mock.calls[0]; + + expect(args[0]).toMatchInlineSnapshot(`"basepath//api/reporting/generate/printablePdf"`); + expect(args[1]).toMatchInlineSnapshot(` + Object { + "jobParams": "(browserTimezone:America/Phoenix,layout:(dimensions:(height:0,width:0),id:preserve_layout),objectType:'canvas workpad',relativeUrls:!(/app/canvas#/export/workpad/pdf/base-workpad/page/1,/app/canvas#/export/workpad/pdf/base-workpad/page/2),title:'base workpad')", + } + `); +}); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/utils.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/utils.ts index b06bf5a74b528a..10bb2349c3a030 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/utils.ts +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_export/utils.ts @@ -6,6 +6,7 @@ import rison from 'rison-node'; import chrome from 'ui/chrome'; +import { QueryString } from 'ui/utils/query_string'; // @ts-ignore Untyped local. import { fetch } from '../../../../common/lib/fetch'; import { CanvasWorkpad } from '../../../../types'; @@ -24,7 +25,7 @@ interface PdfUrlData { createPdfPayload: { jobParams: string }; } -export function getPdfUrl( +function getPdfUrlParts( { id, name: title, width, height }: CanvasWorkpad, { pageCount }: PageCount ): PdfUrlData { @@ -66,7 +67,16 @@ export function getPdfUrl( }; } +export function getPdfUrl(...args: Arguments): string { + const urlParts = getPdfUrlParts(...args); + + return `${urlParts.createPdfUri}?${QueryString.param( + 'jobParams', + urlParts.createPdfPayload.jobParams + )}`; +} + export function createPdf(...args: Arguments) { - const { createPdfUri, createPdfPayload } = getPdfUrl(...args); + const { createPdfUri, createPdfPayload } = getPdfUrlParts(...args); return fetch.post(createPdfUri, createPdfPayload); } diff --git a/x-pack/legacy/plugins/canvas/public/legacy.ts b/x-pack/legacy/plugins/canvas/public/legacy.ts new file mode 100644 index 00000000000000..61e12893b3e02f --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/legacy.ts @@ -0,0 +1,62 @@ +/* + * 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 { npSetup, npStart } from 'ui/new_platform'; +import { CanvasStartDeps } from './plugin'; // eslint-disable-line import/order + +// @ts-ignore Untyped Kibana Lib +import chrome, { loadingCount } from 'ui/chrome'; // eslint-disable-line import/order +// @ts-ignore Untyped Module +import { uiModules } from 'ui/modules'; // eslint-disable-line import/order +import { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; // eslint-disable-line import/order +import { Storage } from '../../../../../src/plugins/kibana_utils/public'; // eslint-disable-line import/order +// @ts-ignore Untyped Kibana Lib +import { formatMsg } from 'ui/notify/lib/format_msg'; // eslint-disable-line import/order +// @ts-ignore Untyped Kibana Lib +import { QueryString } from 'ui/utils/query_string'; // eslint-disable-line import/order + +const shimCoreSetup = { + ...npSetup.core, +}; +const shimCoreStart = { + ...npStart.core, +}; +const shimSetupPlugins = {}; +const shimStartPlugins: CanvasStartDeps = { + ...npStart.plugins, + __LEGACY: { + // ToDo: Copy directly into canvas + absoluteToParsedUrl, + // ToDo: Copy directly into canvas + formatMsg, + QueryString, + // ToDo: Remove in favor of core.application.register + setRootController: chrome.setRootController, + storage: Storage, + // ToDo: Won't be a part of New Platform. Will need to handle internally + trackSubUrlForApp: chrome.trackSubUrlForApp, + uiModules, + }, +}; + +// These methods are intended to be a replacement for import from 'ui/whatever' +// These will go away once all of this one plugin start/setup properly +// injects wherever these need to go. +export function getCoreSetup() { + return shimCoreSetup; +} + +export function getCoreStart() { + return shimCoreStart; +} + +export function getSetupPlugins() { + return shimSetupPlugins; +} + +export function getStartPlugins() { + return shimStartPlugins; +} diff --git a/x-pack/legacy/plugins/canvas/public/plugin.tsx b/x-pack/legacy/plugins/canvas/public/plugin.tsx new file mode 100644 index 00000000000000..155eef99632a0d --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/plugin.tsx @@ -0,0 +1,102 @@ +/* + * 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 React from 'react'; +import ReactDOM from 'react-dom'; +import { Chrome } from 'ui/chrome'; +import { IModule } from 'angular'; +import { i18n } from '@kbn/i18n'; +import { Storage } from '../../../../../src/plugins/kibana_utils/public'; +import { CoreSetup, CoreStart, Plugin } from '../../../../../src/core/public'; +// @ts-ignore: Untyped Local +import { initStateManagement, initLocationProvider } from './angular/config'; +import { CanvasRootControllerFactory } from './angular/controllers'; +// @ts-ignore: Untypled Local +import { initStore } from './angular/services'; +// @ts-ignore: untyped local component +import { HelpMenu } from './components/help_menu/help_menu'; +// @ts-ignore: untyped local +import { loadExpressionTypes } from './lib/load_expression_types'; +// @ts-ignore: untyped local +import { loadTransitions } from './lib/load_transitions'; +import { initLoadingIndicator } from './lib/loading_indicator'; +import { getDocumentationLinks } from './lib/documentation_links'; + +// @ts-ignore: untyped local +import { initClipboard } from './lib/clipboard'; + +export { CoreStart }; +/** + * These are the private interfaces for the services your plugin depends on. + * @internal + */ +// This interface will be built out as we require other plugins for setup +export interface CanvasSetupDeps {} // eslint-disable-line @typescript-eslint/no-empty-interface +export interface CanvasStartDeps { + __LEGACY: { + absoluteToParsedUrl: (url: string, basePath: string) => any; + formatMsg: any; + QueryString: any; + setRootController: Chrome['setRootController']; + storage: typeof Storage; + trackSubUrlForApp: Chrome['trackSubUrlForApp']; + uiModules: { + get: (module: string) => IModule; + }; + }; +} + +/** + * These are the interfaces with your public contracts. You should export these + * for other plugins to use in _their_ `SetupDeps`/`StartDeps` interfaces. + * @public + */ +// These interfaces are empty for now but will be populate as we need to export +// things for other plugins to use at startup or runtime +export interface CanvasSetup {} // eslint-disable-line @typescript-eslint/no-empty-interface +export interface CanvasStart {} // eslint-disable-line @typescript-eslint/no-empty-interface + +/** @internal */ +export class CanvasPlugin + implements Plugin { + public setup(core: CoreSetup, plugins: CanvasSetupDeps) { + // This is where any setup actions need to occur. + // Things like registering functions to the interpreter that need + // to be available everywhere, not just in Canvas + + return {}; + } + + public start(core: CoreStart, plugins: CanvasStartDeps) { + loadExpressionTypes(); + loadTransitions(); + + initStateManagement(core, plugins); + initLocationProvider(core, plugins); + initStore(core, plugins); + initClipboard(plugins.__LEGACY.storage); + initLoadingIndicator(core.http.addLoadingCountSource); + + const CanvasRootController = CanvasRootControllerFactory(core, plugins); + plugins.__LEGACY.setRootController('canvas', CanvasRootController); + core.chrome.setHelpExtension({ + appName: i18n.translate('xpack.canvas.helpMenu.appName', { + defaultMessage: 'Canvas', + }), + links: [ + { + linkType: 'documentation', + href: getDocumentationLinks().canvas, + }, + ], + content: domNode => () => { + ReactDOM.render(, domNode); + }, + }); + + return {}; + } +}