Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3e9a07e
scaffold new experience for share export
eokoneyo Apr 3, 2025
7ad89e6
switch to displaying export through popover
eokoneyo Apr 4, 2025
1b49301
apply new export behaviour to visualizations and discover
eokoneyo Apr 4, 2025
aa068a6
fix translation issues
eokoneyo Apr 4, 2025
e64bc7b
add test and amendement so flyout immediately display when only one s…
eokoneyo Apr 14, 2025
d085cdf
use icons for share buttons across apps
eokoneyo Apr 24, 2025
ef68e12
start on fixing tests
eokoneyo Apr 24, 2025
847f983
add emotion typing to share plugin to improve typings
eokoneyo Apr 24, 2025
5915833
adjustments for FTR tests
eokoneyo Apr 24, 2025
575fa4c
add util to query available integrations, and render export option co…
eokoneyo May 2, 2025
fb43832
provide application capabilities within prerequisite check callback
eokoneyo May 2, 2025
f4f3cdf
provide licensing information within prerequiste check callback
eokoneyo May 2, 2025
b5fa2af
fix tests
eokoneyo May 4, 2025
0a03bbd
attend to design feedback
eokoneyo May 5, 2025
eb4cae1
make copy config more flexible
eokoneyo May 7, 2025
50abaa7
add support for custom component in export flyout
eokoneyo May 7, 2025
b9a3964
resolve PR feedback
eokoneyo May 7, 2025
6091e8f
externalize draft error message for export integrations
eokoneyo May 23, 2025
3638e4b
disable tooltip on disabled icon buttons
eokoneyo Jun 2, 2025
6c0da88
remove comment
eokoneyo Jun 2, 2025
0870eca
Merge branch 'main' into chore/separate-export-menu-from-share
elasticmachine Jun 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ export type StartServices = [

export interface ExportModalShareOpts {
apiClient: ReportingAPIClient;
license: ILicense;
application: ApplicationStart;
startServices$: Rx.Observable<StartServices>;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,13 @@ import { checkLicense } from '../..';

export const reportingCsvExportProvider = ({
apiClient,
application,
license,
startServices$,
}: ExportModalShareOpts): ExportShare => {
const getShareMenuItems = ({
objectType,
sharingData,
toasts,
}: ShareContext): ReturnType<ExportShare['config']> => {
const licenseCheck = checkLicense(license.check('reporting', 'basic'));
const licenseToolTipContent = licenseCheck.message;
const licenseHasCsvReporting = licenseCheck.showLinks;
const licenseDisabled = !licenseCheck.enableLinks;

const capabilityHasCsvReporting = application.capabilities.discover_v2?.generateCsv === true;

if (!(licenseHasCsvReporting && capabilityHasCsvReporting)) {
return null;
}

const getSearchSource = sharingData.getSearchSource as ({
addGlobalTimeFilter,
absoluteTime,
Expand Down Expand Up @@ -138,34 +125,58 @@ export const reportingCsvExportProvider = ({

return {
name: panelTitle,
toolTipContent: licenseToolTipContent,
exportType: reportType,
label: 'CSV',
disabled: licenseDisabled,
generateAssetExport: generateReportingJobCSV,
generateAssetURIValue: () => absoluteUrl,
helpText: (
<FormattedMessage
id="reporting.share.csv.reporting.helpTextCSV"
defaultMessage="Export a CSV of this {objectType}."
values={{ objectType }}
/>
),
generateExportButton: (
generateExportButtonLabel: (
<FormattedMessage
id="reporting.share.generateButtonLabelCSV"
data-test-subj="generateReportButton"
defaultMessage="Generate CSV"
/>
),
renderCopyURIButton: true,
copyAssetURIConfig: {
headingText: i18n.translate('reporting.export.csv.exportFlyout.csvExportCopyUriHeading', {
defaultMessage: 'Post URL',
}),
helpText: i18n.translate('reporting.export.csv.exportFlyout.csvExportCopyUriHelpText', {
defaultMessage:
'Allows to generate selected file format programmatically outside Kibana or in Watcher.',
}),
contentType: 'text',
generateAssetURIValue: () => absoluteUrl,
},
};
};

return {
shareType: 'integration',
id: 'csvReportsModal',
id: 'csvReports',
groupId: 'export',
config: getShareMenuItems,
prerequisiteCheck: ({ license, capabilities }) => {
if (!license) {
return false;
}

const licenseCheck = checkLicense(license.check('reporting', 'basic'));

const licenseHasCsvReporting = licenseCheck.showLinks;

const capabilityHasCsvReporting = capabilities.discover_v2?.generateCsv === true;

if (!(licenseHasCsvReporting && capabilityHasCsvReporting)) {
return false;
}

return true;
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ const getJobParams = (opts: JobParamsProviderOptions, type: 'pngV2' | 'printable

export const reportingPDFExportProvider = ({
apiClient,
license,
application,
startServices$,
}: ExportModalShareOpts): ExportShare => {
const supportedObjectTypes = ['dashboard', 'visualization', 'lens'];

const getShareMenuItems = ({
objectType,
objectId,
Expand All @@ -55,39 +55,6 @@ export const reportingPDFExportProvider = ({
toasts,
...shareOpts
}: ShareContext): ReturnType<ExportShare['config']> => {
const { enableLinks, showLinks, message } = checkLicense(license.check('reporting', 'gold'));
const licenseToolTipContent = message;
const licenseHasScreenshotReporting = showLinks;
const licenseDisabled = !enableLinks;

const capabilityHasDashboardScreenshotReporting =
application.capabilities.dashboard_v2?.generateScreenshot === true;
const capabilityHasVisualizeScreenshotReporting =
application.capabilities.visualize_v2?.generateScreenshot === true;

if (!licenseHasScreenshotReporting) {
return null;
}

// for lens png pdf and csv are combined into one modal
const isSupportedType = ['dashboard', 'visualization', 'lens'].includes(objectType);

if (!isSupportedType) {
return null;
}

if (objectType === 'dashboard' && !capabilityHasDashboardScreenshotReporting) {
return null;
}

if (
isSupportedType &&
!capabilityHasVisualizeScreenshotReporting &&
!capabilityHasDashboardScreenshotReporting
) {
return null;
}

const { sharingData } = shareOpts as unknown as { sharingData: ReportingSharingData };

const jobProviderOptions: JobParamsProviderOptions = {
Expand Down Expand Up @@ -159,15 +126,30 @@ export const reportingPDFExportProvider = ({
name: i18n.translate('reporting.shareContextMenu.ExportsButtonLabel', {
defaultMessage: 'PDF',
}),
toolTipContent: licenseToolTipContent,
disabled: licenseDisabled || sharingData.reportingDisabled,
icon: 'document',
disabled: sharingData.reportingDisabled,
label: 'PDF' as const,
generateAssetExport: generateReportPDF,
generateAssetURIValue: generateExportUrlPDF,
exportType: 'printablePdfV2',
requiresSavedState,
renderLayoutOptionSwitch: objectType === 'dashboard',
renderCopyURIButton: true,
copyAssetURIConfig: {
headingText: i18n.translate(
'reporting.shareContextMenu.copyUriModal.pdfExportCopyUriHeading',
{
defaultMessage: 'Post URL',
}
),
helpText: i18n.translate(
'reporting.shareContextMenu.copyUriModal.pdfExportCopyUriHelpText',
{
defaultMessage:
'Allows to generate selected file format programmatically outside Kibana or in Watcher.',
}
),
contentType: 'text',
generateAssetURIValue: generateExportUrlPDF,
},
};
};

Expand All @@ -176,15 +158,53 @@ export const reportingPDFExportProvider = ({
shareType: 'integration',
groupId: 'export',
config: getShareMenuItems,
prerequisiteCheck({ license, capabilities, objectType }) {
if (!license) {
return false;
}

let isSupportedType: boolean;

if (!(isSupportedType = supportedObjectTypes.includes(objectType))) {
return false;
}

const { showLinks: licenseHasScreenshotReporting } = checkLicense(
license.check('reporting', 'gold')
);

const capabilityHasDashboardScreenshotReporting =
capabilities.dashboard_v2?.generateScreenshot === true;
const capabilityHasVisualizeScreenshotReporting =
capabilities.visualize_v2?.generateScreenshot === true;

if (!licenseHasScreenshotReporting) {
return false;
}

if (objectType === 'dashboard' && !capabilityHasDashboardScreenshotReporting) {
return false;
}

if (
isSupportedType &&
!capabilityHasVisualizeScreenshotReporting &&
!capabilityHasDashboardScreenshotReporting
) {
return false;
}

return true;
},
};
};

export const reportingPNGExportProvider = ({
apiClient,
license,
application,
startServices$,
}: ExportModalShareOpts): ExportShare => {
const supportedObjectTypes = ['dashboard', 'visualization', 'lens'];

const getShareMenuItems = ({
objectType,
objectId,
Expand All @@ -194,39 +214,7 @@ export const reportingPNGExportProvider = ({
shareableUrlForSavedObject,
toasts,
...shareOpts
}: ShareContext): ReturnType<ExportShare['config']> | null => {
const { enableLinks, showLinks, message } = checkLicense(license.check('reporting', 'gold'));
const licenseToolTipContent = message;
const licenseHasScreenshotReporting = showLinks;
const licenseDisabled = !enableLinks;

const capabilityHasDashboardScreenshotReporting =
application.capabilities.dashboard_v2?.generateScreenshot === true;
const capabilityHasVisualizeScreenshotReporting =
application.capabilities.visualize_v2?.generateScreenshot === true;

if (!licenseHasScreenshotReporting) {
return null;
}
// for lens png pdf and csv are combined into one modal
const isSupportedType = ['dashboard', 'visualization', 'lens'].includes(objectType);

if (!isSupportedType) {
return null;
}

if (objectType === 'dashboard' && !capabilityHasDashboardScreenshotReporting) {
return null;
}

if (
isSupportedType &&
!capabilityHasVisualizeScreenshotReporting &&
!capabilityHasDashboardScreenshotReporting
) {
return null;
}

}: ShareContext): ReturnType<ExportShare['config']> => {
const { sharingData } = shareOpts as unknown as { sharingData: ReportingSharingData };

const jobProviderOptions: JobParamsProviderOptions = {
Expand Down Expand Up @@ -297,14 +285,29 @@ export const reportingPNGExportProvider = ({
name: i18n.translate('reporting.shareContextMenu.ExportsButtonLabelPNG', {
defaultMessage: 'PNG export',
}),
toolTipContent: licenseToolTipContent,
disabled: licenseDisabled || sharingData.reportingDisabled,
icon: 'image',
disabled: sharingData.reportingDisabled,
label: 'PNG' as const,
generateAssetExport: generateReportPNG,
generateAssetURIValue: generateExportUrlPNG,
exportType: 'pngV2',
requiresSavedState,
renderCopyURIButton: true,
copyAssetURIConfig: {
headingText: i18n.translate(
'reporting.shareContextMenu.copyUriModal.pngExportCopyUriHeading',
{
defaultMessage: 'Post URL',
}
),
helpText: i18n.translate(
'reporting.shareContextMenu.copyUriModal.pngExportCopyUriHelpText',
{
defaultMessage:
'Allows to generate selected file format programmatically outside Kibana or in Watcher.',
}
),
contentType: 'text',
generateAssetURIValue: generateExportUrlPNG,
},
};
};

Expand All @@ -313,5 +316,42 @@ export const reportingPNGExportProvider = ({
groupId: 'export',
id: 'imageReports',
config: getShareMenuItems,
prerequisiteCheck({ license, capabilities, objectType }) {
if (!license) {
return false;
}

let isSupportedType: boolean;

if (!(isSupportedType = supportedObjectTypes.includes(objectType))) {
return false;
}

const { showLinks } = checkLicense(license.check('reporting', 'gold'));
const licenseHasScreenshotReporting = showLinks;

const capabilityHasDashboardScreenshotReporting =
capabilities.dashboard_v2?.generateScreenshot === true;
const capabilityHasVisualizeScreenshotReporting =
capabilities.visualize_v2?.generateScreenshot === true;

if (!licenseHasScreenshotReporting) {
return false;
}

if (objectType === 'dashboard' && !capabilityHasDashboardScreenshotReporting) {
return false;
}

if (
isSupportedType &&
!capabilityHasVisualizeScreenshotReporting &&
!capabilityHasDashboardScreenshotReporting
) {
return false;
}

return true;
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export enum AppMenuActionId {
new = 'new',
open = 'open',
share = 'share',
export = 'export',
alerts = 'alerts',
inspect = 'inspect',
createRule = 'createRule',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ export const topNavStrings = {
defaultMessage: 'Switch to view-only mode',
}),
},
export: {
label: i18n.translate('dashboard.topNave.exportButtonAriaLabel', {
defaultMessage: 'Export',
}),
description: i18n.translate('dashboard.topNave.exportConfigDescription', {
defaultMessage: 'Export dashboard',
}),
},
share: {
label: i18n.translate('dashboard.topNave.shareButtonAriaLabel', {
defaultMessage: 'share',
Expand Down
Loading