From c5bf708c55ef2a360e1b30178bce89089009527d Mon Sep 17 00:00:00 2001 From: Maja Grubic Date: Thu, 12 Dec 2019 16:07:25 +0000 Subject: [PATCH] [Dashboard] Add visualization from dasbhoard empty screen (#52670) * [Dashboard] Add visualization from dasbhoard empty screen * Fixing linting errors * Fixing i18n error * Fixing unit test that was causing typecheck failure --- .../dashboard_empty_screen.test.tsx.snap | 74 ++- .../__tests__/dashboard_empty_screen.test.tsx | 11 + .../dashboard/dashboard_app_controller.tsx | 33 +- .../dashboard/dashboard_empty_screen.tsx | 32 +- .../dashboard_empty_screen_constants.tsx | 6 + .../__snapshots__/new_vis_modal.test.tsx.snap | 628 +++++++++++++++++- .../visualize/wizard/new_vis_modal.test.tsx | 31 + .../public/visualize/wizard/new_vis_modal.tsx | 6 +- .../embeddable/grid/_dashboard_grid.scss | 2 +- .../viewport/_dashboard_viewport.scss | 1 - .../apps/dashboard/empty_dashboard.js | 8 + .../services/dashboard/visualizations.js | 8 +- 12 files changed, 773 insertions(+), 67 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap index 8410040a0100d..4ea658bcd03ef 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap @@ -306,40 +306,56 @@ exports[`DashboardEmptyScreen renders correctly with visualize paragraph 1`] = ` className="euiSpacer euiSpacer--m" /> - -
-

- - visit the Visualize app - , - } - } +

-
+ + + + Create new + + + + +

diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx index 69bdcf59bb227..653e7d4215eef 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx @@ -47,4 +47,15 @@ describe('DashboardEmptyScreen', () => { const paragraph = findTestSubject(component, 'linkToVisualizeParagraph'); expect(paragraph.length).toBe(0); }); + + test('when specified, prop onVisualizeClick is called correctly', () => { + const onVisualizeClick = jest.fn(); + const component = mountComponent({ + ...defaultProps, + ...{ showLinkToVisualize: true, onVisualizeClick }, + }); + const button = findTestSubject(component, 'addVisualizationButton'); + button.simulate('click'); + expect(onVisualizeClick).toHaveBeenCalled(); + }); }); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx index fd49b26e0d948..d8496ebb5cdbc 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx @@ -21,7 +21,7 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import React from 'react'; import angular from 'angular'; -import { uniq, noop } from 'lodash'; +import { uniq } from 'lodash'; import { Subscription } from 'rxjs'; import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_empty_screen'; @@ -53,6 +53,7 @@ import { ErrorEmbeddable, ViewMode, openAddPanelFlyout, + EmbeddableFactoryNotFoundError, } from '../../../embeddable_api/public/np_ready/public'; import { DashboardAppState, NavAction, ConfirmModalFn, SavedDashboardPanel } from './types'; @@ -145,16 +146,20 @@ export class DashboardAppController { } $scope.showSaveQuery = dashboardCapabilities.saveQuery as boolean; - $scope.getShouldShowEditHelp = () => + const getShouldShowEditHelp = () => !dashboardStateManager.getPanels().length && dashboardStateManager.getIsEditMode() && !dashboardConfig.getHideWriteControls(); - $scope.getShouldShowViewHelp = () => + const getShouldShowViewHelp = () => !dashboardStateManager.getPanels().length && dashboardStateManager.getIsViewMode() && !dashboardConfig.getHideWriteControls(); + const addVisualization = () => { + navActions[TopNavIds.VISUALIZE](); + }; + const updateIndexPatterns = (container?: DashboardContainer) => { if (!container || isErrorEmbeddable(container)) { return; @@ -189,7 +194,7 @@ export class DashboardAppController { showLinkToVisualize: shouldShowEditHelp, }; if (shouldShowEditHelp) { - emptyScreenProps.onVisualizeClick = noop; + emptyScreenProps.onVisualizeClick = addVisualization; } return emptyScreenProps; }; @@ -205,8 +210,8 @@ export class DashboardAppController { if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) { expandedPanelId = dashboardContainer.getInput().expandedPanelId; } - const shouldShowEditHelp = $scope.getShouldShowEditHelp(); - const shouldShowViewHelp = $scope.getShouldShowViewHelp(); + const shouldShowEditHelp = getShouldShowEditHelp(); + const shouldShowViewHelp = getShouldShowViewHelp(); return { id: dashboardStateManager.savedDashboard.id || '', filters: queryFilter.getFilters(), @@ -261,8 +266,8 @@ export class DashboardAppController { dashboardContainer = container; dashboardContainer.renderEmpty = () => { - const shouldShowEditHelp = $scope.getShouldShowEditHelp(); - const shouldShowViewHelp = $scope.getShouldShowViewHelp(); + const shouldShowEditHelp = getShouldShowEditHelp(); + const shouldShowViewHelp = getShouldShowViewHelp(); const isEmptyState = shouldShowEditHelp || shouldShowViewHelp; return isEmptyState ? ( @@ -759,7 +764,17 @@ export class DashboardAppController { } }; - navActions[TopNavIds.VISUALIZE] = async () => {}; + navActions[TopNavIds.VISUALIZE] = async () => { + const type = 'visualization'; + const factory = embeddables.getEmbeddableFactory(type); + if (!factory) { + throw new EmbeddableFactoryNotFoundError(type); + } + const explicitInput = await factory.getExplicitInput(); + if (dashboardContainer) { + await dashboardContainer.addNewEmbeddable(type, explicitInput); + } + }; navActions[TopNavIds.OPTIONS] = anchorElement => { showOptionsPopover({ diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx index 234228ba4166a..2fc78d64d0a0c 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx @@ -17,7 +17,7 @@ * under the License. */ import React from 'react'; -import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; +import { I18nProvider } from '@kbn/i18n/react'; import { EuiIcon, EuiLink, @@ -26,6 +26,7 @@ import { EuiPageBody, EuiPage, EuiText, + EuiButton, } from '@elastic/eui'; import * as constants from './dashboard_empty_screen_constants'; @@ -38,23 +39,20 @@ export interface DashboardEmptyScreenProps { export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick, + onVisualizeClick, }: DashboardEmptyScreenProps) { const linkToVisualizeParagraph = ( - -

- - {constants.visualizeAppLinkTest} - - ), - }} - /> -

-
+

+ + {constants.createNewVisualizationButton} + +

); const paragraph = ( description1: string, @@ -96,7 +94,7 @@ export function DashboardEmptyScreen({ ); return ( - + diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_constants.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_constants.tsx index 0f510375aaf59..03004f6270fef 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_constants.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_constants.tsx @@ -76,3 +76,9 @@ export const visualizeAppLinkTest: string = i18n.translate( defaultMessage: 'visit the Visualize app', } ); +export const createNewVisualizationButton: string = i18n.translate( + 'kbn.dashboard.createNewVisualizationButton', + { + defaultMessage: 'Create new', + } +); diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap b/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap index 04b7cddc75289..ca6b872c73f8f 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap @@ -242,13 +242,70 @@ exports[`NewVisModal filter for visualization types should render as expected 1` aria-live="polite" class="euiScreenReaderOnly" > - 1 type found + 2 types found + + + + + Vis with alias Url + + } + onBlur={[Function]} + onClick={[Function]} + onFocus={[Function]} + onMouseEnter={[Function]} + onMouseLeave={[Function]} + role="menuitem" + > + + { + const { location } = window; const defaultVisTypeParams = { hidden: false, visualization: class Controller { @@ -51,6 +52,12 @@ describe('NewVisModal', () => { stage: 'production', ...defaultVisTypeParams, }, + { + name: 'visWithAliasUrl', + title: 'Vis with alias Url', + stage: 'production', + aliasUrl: '/aliasUrl', + }, ]; const visTypes: TypesStart = { get: (id: string) => { @@ -69,6 +76,10 @@ describe('NewVisModal', () => { jest.clearAllMocks(); }); + afterAll(() => { + window.location = location; + }); + it('should render as expected', () => { const wrapper = mountWithIntl( { visButton.simulate('click'); expect(window.location.assign).toBeCalledWith('#/visualize/create?type=vis&foo=true&bar=42'); }); + + it('closes if visualization with aliasUrl and addToDashboard in editorParams', () => { + const onClose = jest.fn(); + window.location.assign = jest.fn(); + const wrapper = mountWithIntl( + + ); + const visButton = wrapper.find('button[data-test-subj="visType-visWithAliasUrl"]'); + visButton.simulate('click'); + expect(window.location.assign).toBeCalledWith('testbasepath/aliasUrl'); + expect(onClose).toHaveBeenCalled(); + }); }); describe('filter for visualization types', () => { diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx index 0402265610fb1..e84797302589d 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx +++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx @@ -132,8 +132,10 @@ class NewVisModal extends React.Component { @@ -54,6 +56,12 @@ export default function ({ getService, getPageObjects }) { expect(isAddPanelOpen).to.be(true); }); + it('should add new visualization from dashboard', async () => { + await testSubjects.click('addVisualizationButton'); + await dashboardVisualizations.createAndAddMarkdown({ name: 'Dashboard Test Markdown', markdown: 'Markdown text' }, false); + await PageObjects.dashboard.waitForRenderComplete(); + await dashboardExpect.markdownWithValuesExists(['Markdown text']); + }); }); } diff --git a/test/functional/services/dashboard/visualizations.js b/test/functional/services/dashboard/visualizations.js index 8cde98861ca88..97433a1e4923c 100644 --- a/test/functional/services/dashboard/visualizations.js +++ b/test/functional/services/dashboard/visualizations.js @@ -73,14 +73,16 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }) { await dashboardAddPanel.addSavedSearch(name); } - async createAndAddMarkdown({ name, markdown }) { + async createAndAddMarkdown({ name, markdown }, checkForAddPanel = true) { log.debug(`createAndAddMarkdown(${markdown})`); const inViewMode = await PageObjects.dashboard.getIsInViewMode(); if (inViewMode) { await PageObjects.dashboard.switchToEditMode(); } - await dashboardAddPanel.ensureAddPanelIsShowing(); - await dashboardAddPanel.clickAddNewEmbeddableLink('visualization'); + if (checkForAddPanel) { + await dashboardAddPanel.ensureAddPanelIsShowing(); + await dashboardAddPanel.clickAddNewEmbeddableLink('visualization'); + } await PageObjects.visualize.clickMarkdownWidget(); await PageObjects.visualize.setMarkdownTxt(markdown); await PageObjects.visualize.clickGo();