diff --git a/src/plugins/dashboard/kibana.json b/src/plugins/dashboard/kibana.json index cb6a5383688dc..2be6e9b269e71 100644 --- a/src/plugins/dashboard/kibana.json +++ b/src/plugins/dashboard/kibana.json @@ -13,6 +13,7 @@ "navigation", "savedObjects", "share", + "screenshotMode", "uiActions", "urlForwarding", "presentationUtil", diff --git a/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx b/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx index fa484de2180b4..40f6f872535f9 100644 --- a/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx @@ -15,6 +15,7 @@ import { CoreStart } from 'kibana/public'; import { coreMock, uiSettingsServiceMock } from '../../../../../core/public/mocks'; import { embeddablePluginMock } from 'src/plugins/embeddable/public/mocks'; import { getStubPluginServices } from '../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; import { EmbeddableInput, @@ -65,6 +66,7 @@ beforeEach(async () => { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreStart.http, presentationUtil: getStubPluginServices(), + screenshotMode: screenshotModePluginMock.createSetupContract(), }; container = new DashboardContainer(getSampleDashboardInput(), containerOptions); diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx index 99665d312d32e..fc4c6b299284b 100644 --- a/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx @@ -23,6 +23,7 @@ import { } from '../../services/embeddable_test_samples'; import { ErrorEmbeddable, IContainer, isErrorEmbeddable } from '../../services/embeddable'; import { getStubPluginServices } from '../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; const { setup, doStart } = embeddablePluginMock.createInstance(); setup.registerEmbeddableFactory( @@ -56,6 +57,7 @@ beforeEach(async () => { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreStart.http, presentationUtil: getStubPluginServices(), + screenshotMode: screenshotModePluginMock.createSetupContract(), }; const input = getSampleDashboardInput({ panels: { diff --git a/src/plugins/dashboard/public/application/actions/expand_panel_action.test.tsx b/src/plugins/dashboard/public/application/actions/expand_panel_action.test.tsx index 0635152332993..b20a96c79aed6 100644 --- a/src/plugins/dashboard/public/application/actions/expand_panel_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/expand_panel_action.test.tsx @@ -13,6 +13,7 @@ import { getSampleDashboardInput, getSampleDashboardPanel } from '../test_helper import { embeddablePluginMock } from 'src/plugins/embeddable/public/mocks'; import { isErrorEmbeddable } from '../../services/embeddable'; import { getStubPluginServices } from '../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; import { CONTACT_CARD_EMBEDDABLE, @@ -48,6 +49,7 @@ beforeEach(async () => { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreMock.createStart().http, presentationUtil: getStubPluginServices(), + screenshotMode: screenshotModePluginMock.createSetupContract(), }; const input = getSampleDashboardInput({ panels: { diff --git a/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx b/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx index 51c64f1875376..797765eda232d 100644 --- a/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx @@ -25,6 +25,7 @@ import { DataPublicPluginStart } from '../../../../data/public/types'; import { dataPluginMock } from '../../../../data/public/mocks'; import { LINE_FEED_CHARACTER } from 'src/plugins/data/common/exports/export_csv'; import { getStubPluginServices } from '../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; describe('Export CSV action', () => { const { setup, doStart } = embeddablePluginMock.createInstance(); @@ -61,6 +62,7 @@ describe('Export CSV action', () => { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreStart.http, presentationUtil: getStubPluginServices(), + screenshotMode: screenshotModePluginMock.createSetupContract(), }; const input = getSampleDashboardInput({ panels: { diff --git a/src/plugins/dashboard/public/application/actions/library_notification_action.test.tsx b/src/plugins/dashboard/public/application/actions/library_notification_action.test.tsx index 587f741461bb4..ab442bf839e37 100644 --- a/src/plugins/dashboard/public/application/actions/library_notification_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/library_notification_action.test.tsx @@ -28,6 +28,7 @@ import { CONTACT_CARD_EMBEDDABLE, } from '../../services/embeddable_test_samples'; import { getStubPluginServices } from '../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; const { setup, doStart } = embeddablePluginMock.createInstance(); setup.registerEmbeddableFactory( @@ -62,6 +63,7 @@ beforeEach(async () => { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreStart.http, presentationUtil: getStubPluginServices(), + screenshotMode: screenshotModePluginMock.createSetupContract(), }; container = new DashboardContainer(getSampleDashboardInput(), containerOptions); diff --git a/src/plugins/dashboard/public/application/actions/library_notification_popover.test.tsx b/src/plugins/dashboard/public/application/actions/library_notification_popover.test.tsx index b5efa0447e651..de1a475fdbd18 100644 --- a/src/plugins/dashboard/public/application/actions/library_notification_popover.test.tsx +++ b/src/plugins/dashboard/public/application/actions/library_notification_popover.test.tsx @@ -29,6 +29,7 @@ import { ContactCardEmbeddable, } from '../../services/embeddable_test_samples'; import { getStubPluginServices } from '../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; describe('LibraryNotificationPopover', () => { const { setup, doStart } = embeddablePluginMock.createInstance(); @@ -58,6 +59,7 @@ describe('LibraryNotificationPopover', () => { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreStart.http, presentationUtil: getStubPluginServices(), + screenshotMode: screenshotModePluginMock.createSetupContract(), }; container = new DashboardContainer(getSampleDashboardInput(), containerOptions); diff --git a/src/plugins/dashboard/public/application/actions/replace_panel_action.test.tsx b/src/plugins/dashboard/public/application/actions/replace_panel_action.test.tsx index f8880ac5618fc..fe39f6112a7f3 100644 --- a/src/plugins/dashboard/public/application/actions/replace_panel_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/replace_panel_action.test.tsx @@ -22,6 +22,7 @@ import { ContactCardEmbeddableOutput, } from '../../services/embeddable_test_samples'; import { getStubPluginServices } from '../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; const { setup, doStart } = embeddablePluginMock.createInstance(); setup.registerEmbeddableFactory( @@ -48,6 +49,7 @@ beforeEach(async () => { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreStart.http, presentationUtil: getStubPluginServices(), + screenshotMode: screenshotModePluginMock.createSetupContract(), }; const input = getSampleDashboardInput({ panels: { diff --git a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.test.tsx b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.test.tsx index 7d87c49bda649..4f10f833f643c 100644 --- a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.test.tsx @@ -30,6 +30,7 @@ import { CONTACT_CARD_EMBEDDABLE, } from '../../services/embeddable_test_samples'; import { getStubPluginServices } from '../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; const { setup, doStart } = embeddablePluginMock.createInstance(); setup.registerEmbeddableFactory( @@ -57,6 +58,7 @@ beforeEach(async () => { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreStart.http, presentationUtil: getStubPluginServices(), + screenshotMode: screenshotModePluginMock.createSetupContract(), }; container = new DashboardContainer(getSampleDashboardInput(), containerOptions); diff --git a/src/plugins/dashboard/public/application/dashboard_app.tsx b/src/plugins/dashboard/public/application/dashboard_app.tsx index 3e6566f0da0a4..7aedbe9e11001 100644 --- a/src/plugins/dashboard/public/application/dashboard_app.tsx +++ b/src/plugins/dashboard/public/application/dashboard_app.tsx @@ -17,11 +17,11 @@ import { getDashboardTitle, leaveConfirmStrings, } from '../dashboard_strings'; -import { EmbeddableRenderer } from '../services/embeddable'; +import { createDashboardEditUrl } from '../dashboard_constants'; +import { EmbeddableRenderer, ViewMode } from '../services/embeddable'; import { DashboardTopNav, isCompleteDashboardAppState } from './top_nav/dashboard_top_nav'; import { DashboardAppServices, DashboardEmbedSettings, DashboardRedirect } from '../types'; import { createKbnUrlStateStorage, withNotifyOnErrors } from '../services/kibana_utils'; -import { createDashboardEditUrl } from '../dashboard_constants'; export interface DashboardAppProps { history: History; savedDashboardId?: string; @@ -51,7 +51,6 @@ export function DashboardApp({ const dashboardState = useDashboardSelector((state) => state.dashboardStateReducer); const dashboardAppState = useDashboardAppState({ history, - redirectTo, savedDashboardId, kbnUrlStateStorage, isEmbeddedExternally: Boolean(embedSettings), @@ -101,15 +100,26 @@ export function DashboardApp({ }; }, [data.search.session]); + const printMode = useMemo( + () => dashboardAppState.getLatestDashboardState?.().viewMode === ViewMode.PRINT, + [dashboardAppState] + ); + + useEffect(() => { + if (!embedSettings) chrome.setIsVisible(!printMode); + }, [chrome, printMode, embedSettings]); + return ( <> {isCompleteDashboardAppState(dashboardAppState) && ( <> - + {!printMode && ( + + )} {dashboardAppState.savedDashboard.outcome === 'conflict' && dashboardAppState.savedDashboard.id && diff --git a/src/plugins/dashboard/public/application/dashboard_router.tsx b/src/plugins/dashboard/public/application/dashboard_router.tsx index 4a22899c12e8a..c74ac506e4809 100644 --- a/src/plugins/dashboard/public/application/dashboard_router.tsx +++ b/src/plugins/dashboard/public/application/dashboard_router.tsx @@ -109,6 +109,7 @@ export async function mountApp({ embeddable: embeddableStart, uiSettings: coreStart.uiSettings, scopedHistory: () => scopedHistory, + screenshotModeService: screenshotMode, indexPatterns: dataStart.indexPatterns, savedQueryService: dataStart.query.savedQueries, savedObjectsClient: coreStart.savedObjects.client, @@ -131,7 +132,6 @@ export async function mountApp({ activeSpaceId || 'default' ), spacesService: spacesApi, - screenshotModeService: screenshotMode, }; const getUrlStateStorage = (history: RouteComponentProps['history']) => diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx index 6cd102a4d4770..744d63c1ba04a 100644 --- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx +++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx @@ -43,11 +43,13 @@ import { getStubPluginServices } from '../../../../presentation_util/public'; const presentationUtil = getStubPluginServices(); const options: DashboardContainerServices = { + // TODO: clean up use of any application: {} as any, embeddable: {} as any, notifications: {} as any, overlays: {} as any, inspector: {} as any, + screenshotMode: {} as any, SavedObjectFinder: () => null, ExitFullScreenButton: () => null, uiActions: {} as any, diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx index 54fa1f05b9c0d..d7081bf020d85 100644 --- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx @@ -40,6 +40,7 @@ import { import { PLACEHOLDER_EMBEDDABLE } from './placeholder'; import { DashboardAppCapabilities, DashboardContainerInput } from '../../types'; import { PresentationUtilPluginStart } from '../../services/presentation_util'; +import type { ScreenshotModePluginStart } from '../../services/screenshot_mode'; import { PanelPlacementMethod, IPanelPlacementArgs } from './panel/dashboard_panel_placement'; import { combineDashboardFiltersWithControlGroupFilters, @@ -55,6 +56,7 @@ export interface DashboardContainerServices { application: CoreStart['application']; inspector: InspectorStartContract; overlays: CoreStart['overlays']; + screenshotMode: ScreenshotModePluginStart; uiSettings: IUiSettingsClient; embeddable: EmbeddableStart; uiActions: UiActionsStart; diff --git a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.test.tsx b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.test.tsx index 52f04bcead665..7518a36433d35 100644 --- a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.test.tsx +++ b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.test.tsx @@ -23,6 +23,7 @@ import { } from '../../../services/embeddable_test_samples'; import { coreMock, uiSettingsServiceMock } from '../../../../../../core/public/mocks'; import { getStubPluginServices } from '../../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../../screenshot_mode/public/mocks'; let dashboardContainer: DashboardContainer | undefined; const presentationUtil = getStubPluginServices(); @@ -71,6 +72,7 @@ function prepare(props?: Partial) { uiSettings: uiSettingsServiceMock.createStartContract(), http: coreMock.createStart().http, presentationUtil, + screenshotMode: screenshotModePluginMock.createSetupContract(), }; dashboardContainer = new DashboardContainer(initialInput, options); const defaultTestProps: DashboardGridProps = { diff --git a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx index 9d2afdba36dbc..09ac0c1dd94bb 100644 --- a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx +++ b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx @@ -154,7 +154,7 @@ class DashboardGridUi extends React.Component { id: 'dashboard.dashboardGrid.toast.unableToLoadDashboardDangerMessage', defaultMessage: 'Unable to load dashboard.', }), - body: error.message, + body: (error as { message: string }).message, toastLifeTimeMs: 5000, }); } @@ -254,6 +254,11 @@ class DashboardGridUi extends React.Component { /> )); + // in print mode, dashboard layout is not controlled by React Grid Layout + if (viewMode === ViewMode.PRINT) { + return <>{dashboardPanels}; + } + return ( ; type DivProps = Pick, 'className' | 'style' | 'children'>; @@ -20,6 +21,7 @@ type DivProps = Pick, 'className' | 'style' interface Props extends PanelProps, DivProps { id: DashboardPanelState['explicitInput']['id']; type: DashboardPanelState['type']; + container: DashboardContainer; focusedPanelId?: string; expandedPanelId?: string; key: string; @@ -52,6 +54,8 @@ const Item = React.forwardRef( 'dshDashboardGrid__item--expanded': expandPanel, // eslint-disable-next-line @typescript-eslint/naming-convention 'dshDashboardGrid__item--hidden': hidePanel, + // eslint-disable-next-line @typescript-eslint/naming-convention + printViewport__vis: container.getInput().viewMode === ViewMode.PRINT, }); return ( @@ -116,7 +120,8 @@ export const ObservedItem: FC = (props: Props) => { export const DashboardGridItem: FC = (props: Props) => { const { isProjectEnabled } = useLabs(); - const isEnabled = isProjectEnabled('labs:dashboard:deferBelowFold'); + const isPrintMode = props.container.getInput().viewMode === ViewMode.PRINT; + const isEnabled = !isPrintMode && isProjectEnabled('labs:dashboard:deferBelowFold'); return isEnabled ? : ; }; diff --git a/src/plugins/dashboard/public/application/embeddable/viewport/_index.scss b/src/plugins/dashboard/public/application/embeddable/viewport/_index.scss index 56483d9d10195..02411f5902b3b 100644 --- a/src/plugins/dashboard/public/application/embeddable/viewport/_index.scss +++ b/src/plugins/dashboard/public/application/embeddable/viewport/_index.scss @@ -1 +1,2 @@ @import './dashboard_viewport'; +@import './print_viewport'; diff --git a/src/plugins/dashboard/public/application/embeddable/viewport/_print_viewport.scss b/src/plugins/dashboard/public/application/embeddable/viewport/_print_viewport.scss new file mode 100644 index 0000000000000..a451178cc46b0 --- /dev/null +++ b/src/plugins/dashboard/public/application/embeddable/viewport/_print_viewport.scss @@ -0,0 +1,9 @@ +.printViewport { + &__vis { + height: 600px; // These values might need to be passed in as dimensions for the report. I.e., print should use layout dimensions. + width: 975px; + + // Some vertical space between vis, but center horizontally + margin: 10px auto; + } +} diff --git a/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx b/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx index 7c671ce7736d7..f0333cefd612f 100644 --- a/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx +++ b/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx @@ -27,6 +27,7 @@ import { CONTACT_CARD_EMBEDDABLE, } from '../../../../../embeddable/public/lib/test_samples'; import { getStubPluginServices } from '../../../../../presentation_util/public'; +import { screenshotModePluginMock } from '../../../../../screenshot_mode/public/mocks'; let dashboardContainer: DashboardContainer | undefined; const presentationUtil = getStubPluginServices(); @@ -65,6 +66,7 @@ function getProps(props?: Partial): { getTriggerCompatibleActions: (() => []) as any, } as any, presentationUtil, + screenshotMode: screenshotModePluginMock.createSetupContract(), }; const input = getSampleDashboardInput({ diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx index 5561d1676e41c..0ef21fca26f29 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.test.tsx @@ -52,7 +52,6 @@ const createDashboardAppStateProps = (): UseDashboardStateProps => ({ savedDashboardId: 'testDashboardId', history: createBrowserHistory(), isEmbeddedExternally: false, - redirectTo: jest.fn(), }); const createDashboardAppStateServices = () => { diff --git a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts index fddcc309e1ef1..cb5c7483f261a 100644 --- a/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts +++ b/src/plugins/dashboard/public/application/hooks/use_dashboard_app_state.ts @@ -22,7 +22,6 @@ import { DashboardBuildContext, DashboardAppServices, DashboardAppState, - DashboardRedirect, DashboardState, } from '../../types'; import { DashboardAppLocatorParams } from '../../locator'; @@ -44,14 +43,12 @@ import { export interface UseDashboardStateProps { history: History; savedDashboardId?: string; - redirectTo: DashboardRedirect; isEmbeddedExternally: boolean; kbnUrlStateStorage: IKbnUrlStateStorage; } export const useDashboardAppState = ({ history, - redirectTo, savedDashboardId, kbnUrlStateStorage, isEmbeddedExternally, @@ -184,12 +181,20 @@ export const useDashboardAppState = ({ savedDashboard, }); + // Backwards compatible way of detecting that we are taking a screenshot + const legacyPrintLayoutDetected = + screenshotModeService?.isScreenshotMode() && + screenshotModeService.getScreenshotLayout() === 'print'; + const initialDashboardState = { ...savedDashboardState, ...dashboardSessionStorageState, ...initialDashboardStateFromUrl, ...forwardedAppState, + // if we are in legacy print mode, dashboard needs to be in print viewMode + ...(legacyPrintLayoutDetected ? { viewMode: ViewMode.PRINT } : {}), + // if there is an incoming embeddable, dashboard always needs to be in edit mode to receive it. ...(incomingEmbeddable ? { viewMode: ViewMode.EDIT } : {}), }; diff --git a/src/plugins/dashboard/public/application/test_helpers/make_default_services.ts b/src/plugins/dashboard/public/application/test_helpers/make_default_services.ts index cce2b4eb042ef..616fe56102df9 100644 --- a/src/plugins/dashboard/public/application/test_helpers/make_default_services.ts +++ b/src/plugins/dashboard/public/application/test_helpers/make_default_services.ts @@ -15,6 +15,7 @@ import { DashboardAppServices, DashboardAppCapabilities } from '../../types'; import { embeddablePluginMock } from '../../../../embeddable/public/mocks'; import { IndexPatternsContract, SavedQueryService } from '../../services/data'; import { savedObjectsPluginMock } from '../../../../saved_objects/public/mocks'; +import { screenshotModePluginMock } from '../../../../screenshot_mode/public/mocks'; import { visualizationsPluginMock } from '../../../../visualizations/public/mocks'; import { PluginInitializerContext, ScopedHistory } from '../../../../../core/public'; import { SavedObjectLoader, SavedObjectLoaderFindOptions } from '../../services/saved_objects'; @@ -72,6 +73,7 @@ export function makeDefaultServices(): DashboardAppServices { } as PluginInitializerContext; return { + screenshotModeService: screenshotModePluginMock.createSetupContract(), visualizations: visualizationsPluginMock.createStartContract(), savedObjects: savedObjectsPluginMock.createStartContract(), embeddable: embeddablePluginMock.createInstance().doStart(), diff --git a/src/plugins/dashboard/public/dashboard_constants.ts b/src/plugins/dashboard/public/dashboard_constants.ts index 409d80e2ef066..6f9a30e3a7041 100644 --- a/src/plugins/dashboard/public/dashboard_constants.ts +++ b/src/plugins/dashboard/public/dashboard_constants.ts @@ -14,6 +14,7 @@ export const DashboardConstants = { LANDING_PAGE_PATH: '/list', CREATE_NEW_DASHBOARD_URL: '/create', VIEW_DASHBOARD_URL: '/view', + PRINT_DASHBOARD_URL: '/print', ADD_EMBEDDABLE_ID: 'addEmbeddableId', ADD_EMBEDDABLE_TYPE: 'addEmbeddableType', DASHBOARDS_ID: 'dashboards', diff --git a/src/plugins/dashboard/public/locator.ts b/src/plugins/dashboard/public/locator.ts index a256a65a5d7f4..b6655e246de36 100644 --- a/src/plugins/dashboard/public/locator.ts +++ b/src/plugins/dashboard/public/locator.ts @@ -128,6 +128,7 @@ export class DashboardAppLocatorDefinition implements LocatorDefinition => { diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index ff0ac0642ec91..9912aef943144 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -12,7 +12,6 @@ import { filter, map } from 'rxjs/operators'; import { Start as InspectorStartContract } from 'src/plugins/inspector/public'; import { UrlForwardingSetup, UrlForwardingStart } from 'src/plugins/url_forwarding/public'; -import { ScreenshotModePluginStart } from 'src/plugins/screenshot_mode/public'; import { APP_WRAPPER_CLASS } from '../../../core/public'; import { App, @@ -37,6 +36,10 @@ import { NavigationPublicPluginStart as NavigationStart } from './services/navig import { DataPublicPluginSetup, DataPublicPluginStart, esFilters } from './services/data'; import { SharePluginSetup, SharePluginStart, UrlGeneratorContract } from './services/share'; import type { SavedObjectTaggingOssPluginStart } from './services/saved_objects_tagging_oss'; +import type { + ScreenshotModePluginSetup, + ScreenshotModePluginStart, +} from './services/screenshot_mode'; import { getSavedObjectFinder, SavedObjectLoader, @@ -102,6 +105,7 @@ export interface DashboardSetupDependencies { share?: SharePluginSetup; uiActions: UiActionsSetup; usageCollection?: UsageCollectionSetup; + screenshotMode: ScreenshotModePluginSetup; } export interface DashboardStartDependencies { @@ -116,9 +120,9 @@ export interface DashboardStartDependencies { savedObjects: SavedObjectsStart; presentationUtil: PresentationUtilPluginStart; savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart; - screenshotMode?: ScreenshotModePluginStart; spaces?: SpacesPluginStart; visualizations: VisualizationsStart; + screenshotMode: ScreenshotModePluginStart; } export interface DashboardSetup { @@ -162,7 +166,15 @@ export class DashboardPlugin public setup( core: CoreSetup, - { share, embeddable, home, urlForwarding, data, usageCollection }: DashboardSetupDependencies + { + share, + embeddable, + home, + urlForwarding, + data, + usageCollection, + screenshotMode, + }: DashboardSetupDependencies ): DashboardSetup { this.dashboardFeatureFlagConfig = this.initializerContext.config.get(); @@ -197,6 +209,7 @@ export class DashboardPlugin embeddable: deps.embeddable, uiActions: deps.uiActions, inspector: deps.inspector, + screenshotMode: deps.screenshotMode, http: coreStart.http, ExitFullScreenButton, presentationUtil: deps.presentationUtil, diff --git a/src/plugins/dashboard/public/services/screenshot_mode.ts b/src/plugins/dashboard/public/services/screenshot_mode.ts new file mode 100644 index 0000000000000..12ec1bca2207f --- /dev/null +++ b/src/plugins/dashboard/public/services/screenshot_mode.ts @@ -0,0 +1,14 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { + ScreenshotModePluginStart, + ScreenshotModePluginSetup, +} from '../../../screenshot_mode/public'; + +export type { Layout } from '../../../screenshot_mode/common'; diff --git a/src/plugins/dashboard/public/types.ts b/src/plugins/dashboard/public/types.ts index d4a6cb20bc551..b7b146aeba348 100644 --- a/src/plugins/dashboard/public/types.ts +++ b/src/plugins/dashboard/public/types.ts @@ -19,7 +19,6 @@ import type { import { History } from 'history'; import { AnyAction, Dispatch } from 'redux'; import { BehaviorSubject, Subject } from 'rxjs'; -import { ScreenshotModePluginStart } from 'src/plugins/screenshot_mode/public'; import { Query, Filter, IndexPattern, RefreshInterval, TimeRange } from './services/data'; import { ContainerInput, EmbeddableInput, ViewMode } from './services/embeddable'; import { SharePluginStart } from './services/share'; @@ -33,6 +32,7 @@ import { SavedObjectsTaggingApi } from './services/saved_objects_tagging_oss'; import { DataPublicPluginStart, IndexPatternsContract } from './services/data'; import { SavedObjectLoader, SavedObjectsStart } from './services/saved_objects'; import { IKbnUrlStateStorage } from './services/kibana_utils'; +import type { ScreenshotModePluginStart } from './services/screenshot_mode'; import type { DashboardContainer, DashboardSavedObject } from '.'; import { VisualizationsStart } from '../../visualizations/public'; import { DashboardAppLocatorParams } from './locator'; @@ -206,9 +206,9 @@ export interface DashboardAppServices { onAppLeave: AppMountParameters['onAppLeave']; savedObjectsTagging?: SavedObjectsTaggingApi; savedObjectsClient: SavedObjectsClientContract; + screenshotModeService: ScreenshotModePluginStart; dashboardSessionStorage: DashboardSessionStorage; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; savedQueryService: DataPublicPluginStart['query']['savedQueries']; spacesService?: SpacesPluginStart; - screenshotModeService?: ScreenshotModePluginStart; } diff --git a/src/plugins/embeddable/common/types.ts b/src/plugins/embeddable/common/types.ts index c3cac2d5d67db..b9d9d4cc34146 100644 --- a/src/plugins/embeddable/common/types.ts +++ b/src/plugins/embeddable/common/types.ts @@ -13,6 +13,7 @@ import { PersistableStateService, PersistableState } from '../../kibana_utils/co export enum ViewMode { EDIT = 'edit', PREVIEW = 'preview', + PRINT = 'print', VIEW = 'view', } diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx index 9807a47698a50..6748e9f3b1d08 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx @@ -251,7 +251,7 @@ export class EmbeddablePanel extends React.Component { }; public render() { - const viewOnlyMode = this.state.viewMode === ViewMode.VIEW; + const viewOnlyMode = [ViewMode.VIEW, ViewMode.PRINT].includes(this.state.viewMode); const classes = classNames('embPanel', { 'embPanel--editing': !viewOnlyMode, 'embPanel--loading': this.state.loading, diff --git a/src/plugins/newsfeed/public/plugin.test.ts b/src/plugins/newsfeed/public/plugin.test.ts index 4be69feb79f55..3497a1e52697d 100644 --- a/src/plugins/newsfeed/public/plugin.test.ts +++ b/src/plugins/newsfeed/public/plugin.test.ts @@ -10,6 +10,7 @@ import { take } from 'rxjs/operators'; import { coreMock } from '../../../core/public/mocks'; import { NewsfeedPublicPlugin } from './plugin'; import { NewsfeedApiEndpoint } from './lib/api'; +import { screenshotModePluginMock } from '../../screenshot_mode/public/mocks'; describe('Newsfeed plugin', () => { let plugin: NewsfeedPublicPlugin; @@ -46,7 +47,7 @@ describe('Newsfeed plugin', () => { describe('base case', () => { it('makes fetch requests', () => { const startContract = plugin.start(coreMock.createStart(), { - screenshotMode: { isScreenshotMode: () => false }, + screenshotMode: screenshotModePluginMock.createSetupContract(), }); const sub = startContract .createNewsFeed$(NewsfeedApiEndpoint.KIBANA) // Any endpoint will do @@ -60,8 +61,10 @@ describe('Newsfeed plugin', () => { describe('when in screenshot mode', () => { it('makes no fetch requests in screenshot mode', () => { + const screenshotMode = screenshotModePluginMock.createSetupContract(); + screenshotMode.isScreenshotMode.mockReturnValue(true); const startContract = plugin.start(coreMock.createStart(), { - screenshotMode: { isScreenshotMode: () => true }, + screenshotMode, }); const sub = startContract .createNewsFeed$(NewsfeedApiEndpoint.KIBANA) // Any endpoint will do diff --git a/src/plugins/screenshot_mode/common/get_set_browser_screenshot_mode.ts b/src/plugins/screenshot_mode/common/get_set_browser_screenshot_mode.ts index ff79ccf0126f4..850f70d2d002a 100644 --- a/src/plugins/screenshot_mode/common/get_set_browser_screenshot_mode.ts +++ b/src/plugins/screenshot_mode/common/get_set_browser_screenshot_mode.ts @@ -7,7 +7,7 @@ */ // **PLEASE NOTE** -// The functionality in this file targets a browser environment and is intended to be used both in public and server. +// The functionality in this file targets a browser environment AND is intended to be used both in public and server. // For instance, reporting uses these functions when starting puppeteer to set the current browser into "screenshot" mode. export const KBN_SCREENSHOT_MODE_ENABLED_KEY = '__KBN_SCREENSHOT_MODE_ENABLED_KEY__'; @@ -61,3 +61,31 @@ export const setScreenshotModeDisabled = () => { } ); }; + +/** @deprecated */ +export const KBN_SCREENSHOT_MODE_LAYOUT_KEY = '__KBN_SCREENSHOT_MODE_LAYOUT_KEY__'; + +/** @deprecated */ +export type Layout = 'canvas' | 'preserve_layout' | 'print'; + +/** @deprecated */ +export const setScreenshotLayout = (value: Layout) => { + Object.defineProperty( + window, + '__KBN_SCREENSHOT_MODE_LAYOUT_KEY__', // Literal value to prevent adding an external reference + { + enumerable: true, + writable: true, + configurable: false, + value, + } + ); +}; + +/** @deprecated */ +export const getScreenshotLayout = (): undefined | Layout => { + return ( + (window as unknown as Record)[KBN_SCREENSHOT_MODE_LAYOUT_KEY] || + (window.localStorage.getItem(KBN_SCREENSHOT_MODE_LAYOUT_KEY) as Layout) + ); +}; diff --git a/src/plugins/screenshot_mode/common/index.ts b/src/plugins/screenshot_mode/common/index.ts index 9c8c3d24ef289..949691911fc27 100644 --- a/src/plugins/screenshot_mode/common/index.ts +++ b/src/plugins/screenshot_mode/common/index.ts @@ -11,6 +11,11 @@ export { setScreenshotModeEnabled, setScreenshotModeDisabled, KBN_SCREENSHOT_MODE_ENABLED_KEY, + KBN_SCREENSHOT_MODE_LAYOUT_KEY, + setScreenshotLayout, + getScreenshotLayout, } from './get_set_browser_screenshot_mode'; +export type { Layout } from './get_set_browser_screenshot_mode'; + export { KBN_SCREENSHOT_MODE_HEADER } from './constants'; diff --git a/src/plugins/screenshot_mode/public/mocks.ts b/src/plugins/screenshot_mode/public/mocks.ts index 7fa93ff0bcea8..d7e69e9d89211 100644 --- a/src/plugins/screenshot_mode/public/mocks.ts +++ b/src/plugins/screenshot_mode/public/mocks.ts @@ -11,9 +11,11 @@ import type { ScreenshotModePluginSetup, ScreenshotModePluginStart } from './typ export const screenshotModePluginMock = { createSetupContract: (): DeeplyMockedKeys => ({ + getScreenshotLayout: jest.fn(), isScreenshotMode: jest.fn(() => false), }), createStartContract: (): DeeplyMockedKeys => ({ + getScreenshotLayout: jest.fn(), isScreenshotMode: jest.fn(() => false), }), }; diff --git a/src/plugins/screenshot_mode/public/plugin.ts b/src/plugins/screenshot_mode/public/plugin.ts index a005bb7c3d055..bb34fe84e2c39 100644 --- a/src/plugins/screenshot_mode/public/plugin.ts +++ b/src/plugins/screenshot_mode/public/plugin.ts @@ -10,11 +10,12 @@ import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { ScreenshotModePluginSetup, ScreenshotModePluginStart } from './types'; -import { getScreenshotMode } from '../common'; +import { getScreenshotMode, getScreenshotLayout } from '../common'; export class ScreenshotModePlugin implements Plugin { private publicContract = Object.freeze({ isScreenshotMode: () => getScreenshotMode() === true, + getScreenshotLayout, }); public setup(core: CoreSetup): ScreenshotModePluginSetup { diff --git a/src/plugins/screenshot_mode/public/types.ts b/src/plugins/screenshot_mode/public/types.ts index f6963de0cbd63..d1603cbceb26f 100644 --- a/src/plugins/screenshot_mode/public/types.ts +++ b/src/plugins/screenshot_mode/public/types.ts @@ -6,12 +6,17 @@ * Side Public License, v 1. */ +import type { Layout } from '../common'; + export interface IScreenshotModeService { /** * Returns a boolean indicating whether the current user agent (browser) would like to view UI optimized for * screenshots or printing. */ isScreenshotMode: () => boolean; + + /** @deprecated */ + getScreenshotLayout: () => undefined | Layout; } export type ScreenshotModePluginSetup = IScreenshotModeService; diff --git a/src/plugins/screenshot_mode/server/plugin.ts b/src/plugins/screenshot_mode/server/plugin.ts index 9295451f640c2..b885ff97bf262 100644 --- a/src/plugins/screenshot_mode/server/plugin.ts +++ b/src/plugins/screenshot_mode/server/plugin.ts @@ -30,10 +30,11 @@ export class ScreenshotModePlugin // We use "require" here to ensure the import does not have external references due to code bundling that // commonly happens during transpiling. External references would be missing in the environment puppeteer creates. // eslint-disable-next-line @typescript-eslint/no-var-requires - const { setScreenshotModeEnabled } = require('../common'); + const { setScreenshotModeEnabled, setScreenshotLayout } = require('../common'); return { setScreenshotModeEnabled, + setScreenshotLayout, isScreenshotMode, }; } diff --git a/src/plugins/screenshot_mode/server/types.ts b/src/plugins/screenshot_mode/server/types.ts index 566ae19719454..1b9f3868f0966 100644 --- a/src/plugins/screenshot_mode/server/types.ts +++ b/src/plugins/screenshot_mode/server/types.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import { RequestHandlerContext, KibanaRequest } from 'src/core/server'; +import type { RequestHandlerContext, KibanaRequest } from 'src/core/server'; +import type { Layout } from '../common'; /** * Any context that requires access to the screenshot mode flag but does not have access @@ -23,6 +24,9 @@ export interface ScreenshotModePluginSetup { * on the page have run to ensure that screenshot mode is detected as early as possible. */ setScreenshotModeEnabled: () => void; + + /** @deprecated */ + setScreenshotLayout: (value: Layout) => void; } export interface ScreenshotModePluginStart { diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver/chromium_driver.ts b/x-pack/plugins/reporting/server/browsers/chromium/driver/chromium_driver.ts index 0947d24f827c2..0f2572ff2b2e4 100644 --- a/x-pack/plugins/reporting/server/browsers/chromium/driver/chromium_driver.ts +++ b/x-pack/plugins/reporting/server/browsers/chromium/driver/chromium_driver.ts @@ -17,7 +17,7 @@ import { ReportingCore } from '../../..'; import { KBN_SCREENSHOT_MODE_HEADER } from '../../../../../../../src/plugins/screenshot_mode/server'; import { ConditionalHeaders, ConditionalHeadersConditions } from '../../../export_types/common'; import { LevelLogger } from '../../../lib'; -import { ViewZoomWidthHeight } from '../../../lib/layouts/layout'; +import { Layout, ViewZoomWidthHeight } from '../../../lib/layouts/layout'; import { ElementPosition } from '../../../lib/screenshots'; import { allowRequest, NetworkPolicy } from '../../network_policy'; @@ -97,11 +97,13 @@ export class HeadlessChromiumDriver { waitForSelector: pageLoadSelector, timeout, locator, + layout, }: { conditionalHeaders: ConditionalHeaders; waitForSelector: string; timeout: number; locator?: LocatorParams; + layout?: Layout; }, logger: LevelLogger ): Promise { @@ -116,6 +118,10 @@ export class HeadlessChromiumDriver { */ await this.page.evaluateOnNewDocument(this.core.getEnableScreenshotMode()); + if (layout) { + await this.page.evaluateOnNewDocument(this.core.getSetScreenshotLayout(), layout.id); + } + if (locator) { await this.page.evaluateOnNewDocument( (key: string, value: unknown) => { diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index bc74f5463ba33..43aefb73aebb9 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -253,9 +253,16 @@ export class ReportingCore { .toPromise(); } + private getScreenshotModeDep() { + return this.getPluginSetupDeps().screenshotMode; + } + public getEnableScreenshotMode() { - const { screenshotMode } = this.getPluginSetupDeps(); - return screenshotMode.setScreenshotModeEnabled; + return this.getScreenshotModeDep().setScreenshotModeEnabled; + } + + public getSetScreenshotLayout() { + return this.getScreenshotModeDep().setScreenshotLayout; } /* diff --git a/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.css b/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.css index 508d217cdd030..60513c417165f 100644 --- a/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.css +++ b/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.css @@ -5,7 +5,7 @@ ****** */ - /** +/** * global */ @@ -27,7 +27,6 @@ filter-bar, * Discover Tweaks */ - /* hide unusable controls */ discover-app .dscTimechart, discover-app .dscSidebar__container, @@ -36,7 +35,6 @@ discover-app .discover-table-footer { display: none; } - /** * The global banner (e.g. "Help us improve Elastic...") should not print. */ @@ -73,7 +71,8 @@ discover-app .discover-table-footer { position: fixed; width: 100%; height: 100%; - top: 0; left: 0; + top: 0; + left: 0; } /** diff --git a/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.ts b/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.ts index 424e85327c22b..7f6bc9e5d9505 100644 --- a/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.ts +++ b/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import path from 'path'; import { CustomPageSize } from 'pdfmake/interfaces'; import { LAYOUT_TYPES } from '../../../common/constants'; @@ -37,6 +36,7 @@ export class PreserveLayout extends Layout implements LayoutInstance { } public getCssOverridesPath() { + // TODO: Remove this path once we have migrated all plugins away from depending on this hiding page elements. return path.join(__dirname, 'preserve_layout.css'); } diff --git a/x-pack/plugins/reporting/server/lib/layouts/print.css b/x-pack/plugins/reporting/server/lib/layouts/print.css deleted file mode 100644 index 7d38ebe81e4e8..0000000000000 --- a/x-pack/plugins/reporting/server/lib/layouts/print.css +++ /dev/null @@ -1,122 +0,0 @@ -/* - ****** - ****** This is a collection of CSS overrides that make Kibana look better for - ****** generating PDF reports with headless browser - ****** - */ - -/** - * global - */ - -/* elements can hide themselves when shared */ -.hide-for-sharing { - display: none !important; -} - -/* hide unusable controls */ -kbn-top-nav, -filter-bar, -.kbnTopNavMenu__wrapper, -::-webkit-scrollbar, -.euiNavDrawer { - display: none !important; -} - -/** - * Discover Tweaks - */ - -/* hide unusable controls */ -discover-app .dscTimechart, -discover-app .dscSidebar__container, -discover-app .dscCollapsibleSidebar__collapseButton, -discover-app .discover-table-footer { - display: none; -} - -/** - * The global banner (e.g. "Help us improve Elastic...") should not print. - */ - -#globalBannerList { - display: none; -} - -/** - * Visualize Editor Tweaks - */ - -/* hide unusable controls -* !important is required to override resizable panel inline display */ -.visEditor__content .visEditor--default > :not(.visEditor__visualization__wrapper) { - display: none !important; -} -/** THIS IS FOR TSVB UNTIL REFACTOR **/ -.tvbEditorVisualization { - position: static !important; -} -.visualize .tvbVisTimeSeries__legendToggle, -.tvbEditor--hideForReporting { - /* all non-content rows in interface */ - display: none; -} -/** END TSVB BAD BAD HACKS **/ - -/* remove left padding from visualizations so that map lines up with .leaflet-container and -* setting the position to be fixed and to take up the entire screen, because some zoom levels/viewports -* are triggering the media breakpoints that cause the .visEditor__canvas to take up more room than the viewport */ -.visEditor .visEditor__canvas { - padding-left: 0px; - position: fixed; - width: 100%; - height: 100%; - top: 0; - left: 0; -} - -/** - * Visualization tweaks - */ - -/* hide unusable controls */ -.visualize .visLegend__toggle, -.visualize .kbnAggTable__controls/* export raw, export formatted, etc. */, -.visualize .leaflet-container .leaflet-top.leaflet-left/* tilemap controls */, -.visualize paginate-controls { - display: none; -} - -/* Ensure the min-height of the small breakpoint isn't used */ -.vis-editor visualization { - min-height: 0 !important; -} - -/** -* Dashboard tweaks -*/ - -.dashboardViewport .embPanel__header { - /* hide the panel heading with the controls and title */ - display: none !important; -} - -.dashboardViewport .euiPanel { - /* Remove the border from the eui panel */ - border: none !important; -} - -/** - * 1. Reporting manually makes each visualization it wants to screenshot larger, so we need to hide - * the visualizations in the other panels. We can only use properties that will be manually set in - * reporting/export_types/printable_pdf/lib/screenshot.js or this will also hide the visualization - * we want to capture. - * 2. React grid item's transform affects the visualizations, even when they are using fixed positioning. Chrome seems - * to handle this fine, but firefox moves the visualizations around. - */ -.dashboardViewport .react-grid-item { - height: 0 !important; /* 1. */ - width: 0 !important; /* 1. */ - transform: none !important; /* 2. */ - -webkit-transform: none !important; /* 2. */ -} diff --git a/x-pack/plugins/reporting/server/lib/layouts/print_layout.ts b/x-pack/plugins/reporting/server/lib/layouts/print_layout.ts index 0849f8850f91d..68226affb41e4 100644 --- a/x-pack/plugins/reporting/server/lib/layouts/print_layout.ts +++ b/x-pack/plugins/reporting/server/lib/layouts/print_layout.ts @@ -5,13 +5,8 @@ * 2.0. */ -import path from 'path'; import { PageOrientation, PredefinedPageSize } from 'pdfmake/interfaces'; -import { EvaluateFn, SerializableOrJSHandle } from 'puppeteer'; -import { LevelLogger } from '../'; import { DEFAULT_VIEWPORT, LAYOUT_TYPES } from '../../../common/constants'; -import { Size } from '../../../common/types'; -import { HeadlessChromiumDriver } from '../../browsers'; import { CaptureConfig } from '../../types'; import { getDefaultLayoutSelectors, LayoutInstance, LayoutSelectorDictionary } from './'; import { Layout } from './layout'; @@ -31,7 +26,7 @@ export class PrintLayout extends Layout implements LayoutInstance { } public getCssOverridesPath() { - return path.join(__dirname, 'print.css'); + return undefined; } public getBrowserViewport() { @@ -49,40 +44,6 @@ export class PrintLayout extends Layout implements LayoutInstance { height: this.viewport.height * itemsCount, }; } - - public async positionElements( - browser: HeadlessChromiumDriver, - logger: LevelLogger - ): Promise { - logger.debug('positioning elements'); - - const elementSize: Size = { - width: this.viewport.width / this.captureConfig.zoom, - height: this.viewport.height / this.captureConfig.zoom, - }; - const evalOptions: { fn: EvaluateFn; args: SerializableOrJSHandle[] } = { - fn: (selector: string, height: number, width: number) => { - const visualizations = document.querySelectorAll(selector) as NodeListOf; - const visualizationsLength = visualizations.length; - - for (let i = 0; i < visualizationsLength; i++) { - const visualization = visualizations[i]; - const style = visualization.style; - style.position = 'fixed'; - style.top = `${height * i}px`; - style.left = '0'; - style.width = `${width}px`; - style.height = `${height}px`; - style.zIndex = '1'; - style.backgroundColor = 'inherit'; - } - }, - args: [this.selectors.screenshot, elementSize.height, elementSize.width], - }; - - await browser.evaluate(evalOptions, { context: 'PositionElements' }, logger); - } - public getPdfImageSize() { return { width: 500, diff --git a/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.ts b/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.ts index 1db313b091025..cdbddb8d89c89 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/observable_handler.ts @@ -76,6 +76,7 @@ export class ScreenshotObservableHandler { index, urlOrUrlLocatorTuple, this.conditionalHeaders, + this.layout, this.logger ) ).pipe(this.waitUntil(this.timeouts.openUrl)); diff --git a/x-pack/plugins/reporting/server/lib/screenshots/open_url.ts b/x-pack/plugins/reporting/server/lib/screenshots/open_url.ts index 63a5e80289e3e..b26037aa917b8 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/open_url.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/open_url.ts @@ -10,6 +10,7 @@ import { LevelLogger, startTrace } from '../'; import { LocatorParams, UrlOrUrlLocatorTuple } from '../../../common/types'; import { HeadlessChromiumDriver } from '../../browsers'; import { ConditionalHeaders } from '../../export_types/common'; +import { Layout } from '../layouts'; import { DEFAULT_PAGELOAD_SELECTOR } from './constants'; export const openUrl = async ( @@ -18,6 +19,7 @@ export const openUrl = async ( index: number, urlOrUrlLocatorTuple: UrlOrUrlLocatorTuple, conditionalHeaders: ConditionalHeaders, + layout: undefined | Layout, logger: LevelLogger ): Promise => { // If we're moving to another page in the app, we'll want to wait for the app to tell us @@ -36,7 +38,11 @@ export const openUrl = async ( } try { - await browser.open(url, { conditionalHeaders, waitForSelector, timeout, locator }, logger); + await browser.open( + url, + { conditionalHeaders, waitForSelector, timeout, locator, layout }, + logger + ); } catch (err) { logger.error(err); throw new Error(