mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[Reporting] Make "ScreenCapturePanel" shareable for Canvas (#100623)
* use ScreenCapturePanel component in Canvas * use smaller state object * add comment about canvas-specific shared component * fix example * fix toast error * fix i18n * fix data-test-subj Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
274bbdc628
commit
3559d375b6
29 changed files with 1755 additions and 622 deletions
|
@ -6,8 +6,9 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
EuiCard,
|
||||
EuiCode,
|
||||
EuiContextMenu,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHorizontalRule,
|
||||
|
@ -17,7 +18,7 @@ import {
|
|||
EuiPageContent,
|
||||
EuiPageContentBody,
|
||||
EuiPageHeader,
|
||||
EuiPanel,
|
||||
EuiPopover,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
@ -50,7 +51,19 @@ export const ReportingExampleApp = ({
|
|||
reporting,
|
||||
screenshotMode,
|
||||
}: ReportingExampleAppDeps) => {
|
||||
const { getDefaultLayoutSelectors, ReportingAPIClient } = reporting;
|
||||
const { getDefaultLayoutSelectors } = reporting;
|
||||
|
||||
// Context Menu
|
||||
const [isPopoverOpen, setPopover] = useState(false);
|
||||
const onButtonClick = () => {
|
||||
setPopover(!isPopoverOpen);
|
||||
};
|
||||
|
||||
const closePopover = () => {
|
||||
setPopover(false);
|
||||
};
|
||||
|
||||
// Async Logos
|
||||
const [logos, setLogos] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -61,7 +74,7 @@ export const ReportingExampleApp = ({
|
|||
});
|
||||
});
|
||||
|
||||
const getPDFJobParams = (): JobParamsPDF => {
|
||||
const getPDFJobParamsDefault = (): JobParamsPDF => {
|
||||
return {
|
||||
layout: {
|
||||
id: constants.LAYOUT_TYPES.PRESERVE_LAYOUT,
|
||||
|
@ -73,7 +86,40 @@ export const ReportingExampleApp = ({
|
|||
};
|
||||
};
|
||||
|
||||
// Render the application DOM.
|
||||
const panels = [
|
||||
{ id: 0, items: [{ name: 'PDF Reports', icon: 'document', panel: 1 }] },
|
||||
{
|
||||
id: 1,
|
||||
initialFocusedItemIndex: 1,
|
||||
title: 'PDF Reports',
|
||||
items: [
|
||||
{ name: 'No Layout Option', icon: 'document', panel: 2 },
|
||||
{ name: 'Canvas Layout Option', icon: 'canvasApp', panel: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'No Layout Option',
|
||||
content: (
|
||||
<reporting.components.ReportingPanelPDF
|
||||
getJobParams={getPDFJobParamsDefault}
|
||||
onClose={closePopover}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Canvas Layout Option',
|
||||
content: (
|
||||
<reporting.components.ReportingPanelPDF
|
||||
layoutOption="canvas"
|
||||
getJobParams={getPDFJobParamsDefault}
|
||||
onClose={closePopover}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Router basename={basename}>
|
||||
<I18nProvider>
|
||||
|
@ -87,34 +133,21 @@ export const ReportingExampleApp = ({
|
|||
<EuiPageContent>
|
||||
<EuiPageContentBody>
|
||||
<EuiText>
|
||||
<p>
|
||||
Use the <EuiCode>ReportingStart.components.ScreenCapturePanel</EuiCode>{' '}
|
||||
component to add the Reporting panel to your page.
|
||||
</p>
|
||||
<p>Example of a Sharing menu using components from Reporting</p>
|
||||
|
||||
<EuiPopover
|
||||
id="contextMenuExample"
|
||||
button={<EuiButton onClick={onButtonClick}>Share</EuiButton>}
|
||||
isOpen={isPopoverOpen}
|
||||
closePopover={closePopover}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downLeft"
|
||||
>
|
||||
<EuiContextMenu initialPanelId={0} panels={panels} />
|
||||
</EuiPopover>
|
||||
|
||||
<EuiHorizontalRule />
|
||||
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiPanel>
|
||||
<reporting.components.ScreenCapturePanel
|
||||
apiClient={new ReportingAPIClient(http)}
|
||||
toasts={notifications.toasts}
|
||||
reportType={constants.PDF_REPORT_TYPE}
|
||||
getJobParams={getPDFJobParams}
|
||||
objectId="Visualization:Id:ToEnsure:Visualization:IsSaved"
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiHorizontalRule />
|
||||
|
||||
<p>
|
||||
The logos below are in a <EuiCode>data-shared-items-container</EuiCode> element
|
||||
for Reporting.
|
||||
</p>
|
||||
|
||||
<div data-shared-items-container data-shared-items-count="4">
|
||||
<EuiFlexGroup gutterSize="l">
|
||||
{logos.map((item, index) => (
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { BOLD_MD_TOKEN, CANVAS, HTML, JSON, KIBANA, PDF, POST, URL, ZIP } from './constants';
|
||||
import { BOLD_MD_TOKEN, CANVAS, HTML, JSON, PDF, URL, ZIP } from './constants';
|
||||
|
||||
export const ComponentStrings = {
|
||||
AddEmbeddableFlyout: {
|
||||
|
@ -1418,95 +1418,10 @@ export const ComponentStrings = {
|
|||
URL,
|
||||
},
|
||||
}),
|
||||
getCopyReportingConfigMessage: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.copyReportingConfigMessage', {
|
||||
defaultMessage: 'Copied reporting configuration to clipboard',
|
||||
}),
|
||||
getCopyShareConfigMessage: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.copyShareConfigMessage', {
|
||||
defaultMessage: 'Copied share markup to clipboard',
|
||||
}),
|
||||
getExportPDFErrorTitle: (workpadName: string) =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.exportPDFErrorMessage', {
|
||||
defaultMessage: "Failed to create {PDF} for '{workpadName}'",
|
||||
values: {
|
||||
PDF,
|
||||
workpadName,
|
||||
},
|
||||
}),
|
||||
getExportPDFMessage: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.exportPDFMessage', {
|
||||
defaultMessage: 'Exporting {PDF}. You can track the progress in Management.',
|
||||
values: {
|
||||
PDF,
|
||||
},
|
||||
}),
|
||||
getExportPDFTitle: (workpadName: string) =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.exportPDFTitle', {
|
||||
defaultMessage: "{PDF} export of workpad '{workpadName}'",
|
||||
values: {
|
||||
PDF,
|
||||
workpadName,
|
||||
},
|
||||
}),
|
||||
getPDFFullPageLayoutHelpText: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.FullPageLayoutHelpText', {
|
||||
defaultMessage: 'Remove borders and footer logo',
|
||||
}),
|
||||
getPDFFullPageLayoutLabel: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.FullPageLayoutLabel', {
|
||||
defaultMessage: 'Full page layout',
|
||||
}),
|
||||
getPDFPanelAdvancedOptionsLabel: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.pdfPanelAdvancedOptionsLabel', {
|
||||
defaultMessage: 'Advanced options',
|
||||
}),
|
||||
getPDFPanelCopyAriaLabel: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyAriaLabel', {
|
||||
defaultMessage:
|
||||
'Alternatively, you can generate a {PDF} from a script or with Watcher by using this {URL}. Press Enter to copy the {URL} to clipboard.',
|
||||
values: {
|
||||
PDF,
|
||||
URL,
|
||||
},
|
||||
}),
|
||||
getPDFPanelCopyButtonLabel: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyButtonLabel', {
|
||||
defaultMessage: 'Copy {POST} {URL}',
|
||||
values: {
|
||||
POST,
|
||||
URL,
|
||||
},
|
||||
}),
|
||||
getPDFPanelCopyDescription: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyDescription', {
|
||||
defaultMessage:
|
||||
'Alternatively, copy this {POST} {URL} to call generation from outside {KIBANA} or from Watcher.',
|
||||
values: {
|
||||
POST,
|
||||
KIBANA,
|
||||
URL,
|
||||
},
|
||||
}),
|
||||
getPDFPanelGenerateButtonLabel: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.pdfPanelGenerateButtonLabel', {
|
||||
defaultMessage: 'Generate {PDF}',
|
||||
values: {
|
||||
PDF,
|
||||
},
|
||||
}),
|
||||
getPDFPanelGenerateDescription: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.pdfPanelGenerateDescription', {
|
||||
defaultMessage:
|
||||
'{PDF}s can take a minute or two to generate based on the size of your workpad.',
|
||||
values: {
|
||||
PDF,
|
||||
},
|
||||
}),
|
||||
getPDFPanelOptionsLabel: () =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.pdfPanelOptionsLabel', {
|
||||
defaultMessage: 'Options',
|
||||
}),
|
||||
getShareableZipErrorTitle: (workpadName: string) =>
|
||||
i18n.translate('xpack.canvas.workpadHeaderShareMenu.shareWebsiteErrorTitle', {
|
||||
defaultMessage:
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
"kibanaUtils",
|
||||
"lens",
|
||||
"maps",
|
||||
"reporting",
|
||||
"savedObjects",
|
||||
"visualizations"
|
||||
]
|
||||
|
|
|
@ -1,6 +1,37 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots components/WorkpadHeader/ShareMenu default 1`] = `
|
||||
exports[`Storyshots components/WorkpadHeader/ShareMenu minimal 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownLeft"
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor"
|
||||
>
|
||||
<button
|
||||
aria-label="Share this workpad"
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--xSmall"
|
||||
data-test-subj="shareTopNavButton"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonContent euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Share
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/WorkpadHeader/ShareMenu with Reporting 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownLeft"
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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 { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import React from 'react';
|
||||
import { PDFPanel } from '../pdf_panel';
|
||||
|
||||
storiesOf('components/WorkpadHeader/ShareMenu/PDFPanel', module)
|
||||
.addParameters({
|
||||
info: {
|
||||
inline: true,
|
||||
styles: {
|
||||
infoBody: {
|
||||
margin: 20,
|
||||
},
|
||||
infoStory: {
|
||||
margin: '20px 30px',
|
||||
width: '290px',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.add('default', () => (
|
||||
<div className="euiPanel">
|
||||
<PDFPanel
|
||||
getPdfURL={() => 'PDF URL String'}
|
||||
onCopy={action('onCopy')}
|
||||
onExport={action('onExport')}
|
||||
/>
|
||||
</div>
|
||||
));
|
|
@ -5,19 +5,34 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { platformService } from '../../../../services/stubs/platform';
|
||||
import { reportingService } from '../../../../services/stubs/reporting';
|
||||
import { ShareMenu } from '../share_menu.component';
|
||||
|
||||
storiesOf('components/WorkpadHeader/ShareMenu', module).add('default', () => (
|
||||
storiesOf('components/WorkpadHeader/ShareMenu', module).add('minimal', () => (
|
||||
<ShareMenu
|
||||
includeReporting={true}
|
||||
onCopy={action('onCopy')}
|
||||
onExport={action('onExport')}
|
||||
getExportUrl={(type: string) => {
|
||||
action(`getExportUrl('${type}')`);
|
||||
return type;
|
||||
sharingData={{
|
||||
workpad: { id: 'coolworkpad', name: 'Workpad of Cool', height: 10, width: 7 },
|
||||
pageCount: 11,
|
||||
}}
|
||||
sharingServices={{ basePath: platformService.getBasePathInterface() }}
|
||||
onExport={action('onExport')}
|
||||
/>
|
||||
));
|
||||
|
||||
storiesOf('components/WorkpadHeader/ShareMenu', module).add('with Reporting', () => (
|
||||
<ShareMenu
|
||||
sharingData={{
|
||||
workpad: { id: 'coolworkpad', name: 'Workpad of Cool', height: 10, width: 7 },
|
||||
pageCount: 11,
|
||||
}}
|
||||
sharingServices={{
|
||||
basePath: platformService.getBasePathInterface(),
|
||||
reporting: reportingService.start,
|
||||
}}
|
||||
onExport={action('onExport')}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* 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 React, { useState } from 'react';
|
||||
import {
|
||||
EuiAccordion,
|
||||
EuiButton,
|
||||
EuiFormRow,
|
||||
EuiHorizontalRule,
|
||||
EuiSpacer,
|
||||
EuiSwitch,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { Clipboard } from '../../clipboard';
|
||||
import { LayoutType } from './utils';
|
||||
|
||||
import { ComponentStrings } from '../../../../i18n/components';
|
||||
const { WorkpadHeaderShareMenu: strings } = ComponentStrings;
|
||||
|
||||
interface Props {
|
||||
/** Retrieve URL that will invoke PDF Report generation. */
|
||||
getPdfURL: (layout: LayoutType) => string;
|
||||
/** Handler to invoke when the PDF is exported */
|
||||
onExport: (layout: LayoutType) => void;
|
||||
/** Handler to invoke when the URL is copied to the clipboard. */
|
||||
onCopy: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A panel displayed in the Export Menu with options in which to generate PDF Reports.
|
||||
*/
|
||||
export const PDFPanel = ({ getPdfURL, onExport, onCopy }: Props) => {
|
||||
const [reportLayout, setReportLayout] = useState<LayoutType>('preserve_layout');
|
||||
|
||||
return (
|
||||
<div className="canvasShareMenu__panelContent">
|
||||
<EuiText size="s">
|
||||
<p>{strings.getPDFPanelGenerateDescription()}</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiTitle size="xxs">
|
||||
<h6>{strings.getPDFPanelOptionsLabel()}</h6>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFormRow helpText={strings.getPDFFullPageLayoutHelpText()}>
|
||||
<EuiSwitch
|
||||
label={strings.getPDFFullPageLayoutLabel()}
|
||||
checked={reportLayout === 'canvas'}
|
||||
onChange={() =>
|
||||
reportLayout === 'canvas'
|
||||
? setReportLayout('preserve_layout')
|
||||
: setReportLayout('canvas')
|
||||
}
|
||||
data-test-subj="reportModeToggle"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiButton
|
||||
fill
|
||||
onClick={() => onExport(reportLayout)}
|
||||
size="s"
|
||||
style={{ width: '100%' }}
|
||||
data-test-subj="generateReportButton"
|
||||
>
|
||||
{strings.getPDFPanelGenerateButtonLabel()}
|
||||
</EuiButton>
|
||||
<EuiHorizontalRule
|
||||
margin="s"
|
||||
style={{ width: 'auto', marginLeft: '-16px', marginRight: '-16px' }}
|
||||
/>
|
||||
<EuiAccordion
|
||||
id="advanced-options"
|
||||
buttonContent={strings.getPDFPanelAdvancedOptionsLabel()}
|
||||
paddingSize="none"
|
||||
>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s">
|
||||
<p>{strings.getPDFPanelCopyDescription()}</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<Clipboard content={getPdfURL(reportLayout)} onCopy={onCopy}>
|
||||
<EuiButton
|
||||
iconType="copy"
|
||||
size="s"
|
||||
style={{ width: '100%' }}
|
||||
aria-label={strings.getPDFPanelCopyAriaLabel()}
|
||||
>
|
||||
{strings.getPDFPanelCopyButtonLabel()}
|
||||
</EuiButton>
|
||||
</Clipboard>
|
||||
</EuiAccordion>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -5,47 +5,47 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { FunctionComponent, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EuiButtonEmpty, EuiContextMenu, EuiIcon } from '@elastic/eui';
|
||||
import { IBasePath } from 'kibana/public';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FunctionComponent, useState } from 'react';
|
||||
import { ReportingStart } from '../../../../../reporting/public';
|
||||
import { ComponentStrings } from '../../../../i18n/components';
|
||||
import { flattenPanelTree } from '../../../lib/flatten_panel_tree';
|
||||
import { Popover, ClosePopoverFn } from '../../popover';
|
||||
import { PDFPanel } from './pdf_panel';
|
||||
import { ClosePopoverFn, Popover } from '../../popover';
|
||||
import { ShareWebsiteFlyout } from './flyout';
|
||||
import { LayoutType } from './utils';
|
||||
import { CanvasWorkpadSharingData, getPdfJobParams } from './utils';
|
||||
|
||||
const { WorkpadHeaderShareMenu: strings } = ComponentStrings;
|
||||
|
||||
type CopyTypes = 'pdf' | 'reportingConfig';
|
||||
type ExportTypes = 'pdf' | 'json';
|
||||
type ExportUrlTypes = 'pdf';
|
||||
type CloseTypes = 'share';
|
||||
|
||||
export type OnCopyFn = (type: CopyTypes) => void;
|
||||
export type OnExportFn = (type: ExportTypes, layout?: LayoutType) => void;
|
||||
export type OnExportFn = (type: ExportTypes) => void;
|
||||
export type OnCloseFn = (type: CloseTypes) => void;
|
||||
export type GetExportUrlFn = (type: ExportUrlTypes, layout: LayoutType) => string;
|
||||
|
||||
export interface Props {
|
||||
/** Flag to include the Reporting option only if Reporting is enabled */
|
||||
includeReporting: boolean;
|
||||
/** Handler to invoke when an export URL is copied to the clipboard. */
|
||||
onCopy: OnCopyFn;
|
||||
/** Canvas workpad to export as PDF **/
|
||||
sharingData: CanvasWorkpadSharingData;
|
||||
sharingServices: {
|
||||
/** BasePath dependency **/
|
||||
basePath: IBasePath;
|
||||
/** Reporting dependency **/
|
||||
reporting?: ReportingStart;
|
||||
};
|
||||
/** Handler to invoke when an end product is exported. */
|
||||
onExport: OnExportFn;
|
||||
/** Handler to retrive an export URL based on the type of export requested. */
|
||||
getExportUrl: GetExportUrlFn;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Menu for Exporting a Workpad from Canvas.
|
||||
*/
|
||||
export const ShareMenu: FunctionComponent<Props> = ({
|
||||
includeReporting,
|
||||
onCopy,
|
||||
sharingData,
|
||||
sharingServices: services,
|
||||
onExport,
|
||||
getExportUrl,
|
||||
}) => {
|
||||
const [showFlyout, setShowFlyout] = useState(false);
|
||||
|
||||
|
@ -53,22 +53,6 @@ export const ShareMenu: FunctionComponent<Props> = ({
|
|||
setShowFlyout(false);
|
||||
};
|
||||
|
||||
const getPDFPanel = (closePopover: ClosePopoverFn) => {
|
||||
return (
|
||||
<PDFPanel
|
||||
getPdfURL={(layoutType: LayoutType) => getExportUrl('pdf', layoutType)}
|
||||
onExport={(layoutType) => {
|
||||
onExport('pdf', layoutType);
|
||||
closePopover();
|
||||
}}
|
||||
onCopy={() => {
|
||||
onCopy('pdf');
|
||||
closePopover();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const getPanelTree = (closePopover: ClosePopoverFn) => ({
|
||||
id: 0,
|
||||
items: [
|
||||
|
@ -80,14 +64,20 @@ export const ShareMenu: FunctionComponent<Props> = ({
|
|||
closePopover();
|
||||
},
|
||||
},
|
||||
includeReporting
|
||||
services.reporting != null
|
||||
? {
|
||||
name: strings.getShareDownloadPDFTitle(),
|
||||
icon: 'document',
|
||||
panel: {
|
||||
id: 1,
|
||||
title: strings.getShareDownloadPDFTitle(),
|
||||
content: getPDFPanel(closePopover),
|
||||
content: (
|
||||
<services.reporting.components.ReportingPanelPDF
|
||||
getJobParams={() => getPdfJobParams(sharingData, services.basePath)}
|
||||
layoutOption="canvas"
|
||||
onClose={closePopover}
|
||||
/>
|
||||
),
|
||||
},
|
||||
'data-test-subj': 'sharePanel-PDFReports',
|
||||
}
|
||||
|
@ -132,8 +122,5 @@ export const ShareMenu: FunctionComponent<Props> = ({
|
|||
};
|
||||
|
||||
ShareMenu.propTypes = {
|
||||
includeReporting: PropTypes.bool.isRequired,
|
||||
onCopy: PropTypes.func.isRequired,
|
||||
onExport: PropTypes.func.isRequired,
|
||||
getExportUrl: PropTypes.func.isRequired,
|
||||
};
|
||||
|
|
|
@ -7,16 +7,12 @@
|
|||
|
||||
import { connect } from 'react-redux';
|
||||
import { compose, withProps } from 'recompose';
|
||||
import { jobCompletionNotifications } from '../../../../../../plugins/reporting/public';
|
||||
import { getWorkpad, getPages } from '../../../state/selectors/workpad';
|
||||
import { getWindow } from '../../../lib/get_window';
|
||||
import { downloadWorkpad } from '../../../lib/download_workpad';
|
||||
import { ShareMenu as Component, Props as ComponentProps } from './share_menu.component';
|
||||
import { getPdfUrl, createPdf } from './utils';
|
||||
import { State, CanvasWorkpad } from '../../../../types';
|
||||
import { withServices, WithServicesProps } from '../../../services';
|
||||
|
||||
import { ComponentStrings } from '../../../../i18n';
|
||||
import { CanvasWorkpad, State } from '../../../../types';
|
||||
import { downloadWorkpad } from '../../../lib/download_workpad';
|
||||
import { withServices, WithServicesProps } from '../../../services';
|
||||
import { getPages, getWorkpad } from '../../../state/selectors/workpad';
|
||||
import { Props as ComponentProps, ShareMenu as Component } from './share_menu.component';
|
||||
|
||||
const { WorkpadHeaderShareMenu: strings } = ComponentStrings;
|
||||
|
||||
|
@ -25,17 +21,6 @@ const mapStateToProps = (state: State) => ({
|
|||
pageCount: getPages(state).length,
|
||||
});
|
||||
|
||||
const getAbsoluteUrl = (path: string) => {
|
||||
const { location } = getWindow();
|
||||
|
||||
if (!location) {
|
||||
return path;
|
||||
} // fallback for mocked window object
|
||||
|
||||
const { protocol, hostname, port } = location;
|
||||
return `${protocol}//${hostname}:${port}${path}`;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
workpad: CanvasWorkpad;
|
||||
pageCount: number;
|
||||
|
@ -45,63 +30,28 @@ export const ShareMenu = compose<ComponentProps, {}>(
|
|||
connect(mapStateToProps),
|
||||
withServices,
|
||||
withProps(
|
||||
({ workpad, pageCount, services }: Props & WithServicesProps): ComponentProps => ({
|
||||
includeReporting: services.reporting.includeReporting(),
|
||||
getExportUrl: (type, layout) => {
|
||||
if (type === 'pdf') {
|
||||
const pdfUrl = getPdfUrl(
|
||||
workpad,
|
||||
layout,
|
||||
{ pageCount },
|
||||
services.platform.getBasePathInterface()
|
||||
);
|
||||
return getAbsoluteUrl(pdfUrl);
|
||||
}
|
||||
({ workpad, pageCount, services }: Props & WithServicesProps): ComponentProps => {
|
||||
const {
|
||||
platform,
|
||||
reporting: { start: reporting },
|
||||
} = services;
|
||||
|
||||
throw new Error(strings.getUnknownExportErrorMessage(type));
|
||||
},
|
||||
onCopy: (type) => {
|
||||
switch (type) {
|
||||
case 'pdf':
|
||||
services.notify.info(strings.getCopyPDFMessage());
|
||||
break;
|
||||
case 'reportingConfig':
|
||||
services.notify.info(strings.getCopyReportingConfigMessage());
|
||||
break;
|
||||
default:
|
||||
throw new Error(strings.getUnknownExportErrorMessage(type));
|
||||
}
|
||||
},
|
||||
onExport: (type, layout) => {
|
||||
switch (type) {
|
||||
case 'pdf':
|
||||
return createPdf(
|
||||
workpad,
|
||||
layout || 'preserve_layout',
|
||||
{ pageCount },
|
||||
services.platform.getBasePathInterface()
|
||||
)
|
||||
.then(({ data }: { data: { job: { id: string } } }) => {
|
||||
services.notify.info(strings.getExportPDFMessage(), {
|
||||
title: strings.getExportPDFTitle(workpad.name),
|
||||
});
|
||||
|
||||
// register the job so a completion notification shows up when it's ready
|
||||
jobCompletionNotifications.add(data.job.id);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
services.notify.error(err, {
|
||||
title: strings.getExportPDFErrorTitle(workpad.name),
|
||||
'data-test-subj': 'queueReportError',
|
||||
});
|
||||
});
|
||||
case 'json':
|
||||
downloadWorkpad(workpad.id);
|
||||
return;
|
||||
default:
|
||||
throw new Error(strings.getUnknownExportErrorMessage(type));
|
||||
}
|
||||
},
|
||||
})
|
||||
return {
|
||||
sharingServices: { basePath: platform.getBasePathInterface(), reporting },
|
||||
sharingData: { workpad, pageCount },
|
||||
onExport: (type) => {
|
||||
switch (type) {
|
||||
case 'pdf':
|
||||
// notifications are automatically handled by the Reporting plugin
|
||||
break;
|
||||
case 'json':
|
||||
downloadWorkpad(workpad.id);
|
||||
return;
|
||||
default:
|
||||
throw new Error(strings.getUnknownExportErrorMessage(type));
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
)
|
||||
)(Component);
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
|
||||
jest.mock('../../../../common/lib/fetch');
|
||||
|
||||
import { getPdfUrl, createPdf, LayoutType } from './utils';
|
||||
import { getPdfJobParams } from './utils';
|
||||
import { workpads } from '../../../../__fixtures__/workpads';
|
||||
import { fetch } from '../../../../common/lib/fetch';
|
||||
import { IBasePath } from 'kibana/public';
|
||||
|
||||
const basePath = ({
|
||||
|
@ -17,33 +16,36 @@ const basePath = ({
|
|||
get: () => 'basepath/s/spacey',
|
||||
serverBasePath: `basepath`,
|
||||
} as unknown) as IBasePath;
|
||||
const workpad = workpads[0];
|
||||
const workpadSharingData = { workpad: workpads[0], pageCount: 12 };
|
||||
|
||||
test('getPdfUrl returns the correct url for canvas layout', () => {
|
||||
['canvas', 'preserve_layout'].forEach((layout) => {
|
||||
const url = getPdfUrl(workpad, layout as LayoutType, { pageCount: 2 }, basePath);
|
||||
|
||||
expect(url).toMatchInlineSnapshot(
|
||||
`"basepath/s/spacey//api/reporting/generate/printablePdf?jobParams=(browserTimezone:America%2FNew_York,layout:(dimensions:(height:0,width:0),id:${layout}),objectType:'canvas%20workpad',relativeUrls:!(%2Fs%2Fspacey%2Fapp%2Fcanvas%23%2Fexport%2Fworkpad%2Fpdf%2Fbase-workpad%2Fpage%2F1,%2Fs%2Fspacey%2Fapp%2Fcanvas%23%2Fexport%2Fworkpad%2Fpdf%2Fbase-workpad%2Fpage%2F2),title:'base%20workpad')"`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('createPdf posts to create the pdf with canvas layout', () => {
|
||||
['canvas', 'preserve_layout'].forEach((layout, index) => {
|
||||
createPdf(workpad, layout as LayoutType, { pageCount: 2 }, basePath);
|
||||
|
||||
expect(fetch.post).toBeCalled();
|
||||
|
||||
const args = (fetch.post as jest.MockedFunction<typeof fetch.post>).mock.calls[index];
|
||||
|
||||
expect(args[0]).toMatchInlineSnapshot(
|
||||
`"basepath/s/spacey//api/reporting/generate/printablePdf"`
|
||||
);
|
||||
expect(args[1]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"jobParams": "(browserTimezone:America/New_York,layout:(dimensions:(height:0,width:0),id:${layout}),objectType:'canvas workpad',relativeUrls:!(/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/1,/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/2),title:'base workpad')",
|
||||
}
|
||||
`);
|
||||
});
|
||||
test('getPdfJobParams returns the correct job params for canvas layout', () => {
|
||||
const jobParams = getPdfJobParams(workpadSharingData, basePath);
|
||||
expect(jobParams).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"browserTimezone": "America/New_York",
|
||||
"layout": Object {
|
||||
"dimensions": Object {
|
||||
"height": 0,
|
||||
"width": 0,
|
||||
},
|
||||
"id": "canvas",
|
||||
},
|
||||
"objectType": "canvas workpad",
|
||||
"relativeUrls": Array [
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/1",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/2",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/3",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/4",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/5",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/6",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/7",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/8",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/9",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/10",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/11",
|
||||
"/s/spacey/app/canvas#/export/workpad/pdf/base-workpad/page/12",
|
||||
],
|
||||
"title": "base workpad",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -5,33 +5,24 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import rison from 'rison-node';
|
||||
import { IBasePath } from 'kibana/public';
|
||||
import moment from 'moment-timezone';
|
||||
import { fetch } from '../../../../common/lib/fetch';
|
||||
import rison from 'rison-node';
|
||||
import { BaseParams } from '../../../../../reporting/common/types';
|
||||
import { CanvasWorkpad } from '../../../../types';
|
||||
import { url } from '../../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
interface PageCount {
|
||||
export interface CanvasWorkpadSharingData {
|
||||
workpad: Pick<CanvasWorkpad, 'id' | 'name' | 'height' | 'width'>;
|
||||
pageCount: number;
|
||||
}
|
||||
|
||||
export type LayoutType = 'canvas' | 'preserve_layout';
|
||||
// TODO: get the correct type from Reporting plugin
|
||||
type JobParamsPDF = BaseParams & { relativeUrls: string[] };
|
||||
|
||||
type Arguments = [CanvasWorkpad, LayoutType, PageCount, IBasePath];
|
||||
|
||||
interface PdfUrlData {
|
||||
createPdfUri: string;
|
||||
createPdfPayload: { jobParams: string };
|
||||
}
|
||||
|
||||
function getPdfUrlParts(
|
||||
{ id, name: title, width, height }: CanvasWorkpad,
|
||||
layoutType: LayoutType,
|
||||
{ pageCount }: PageCount,
|
||||
export function getPdfJobParams(
|
||||
{ workpad: { id, name: title, width, height }, pageCount }: CanvasWorkpadSharingData,
|
||||
basePath: IBasePath
|
||||
): PdfUrlData {
|
||||
const reportingEntry = basePath.prepend('/api/reporting/generate');
|
||||
): JobParamsPDF {
|
||||
const urlPrefix = basePath.get().replace(basePath.serverBasePath, ''); // for Spaces prefix, which is included in basePath.get()
|
||||
const canvasEntry = `${urlPrefix}/app/canvas#`;
|
||||
|
||||
|
@ -51,34 +42,14 @@ function getPdfUrlParts(
|
|||
workpadUrls.push(rison.encode(`${canvasEntry}/export/workpad/pdf/${id}/page/${i}`));
|
||||
}
|
||||
|
||||
const jobParams = {
|
||||
return {
|
||||
browserTimezone: moment.tz.guess(),
|
||||
layout: {
|
||||
dimensions: { width, height },
|
||||
id: layoutType,
|
||||
id: 'canvas',
|
||||
},
|
||||
objectType: 'canvas workpad',
|
||||
relativeUrls: workpadUrls,
|
||||
title,
|
||||
};
|
||||
|
||||
return {
|
||||
createPdfUri: `${reportingEntry}/printablePdf`,
|
||||
createPdfPayload: {
|
||||
jobParams: rison.encode(jobParams),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getPdfUrl(...args: Arguments): string {
|
||||
const urlParts = getPdfUrlParts(...args);
|
||||
const param = (key: string, val: any) =>
|
||||
url.encodeUriQuery(key, true) + (val === true ? '' : '=' + url.encodeUriQuery(val, true));
|
||||
|
||||
return `${urlParts.createPdfUri}?${param('jobParams', urlParts.createPdfPayload.jobParams)}`;
|
||||
}
|
||||
|
||||
export function createPdf(...args: Arguments) {
|
||||
const { createPdfUri, createPdfPayload } = getPdfUrlParts(...args);
|
||||
return fetch.post(createPdfUri, createPdfPayload);
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ReportingStart } from '../../../reporting/public';
|
||||
import { CanvasServiceFactory } from './';
|
||||
|
||||
export interface ReportingService {
|
||||
includeReporting: () => boolean;
|
||||
start?: ReportingStart;
|
||||
}
|
||||
|
||||
export const reportingServiceFactory: CanvasServiceFactory<ReportingService> = (
|
||||
|
@ -18,18 +19,24 @@ export const reportingServiceFactory: CanvasServiceFactory<ReportingService> = (
|
|||
startPlugins
|
||||
): ReportingService => {
|
||||
const { reporting } = startPlugins;
|
||||
|
||||
const reportingEnabled = () => ({ start: reporting });
|
||||
const reportingDisabled = () => ({ start: undefined });
|
||||
|
||||
if (!reporting) {
|
||||
// Reporting is not enabled
|
||||
return { includeReporting: () => false };
|
||||
return reportingDisabled();
|
||||
}
|
||||
|
||||
if (reporting.usesUiCapabilities()) {
|
||||
// Canvas has declared Reporting as a subfeature with the `generatePdf` UI Capability
|
||||
return {
|
||||
includeReporting: () => coreStart.application.capabilities.canvas?.generatePdf === true,
|
||||
};
|
||||
if (coreStart.application.capabilities.canvas?.generatePdf === true) {
|
||||
// Canvas has declared Reporting as a subfeature with the `generatePdf` UI Capability
|
||||
return reportingEnabled();
|
||||
} else {
|
||||
return reportingDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
// Reporting is enabled as an Elasticsearch feature (Legacy/Deprecated)
|
||||
return { includeReporting: () => true };
|
||||
// Legacy/Deprecated: Reporting is enabled as an Elasticsearch feature
|
||||
return reportingEnabled();
|
||||
};
|
||||
|
|
|
@ -8,5 +8,16 @@
|
|||
import { ReportingService } from '../reporting';
|
||||
|
||||
export const reportingService: ReportingService = {
|
||||
includeReporting: () => true,
|
||||
start: {
|
||||
usesUiCapabilities: () => true,
|
||||
components: {
|
||||
ReportingPanelPDF: () => (null as unknown) as JSX.Element,
|
||||
},
|
||||
getDefaultLayoutSelectors: () => ({
|
||||
screenshot: 'stub',
|
||||
renderComplete: 'stub',
|
||||
itemsCountAttribute: 'stub',
|
||||
timefilterDurationAttribute: 'stub',
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -53,6 +53,7 @@ export const UI_SETTINGS_CSV_QUOTE_VALUES = 'csv:quoteValues';
|
|||
export const UI_SETTINGS_DATEFORMAT_TZ = 'dateFormat:tz';
|
||||
|
||||
export const LAYOUT_TYPES = {
|
||||
CANVAS: 'canvas',
|
||||
PRESERVE_LAYOUT: 'preserve_layout',
|
||||
PRINT: 'print',
|
||||
};
|
||||
|
|
1191
x-pack/plugins/reporting/public/components/__snapshots__/screen_capture_panel_content.test.tsx.snap
generated
Normal file
1191
x-pack/plugins/reporting/public/components/__snapshots__/screen_capture_panel_content.test.tsx.snap
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -11,3 +11,4 @@ export { getWarningFormulasToast } from './job_warning_formulas';
|
|||
export { getWarningMaxSizeToast } from './job_warning_max_size';
|
||||
export { getGeneralErrorToast } from './general_error';
|
||||
export { ScreenCapturePanelContent } from './screen_capture_panel_content';
|
||||
export { getSharedComponents } from './shared';
|
||||
|
|
|
@ -5,7 +5,17 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiButton, EuiCopy, EuiForm, EuiFormRow, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import {
|
||||
EuiAccordion,
|
||||
EuiButton,
|
||||
EuiCopy,
|
||||
EuiForm,
|
||||
EuiFormRow,
|
||||
EuiHorizontalRule,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
|
||||
import React, { Component, ReactElement } from 'react';
|
||||
import { ToastsSetup } from 'src/core/public';
|
||||
|
@ -20,14 +30,12 @@ export interface Props {
|
|||
toasts: ToastsSetup;
|
||||
reportType: string;
|
||||
|
||||
/**
|
||||
* Whether the report to be generated requires saved state that is not captured in the URL submitted to the report generator.
|
||||
*/
|
||||
/** Whether the report to be generated requires saved state that is not captured in the URL submitted to the report generator. **/
|
||||
requiresSavedState: boolean;
|
||||
layoutId: string | undefined;
|
||||
objectId?: string;
|
||||
getJobParams: () => BaseParams;
|
||||
options?: ReactElement<any>;
|
||||
options?: ReactElement<any> | null;
|
||||
isDirty?: boolean;
|
||||
onClose?: () => void;
|
||||
intl: InjectedIntl;
|
||||
|
@ -110,50 +118,61 @@ class ReportingPanelContentUi extends Component<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
const reportMsg = (
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.panelContent.generationTimeDescription"
|
||||
defaultMessage="{reportingType}s can take a minute or two to generate based upon the size of your {objectType}."
|
||||
description="Here 'reportingType' can be 'PDF' or 'CSV'"
|
||||
values={{
|
||||
reportingType: this.prettyPrintReportingType(),
|
||||
objectType: this.state.objectType,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiForm className="kbnShareContextMenu__finalPanel" data-test-subj="shareReportingForm">
|
||||
<EuiText size="s">
|
||||
<p>{reportMsg}</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.panelContent.generationTimeDescription"
|
||||
defaultMessage="{reportingType}s can take a minute or two to generate based upon the size of your {objectType}."
|
||||
description="Here 'reportingType' can be 'PDF' or 'CSV'"
|
||||
values={{
|
||||
reportingType: this.prettyPrintReportingType(),
|
||||
objectType: this.state.objectType,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
{this.props.options}
|
||||
|
||||
{this.renderGenerateReportButton(false)}
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.panelContent.howToCallGenerationDescription"
|
||||
defaultMessage="Alternatively, copy this POST URL to call generation from outside Kibana or from Watcher."
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiHorizontalRule
|
||||
margin="s"
|
||||
style={{ width: 'auto', marginLeft: '-16px', marginRight: '-16px' }}
|
||||
/>
|
||||
|
||||
<EuiCopy textToCopy={this.state.absoluteUrl} anchorClassName="eui-displayBlock">
|
||||
{(copy) => (
|
||||
<EuiButton fullWidth onClick={copy} size="s">
|
||||
<EuiAccordion
|
||||
id="advanced-options"
|
||||
buttonContent={i18n.translate('xpack.reporting.panelContent.advancedOptions', {
|
||||
defaultMessage: 'Advanced options',
|
||||
})}
|
||||
paddingSize="none"
|
||||
>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.panelContent.copyUrlButtonLabel"
|
||||
defaultMessage="Copy POST URL"
|
||||
id="xpack.reporting.panelContent.howToCallGenerationDescription"
|
||||
defaultMessage="Alternatively, copy this POST URL to call generation from outside Kibana or from Watcher."
|
||||
/>
|
||||
</EuiButton>
|
||||
)}
|
||||
</EuiCopy>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<EuiCopy textToCopy={this.state.absoluteUrl} anchorClassName="eui-displayBlock">
|
||||
{(copy) => (
|
||||
<EuiButton fullWidth onClick={copy} size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.panelContent.copyUrlButtonLabel"
|
||||
defaultMessage="Copy POST URL"
|
||||
/>
|
||||
</EuiButton>
|
||||
)}
|
||||
</EuiCopy>
|
||||
</EuiAccordion>
|
||||
</EuiForm>
|
||||
);
|
||||
}
|
||||
|
@ -247,44 +266,12 @@ class ReportingPanelContentUi extends Component<Props, State> {
|
|||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
if (error.message === 'not exportable') {
|
||||
return this.props.toasts.addWarning({
|
||||
title: intl.formatMessage(
|
||||
{
|
||||
id: 'xpack.reporting.panelContent.whatCanBeExportedWarningTitle',
|
||||
defaultMessage: 'Only saved {objectType} can be exported',
|
||||
},
|
||||
{ objectType: this.state.objectType }
|
||||
),
|
||||
text: toMountPoint(
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.panelContent.whatCanBeExportedWarningDescription"
|
||||
defaultMessage="Please save your work first"
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
const defaultMessage =
|
||||
error?.res?.status === 403 ? (
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.panelContent.noPermissionToGenerateReportDescription"
|
||||
defaultMessage="You don't have permission to generate this report."
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.panelContent.notification.cantReachServerDescription"
|
||||
defaultMessage="Can't reach the server. Please try again."
|
||||
/>
|
||||
);
|
||||
|
||||
this.props.toasts.addDanger({
|
||||
this.props.toasts.addError(error, {
|
||||
title: intl.formatMessage({
|
||||
id: 'xpack.reporting.panelContent.notification.reportingErrorTitle',
|
||||
defaultMessage: 'Reporting error',
|
||||
defaultMessage: 'Failed to create report',
|
||||
}),
|
||||
text: toMountPoint(error.message || defaultMessage),
|
||||
'data-test-subj': 'queueReportError',
|
||||
toastMessage: error.body.message,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { coreMock } from '../../../../../src/core/public/mocks';
|
||||
import { BaseParams } from '../../common/types';
|
||||
import { ReportingAPIClient } from '../lib/reporting_api_client';
|
||||
import { ScreenCapturePanelContent } from './screen_capture_panel_content';
|
||||
|
||||
const getJobParamsDefault: () => BaseParams = () => ({
|
||||
objectType: 'test-object-type',
|
||||
title: 'Test Report Title',
|
||||
browserTimezone: 'America/New_York',
|
||||
});
|
||||
|
||||
test('ScreenCapturePanelContent renders the default view properly', () => {
|
||||
const coreSetup = coreMock.createSetup();
|
||||
const component = mount(
|
||||
<IntlProvider locale="en">
|
||||
<ScreenCapturePanelContent
|
||||
reportType="Analytical App"
|
||||
requiresSavedState={false}
|
||||
apiClient={new ReportingAPIClient(coreSetup.http)}
|
||||
toasts={coreSetup.notifications.toasts}
|
||||
getJobParams={getJobParamsDefault}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
expect(component.find('EuiForm')).toMatchSnapshot();
|
||||
expect(component.text()).not.toMatch('Full page layout');
|
||||
expect(component.text()).not.toMatch('Optimize for printing');
|
||||
});
|
||||
|
||||
test('ScreenCapturePanelContent properly renders a view with "canvas" layout option', () => {
|
||||
const coreSetup = coreMock.createSetup();
|
||||
const component = mount(
|
||||
<IntlProvider locale="en">
|
||||
<ScreenCapturePanelContent
|
||||
layoutOption="canvas"
|
||||
reportType="Analytical App"
|
||||
requiresSavedState={false}
|
||||
apiClient={new ReportingAPIClient(coreSetup.http)}
|
||||
toasts={coreSetup.notifications.toasts}
|
||||
getJobParams={getJobParamsDefault}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
expect(component.find('EuiForm')).toMatchSnapshot();
|
||||
expect(component.text()).toMatch('Full page layout');
|
||||
});
|
||||
|
||||
test('ScreenCapturePanelContent properly renders a view with "print" layout option', () => {
|
||||
const coreSetup = coreMock.createSetup();
|
||||
const component = mount(
|
||||
<IntlProvider locale="en">
|
||||
<ScreenCapturePanelContent
|
||||
layoutOption="print"
|
||||
reportType="Analytical App"
|
||||
requiresSavedState={false}
|
||||
apiClient={new ReportingAPIClient(coreSetup.http)}
|
||||
toasts={coreSetup.notifications.toasts}
|
||||
getJobParams={getJobParamsDefault}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
expect(component.find('EuiForm')).toMatchSnapshot();
|
||||
expect(component.text()).toMatch('Optimize for printing');
|
||||
});
|
|
@ -5,11 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiSpacer, EuiSwitch, EuiSwitchEvent } from '@elastic/eui';
|
||||
import { EuiFormRow, EuiSwitch, EuiSwitchEvent } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import moment from 'moment';
|
||||
import React, { Component } from 'react';
|
||||
import { ToastsSetup } from 'src/core/public';
|
||||
import { BaseParams } from '../../common/types';
|
||||
import { getDefaultLayoutSelectors } from '../../common';
|
||||
import { BaseParams, LayoutParams } from '../../common/types';
|
||||
import { ReportingAPIClient } from '../lib/reporting_api_client';
|
||||
import { ReportingPanelContent } from './reporting_panel_content';
|
||||
|
||||
|
@ -17,33 +19,33 @@ export interface Props {
|
|||
apiClient: ReportingAPIClient;
|
||||
toasts: ToastsSetup;
|
||||
reportType: string;
|
||||
layoutOption?: 'canvas' | 'print';
|
||||
objectId?: string;
|
||||
getJobParams: () => BaseParams;
|
||||
requiresSavedState: boolean;
|
||||
isDirty?: boolean;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
isPreserveLayoutSupported: boolean;
|
||||
usePrintLayout: boolean;
|
||||
useCanvasLayout: boolean;
|
||||
}
|
||||
|
||||
export class ScreenCapturePanelContent extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
const { objectType } = props.getJobParams();
|
||||
const isPreserveLayoutSupported = props.reportType !== 'png' && objectType !== 'visualization';
|
||||
this.state = {
|
||||
isPreserveLayoutSupported,
|
||||
usePrintLayout: false,
|
||||
useCanvasLayout: false,
|
||||
};
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<ReportingPanelContent
|
||||
requiresSavedState
|
||||
requiresSavedState={this.props.requiresSavedState}
|
||||
apiClient={this.props.apiClient}
|
||||
toasts={this.props.toasts}
|
||||
reportType={this.props.reportType}
|
||||
|
@ -58,9 +60,16 @@ export class ScreenCapturePanelContent extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private renderOptions = () => {
|
||||
if (this.state.isPreserveLayoutSupported) {
|
||||
if (this.props.layoutOption === 'print') {
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.screenCapturePanelContent.optimizeForPrintingHelpText"
|
||||
defaultMessage="Uses multiple pages, showing at most 2 visualizations per page"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiSwitch
|
||||
label={
|
||||
<FormattedMessage
|
||||
|
@ -72,43 +81,83 @@ export class ScreenCapturePanelContent extends Component<Props, State> {
|
|||
onChange={this.handlePrintLayoutChange}
|
||||
data-test-subj="usePrintLayout"
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
</Fragment>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiSpacer size="s" />
|
||||
</Fragment>
|
||||
);
|
||||
if (this.props.layoutOption === 'canvas') {
|
||||
return (
|
||||
<EuiFormRow
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.screenCapturePanelContent.canvasLayoutHelpText"
|
||||
defaultMessage="Remove borders and footer logo"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiSwitch
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.screenCapturePanelContent.canvasLayoutLabel"
|
||||
defaultMessage="Full page layout"
|
||||
/>
|
||||
}
|
||||
checked={this.state.useCanvasLayout}
|
||||
onChange={this.handleCanvasLayoutChange}
|
||||
data-test-subj="reportModeToggle"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
private handlePrintLayoutChange = (evt: EuiSwitchEvent) => {
|
||||
this.setState({ usePrintLayout: evt.target.checked });
|
||||
this.setState({ usePrintLayout: evt.target.checked, useCanvasLayout: false });
|
||||
};
|
||||
|
||||
private getLayout = () => {
|
||||
if (this.state.usePrintLayout) {
|
||||
return { id: 'print' };
|
||||
private handleCanvasLayoutChange = (evt: EuiSwitchEvent) => {
|
||||
this.setState({ useCanvasLayout: evt.target.checked, usePrintLayout: false });
|
||||
};
|
||||
|
||||
private getLayout = (): Required<LayoutParams> => {
|
||||
const { layout: outerLayout } = this.props.getJobParams();
|
||||
|
||||
let dimensions = outerLayout?.dimensions;
|
||||
if (!dimensions) {
|
||||
const el = document.querySelector('[data-shared-items-container]');
|
||||
const { height, width } = el ? el.getBoundingClientRect() : { height: 768, width: 1024 };
|
||||
dimensions = { height, width };
|
||||
}
|
||||
|
||||
const el = document.querySelector('[data-shared-items-container]');
|
||||
const bounds = el ? el.getBoundingClientRect() : { height: 768, width: 1024 };
|
||||
let selectors = outerLayout?.selectors;
|
||||
if (!selectors) {
|
||||
selectors = getDefaultLayoutSelectors();
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.props.reportType === 'png' ? 'png' : 'preserve_layout',
|
||||
dimensions: {
|
||||
height: bounds.height,
|
||||
width: bounds.width,
|
||||
},
|
||||
};
|
||||
if (this.state.usePrintLayout) {
|
||||
return { id: 'print', dimensions, selectors };
|
||||
}
|
||||
|
||||
if (this.state.useCanvasLayout) {
|
||||
return { id: 'canvas', dimensions, selectors };
|
||||
}
|
||||
|
||||
return { id: 'preserve_layout', dimensions, selectors };
|
||||
};
|
||||
|
||||
private getJobParams = () => {
|
||||
private getJobParams = (): Required<BaseParams> => {
|
||||
const outerParams = this.props.getJobParams();
|
||||
let browserTimezone = outerParams.browserTimezone;
|
||||
if (!browserTimezone) {
|
||||
browserTimezone = moment.tz.guess();
|
||||
}
|
||||
|
||||
return {
|
||||
...this.props.getJobParams(),
|
||||
layout: this.getLayout(),
|
||||
browserTimezone,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 { CoreSetup } from 'kibana/public';
|
||||
import React from 'react';
|
||||
import { ReportingAPIClient } from '../..';
|
||||
import { PDF_REPORT_TYPE } from '../../../common/constants';
|
||||
import type { Props as PanelPropsScreenCapture } from '../screen_capture_panel_content';
|
||||
import { ScreenCapturePanelContent } from '../screen_capture_panel_content_lazy';
|
||||
|
||||
interface IncludeOnCloseFn {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
type PropsPDF = Pick<PanelPropsScreenCapture, 'getJobParams' | 'layoutOption'> & IncludeOnCloseFn;
|
||||
|
||||
/*
|
||||
* As of 7.14, the only shared component is a PDF report that is suited for Canvas integration.
|
||||
* This is not planned to expand, as work is to be done on moving the export-type implementations out of Reporting
|
||||
* Related Discuss issue: https://github.com/elastic/kibana/issues/101422
|
||||
*/
|
||||
export function getSharedComponents(core: CoreSetup) {
|
||||
return {
|
||||
ReportingPanelPDF(props: PropsPDF) {
|
||||
return (
|
||||
<ScreenCapturePanelContent
|
||||
layoutOption={props.layoutOption}
|
||||
requiresSavedState={false}
|
||||
reportType={PDF_REPORT_TYPE}
|
||||
apiClient={new ReportingAPIClient(core.http)}
|
||||
toasts={core.notifications.toasts}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { getSharedComponents } from './get_shared_components';
|
|
@ -7,24 +7,20 @@
|
|||
|
||||
import { PluginInitializerContext } from 'src/core/public';
|
||||
import { getDefaultLayoutSelectors } from '../common';
|
||||
import { ScreenCapturePanelContent } from './components/screen_capture_panel_content';
|
||||
import * as jobCompletionNotifications from './lib/job_completion_notifications';
|
||||
import { getSharedComponents } from './components';
|
||||
import { ReportingAPIClient } from './lib/reporting_api_client';
|
||||
import { ReportingPublicPlugin } from './plugin';
|
||||
|
||||
export interface ReportingSetup {
|
||||
components: {
|
||||
ScreenCapturePanel: typeof ScreenCapturePanelContent;
|
||||
};
|
||||
getDefaultLayoutSelectors: typeof getDefaultLayoutSelectors;
|
||||
ReportingAPIClient: typeof ReportingAPIClient;
|
||||
usesUiCapabilities: () => boolean;
|
||||
components: ReturnType<typeof getSharedComponents>;
|
||||
}
|
||||
|
||||
export type ReportingStart = ReportingSetup;
|
||||
|
||||
export { constants, getDefaultLayoutSelectors } from '../common';
|
||||
export { ReportingAPIClient, ReportingPublicPlugin as Plugin, jobCompletionNotifications };
|
||||
export { ReportingAPIClient, ReportingPublicPlugin as Plugin };
|
||||
|
||||
export function plugin(initializerContext: PluginInitializerContext) {
|
||||
return new ReportingPublicPlugin(initializerContext);
|
||||
|
|
27
x-pack/plugins/reporting/public/mocks.ts
Normal file
27
x-pack/plugins/reporting/public/mocks.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 { coreMock } from 'src/core/public/mocks';
|
||||
import { ReportingSetup } from '.';
|
||||
import { getDefaultLayoutSelectors } from '../common';
|
||||
import { getSharedComponents } from './components/shared';
|
||||
|
||||
type Setup = jest.Mocked<ReportingSetup>;
|
||||
|
||||
const createSetupContract = (): Setup => {
|
||||
const coreSetup = coreMock.createSetup();
|
||||
return {
|
||||
getDefaultLayoutSelectors: jest.fn().mockImplementation(getDefaultLayoutSelectors),
|
||||
usesUiCapabilities: jest.fn().mockImplementation(() => true),
|
||||
components: getSharedComponents(coreSetup),
|
||||
};
|
||||
};
|
||||
|
||||
export const reportingPluginMock = {
|
||||
createSetupContract,
|
||||
createStartContract: createSetupContract,
|
||||
};
|
|
@ -29,10 +29,7 @@ import { constants, getDefaultLayoutSelectors } from '../common';
|
|||
import { durationToNumber } from '../common/schema_utils';
|
||||
import { JobId, JobSummarySet } from '../common/types';
|
||||
import { ReportingSetup, ReportingStart } from './';
|
||||
import {
|
||||
getGeneralErrorToast,
|
||||
ScreenCapturePanelContent as ScreenCapturePanel,
|
||||
} from './components';
|
||||
import { getGeneralErrorToast, getSharedComponents } from './components';
|
||||
import { ReportingAPIClient } from './lib/reporting_api_client';
|
||||
import { ReportingNotifierStreamHandler as StreamHandler } from './lib/stream_handler';
|
||||
import { ReportingCsvPanelAction } from './panel_actions/get_csv_panel_action';
|
||||
|
@ -86,7 +83,6 @@ export class ReportingPublicPlugin
|
|||
ReportingPublicPluginSetupDendencies,
|
||||
ReportingPublicPluginStartDendencies
|
||||
> {
|
||||
private readonly contract: ReportingStart;
|
||||
private readonly stop$ = new Rx.ReplaySubject(1);
|
||||
private readonly title = i18n.translate('xpack.reporting.management.reportingTitle', {
|
||||
defaultMessage: 'Reporting',
|
||||
|
@ -95,21 +91,30 @@ export class ReportingPublicPlugin
|
|||
defaultMessage: 'Reporting',
|
||||
});
|
||||
private config: ClientConfigType;
|
||||
private contract?: ReportingSetup;
|
||||
|
||||
constructor(initializerContext: PluginInitializerContext) {
|
||||
this.config = initializerContext.config.get<ClientConfigType>();
|
||||
}
|
||||
|
||||
this.contract = {
|
||||
ReportingAPIClient,
|
||||
components: { ScreenCapturePanel },
|
||||
getDefaultLayoutSelectors,
|
||||
usesUiCapabilities: () => this.config.roles?.enabled === false,
|
||||
};
|
||||
private getContract(core?: CoreSetup) {
|
||||
if (core) {
|
||||
this.contract = {
|
||||
getDefaultLayoutSelectors,
|
||||
usesUiCapabilities: () => this.config.roles?.enabled === false,
|
||||
components: getSharedComponents(core),
|
||||
};
|
||||
}
|
||||
|
||||
if (!this.contract) {
|
||||
throw new Error(`Setup error in Reporting plugin!`);
|
||||
}
|
||||
|
||||
return this.contract;
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup, setupDeps: ReportingPublicPluginSetupDendencies) {
|
||||
const { http, notifications, getStartServices, uiSettings } = core;
|
||||
const { toasts } = notifications;
|
||||
const { http, getStartServices, uiSettings } = core;
|
||||
const {
|
||||
home,
|
||||
management,
|
||||
|
@ -163,6 +168,9 @@ export class ReportingPublicPlugin
|
|||
new ReportingCsvPanelAction({ core, startServices$, license$, usesUiCapabilities })
|
||||
);
|
||||
|
||||
const reportingStart = this.getContract(core);
|
||||
const { toasts } = core.notifications;
|
||||
|
||||
share.register(
|
||||
ReportingCsvShareProvider({
|
||||
apiClient,
|
||||
|
@ -173,6 +181,7 @@ export class ReportingPublicPlugin
|
|||
usesUiCapabilities,
|
||||
})
|
||||
);
|
||||
|
||||
share.register(
|
||||
reportingScreenshotShareProvider({
|
||||
apiClient,
|
||||
|
@ -184,7 +193,7 @@ export class ReportingPublicPlugin
|
|||
})
|
||||
);
|
||||
|
||||
return this.contract;
|
||||
return reportingStart;
|
||||
}
|
||||
|
||||
public start(core: CoreStart) {
|
||||
|
@ -203,7 +212,7 @@ export class ReportingPublicPlugin
|
|||
)
|
||||
.subscribe();
|
||||
|
||||
return this.contract;
|
||||
return this.getContract();
|
||||
}
|
||||
|
||||
public stop() {
|
||||
|
|
|
@ -65,13 +65,7 @@ export const ReportingCsvShareProvider = ({
|
|||
? moment.tz.guess()
|
||||
: uiSettings.get('dateFormat:tz');
|
||||
|
||||
const getShareMenuItems = ({
|
||||
objectType,
|
||||
objectId,
|
||||
sharingData,
|
||||
onClose,
|
||||
isDirty,
|
||||
}: ShareContext) => {
|
||||
const getShareMenuItems = ({ objectType, objectId, sharingData, onClose }: ShareContext) => {
|
||||
if ('search' !== objectType) {
|
||||
return [];
|
||||
}
|
||||
|
@ -114,7 +108,6 @@ export const ReportingCsvShareProvider = ({
|
|||
layoutId={undefined}
|
||||
objectId={objectId}
|
||||
getJobParams={getJobParams}
|
||||
isDirty={isDirty}
|
||||
onClose={onClose}
|
||||
/>
|
||||
),
|
||||
|
|
|
@ -11,7 +11,7 @@ import React from 'react';
|
|||
import * as Rx from 'rxjs';
|
||||
import type { IUiSettingsClient, ToastsSetup } from 'src/core/public';
|
||||
import { CoreStart } from 'src/core/public';
|
||||
import type { ShareContext } from '../../../../../src/plugins/share/public';
|
||||
import { ShareContext } from 'src/plugins/share/public';
|
||||
import type { LicensingPluginSetup } from '../../../licensing/public';
|
||||
import type { LayoutParams } from '../../common/types';
|
||||
import type { JobParamsPNG } from '../../server/export_types/png/types';
|
||||
|
@ -167,6 +167,7 @@ export const reportingScreenshotShareProvider = ({
|
|||
toasts={toasts}
|
||||
reportType="png"
|
||||
objectId={objectId}
|
||||
requiresSavedState={true}
|
||||
getJobParams={getPngJobParams({
|
||||
shareableUrl,
|
||||
apiClient,
|
||||
|
@ -203,6 +204,8 @@ export const reportingScreenshotShareProvider = ({
|
|||
toasts={toasts}
|
||||
reportType="printablePdf"
|
||||
objectId={objectId}
|
||||
requiresSavedState={true}
|
||||
layoutOption={objectType === 'dashboard' ? 'print' : undefined}
|
||||
getJobParams={getPdfJobParams({
|
||||
shareableUrl,
|
||||
apiClient,
|
||||
|
|
|
@ -7003,20 +7003,7 @@
|
|||
"xpack.canvas.workpadHeaderRefreshControlSettings.refreshAriaLabel": "エレメントを更新",
|
||||
"xpack.canvas.workpadHeaderRefreshControlSettings.refreshTooltip": "データを更新",
|
||||
"xpack.canvas.workpadHeaderShareMenu.copyPDFMessage": "{PDF}生成{URL}がクリップボードにコピーされました。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.copyReportingConfigMessage": "レポート構成がクリップボードにコピーされました",
|
||||
"xpack.canvas.workpadHeaderShareMenu.copyShareConfigMessage": "共有マークアップがクリップボードにコピーされました",
|
||||
"xpack.canvas.workpadHeaderShareMenu.exportPDFErrorMessage": "'{workpadName}'の{PDF}を作成できませんでした",
|
||||
"xpack.canvas.workpadHeaderShareMenu.exportPDFMessage": "{PDF}をエクスポートしています。管理で進捗を確認できます。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.exportPDFTitle": "ワークパッド '{workpadName}' の {PDF} エクスポート",
|
||||
"xpack.canvas.workpadHeaderShareMenu.FullPageLayoutHelpText": "枠線とフッターロゴを削除",
|
||||
"xpack.canvas.workpadHeaderShareMenu.FullPageLayoutLabel": "全ページレイアウト",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelAdvancedOptionsLabel": "高度なオプション",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyAriaLabel": "この {URL} を使用してスクリプトから、または Watcher で {PDF} を生成することもできます。{URL}をクリップボードにコピーするにはEnterキーを押してください。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyButtonLabel": "{POST} {URL}をコピー",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyDescription": "{POST} {URL}をコピーして{KIBANA}外またはWatcherから生成を実行することもできます。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelGenerateButtonLabel": "{PDF}を生成",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelGenerateDescription": "ワークパッドのサイズによって、{PDF} の生成には数分かかる場合があります。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelOptionsLabel": "オプション",
|
||||
"xpack.canvas.workpadHeaderShareMenu.shareDownloadJSONTitle": "{JSON} をダウンロード",
|
||||
"xpack.canvas.workpadHeaderShareMenu.shareDownloadPDFTitle": "{PDF}レポート",
|
||||
"xpack.canvas.workpadHeaderShareMenu.shareMenuButtonLabel": "共有",
|
||||
|
@ -17879,14 +17866,10 @@
|
|||
"xpack.reporting.panelContent.generateButtonLabel": "{reportingType} を生成",
|
||||
"xpack.reporting.panelContent.generationTimeDescription": "{objectType} のサイズによって、{reportingType} の作成には数分かかる場合があります。",
|
||||
"xpack.reporting.panelContent.howToCallGenerationDescription": "POST URL をコピーして Kibana 外または ウォッチャー から生成を実行することもできます。",
|
||||
"xpack.reporting.panelContent.noPermissionToGenerateReportDescription": "このレポートを生成するパーミッションがありません。",
|
||||
"xpack.reporting.panelContent.notification.cantReachServerDescription": "サーバーと通信できません。再試行してください。",
|
||||
"xpack.reporting.panelContent.notification.reportingErrorTitle": "レポートエラー",
|
||||
"xpack.reporting.panelContent.saveWorkDescription": "レポートの生成前に変更内容を保存してください。",
|
||||
"xpack.reporting.panelContent.successfullyQueuedReportNotificationDescription": "{path}で進捗状況を追跡",
|
||||
"xpack.reporting.panelContent.successfullyQueuedReportNotificationTitle": "{objectType} のレポートキュー",
|
||||
"xpack.reporting.panelContent.whatCanBeExportedWarningDescription": "初めに変更内容を保存してください",
|
||||
"xpack.reporting.panelContent.whatCanBeExportedWarningTitle": "保存された {objectType} のみエクスポートできます",
|
||||
"xpack.reporting.pdfFooterImageDescription": "PDFのフッターに使用するカスタム画像です",
|
||||
"xpack.reporting.pdfFooterImageLabel": "PDFフッター画像",
|
||||
"xpack.reporting.publicNotifier.csvContainsFormulas.formulaReportMessage": "レポートには、スプレッドシートアプリケーションで式と解釈される可能性のある文字が含まれています。",
|
||||
|
|
|
@ -7051,20 +7051,7 @@
|
|||
"xpack.canvas.workpadHeaderRefreshControlSettings.refreshAriaLabel": "刷新元素",
|
||||
"xpack.canvas.workpadHeaderRefreshControlSettings.refreshTooltip": "刷新数据",
|
||||
"xpack.canvas.workpadHeaderShareMenu.copyPDFMessage": "{PDF} 生成 {URL} 已复制到您的剪贴板。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.copyReportingConfigMessage": "已将报告配置复制到剪贴板",
|
||||
"xpack.canvas.workpadHeaderShareMenu.copyShareConfigMessage": "已将共享标记复制到剪贴板",
|
||||
"xpack.canvas.workpadHeaderShareMenu.exportPDFErrorMessage": "无法为“{workpadName}”创建 {PDF}",
|
||||
"xpack.canvas.workpadHeaderShareMenu.exportPDFMessage": "正在导出 {PDF}。可以在“管理”中跟踪进度。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.exportPDFTitle": "Workpad“{workpadName}”的 {PDF} 导出",
|
||||
"xpack.canvas.workpadHeaderShareMenu.FullPageLayoutHelpText": "删除边框和页脚徽标",
|
||||
"xpack.canvas.workpadHeaderShareMenu.FullPageLayoutLabel": "全页面布局",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelAdvancedOptionsLabel": "高级选项",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyAriaLabel": "或者,也可以从脚本或使用此 {URL} 通过 Watcher 生成 {PDF}。按 Enter 键可将 {URL} 复制到剪贴板。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyButtonLabel": "复制 {POST} {URL}",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelCopyDescription": "或者,复制此 {POST} {URL} 以从 {KIBANA} 外部或从 Watcher 调用生成。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelGenerateButtonLabel": "生成 {PDF}",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelGenerateDescription": "{PDF} 可能会花费一两分钟生成,具体取决于 Workpad 的大小。",
|
||||
"xpack.canvas.workpadHeaderShareMenu.pdfPanelOptionsLabel": "选项",
|
||||
"xpack.canvas.workpadHeaderShareMenu.shareDownloadJSONTitle": "下载为 {JSON}",
|
||||
"xpack.canvas.workpadHeaderShareMenu.shareDownloadPDFTitle": "{PDF} 报告",
|
||||
"xpack.canvas.workpadHeaderShareMenu.shareMenuButtonLabel": "共享",
|
||||
|
@ -18120,14 +18107,10 @@
|
|||
"xpack.reporting.panelContent.generateButtonLabel": "生成 {reportingType}",
|
||||
"xpack.reporting.panelContent.generationTimeDescription": "{reportingType} 可能会花费 1 或 2 分钟生成,取决于 {objectType} 的大小。",
|
||||
"xpack.reporting.panelContent.howToCallGenerationDescription": "或者,复制此 POST URL 以从 Kibana 外部或从 Watcher 调用生成。",
|
||||
"xpack.reporting.panelContent.noPermissionToGenerateReportDescription": "您无权生成此报告。",
|
||||
"xpack.reporting.panelContent.notification.cantReachServerDescription": "无法访问服务器。请重试。",
|
||||
"xpack.reporting.panelContent.notification.reportingErrorTitle": "报告错误",
|
||||
"xpack.reporting.panelContent.saveWorkDescription": "请在生成报告之前保存您的工作。",
|
||||
"xpack.reporting.panelContent.successfullyQueuedReportNotificationDescription": "在 {path} 中跟踪其进度",
|
||||
"xpack.reporting.panelContent.successfullyQueuedReportNotificationTitle": "已为 {objectType} 排队报告",
|
||||
"xpack.reporting.panelContent.whatCanBeExportedWarningDescription": "请先保存您的工作",
|
||||
"xpack.reporting.panelContent.whatCanBeExportedWarningTitle": "只会导出保存的 {objectType}",
|
||||
"xpack.reporting.pdfFooterImageDescription": "要在 PDF 的页脚中使用的定制图像",
|
||||
"xpack.reporting.pdfFooterImageLabel": "PDF 页脚图像",
|
||||
"xpack.reporting.publicNotifier.csvContainsFormulas.formulaReportMessage": "报告包含电子表格应用程序可解释为公式的字符。",
|
||||
|
|
|
@ -91,7 +91,7 @@ export class ReportingPageObject extends FtrService {
|
|||
}
|
||||
|
||||
async getQueueReportError() {
|
||||
return await this.testSubjects.exists('queueReportError');
|
||||
return await this.testSubjects.exists('errorToastMessage');
|
||||
}
|
||||
|
||||
async getGenerateReportButton() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue