From 0e34c3ccbc7de911862694c98f910dd223d5c27a Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Mon, 24 Apr 2023 19:51:54 -0700 Subject: [PATCH] [BUG][Dashboard listing] push to history if dashboard otherwise nav (#3922) History push will just to the current route. However, dashboardsProvider was implemented with the expectation that it was a different app. So when a plugin registered it was attempting to navigate to `app/dashboard#/app/{url}` Add tests and extra data test subject. Signed-off-by: Kawika Avilla --- .../public/application/legacy_app.js | 16 +++-- .../listing/create_button.test.tsx | 2 +- .../application/listing/create_button.tsx | 2 +- test/plugin_functional/config.ts | 1 + .../opensearch_dashboards.json | 9 +++ .../package.json | 17 +++++ .../public/index.ts | 22 ++++++ .../public/plugin.tsx | 53 ++++++++++++++ .../tsconfig.json | 17 +++++ .../dashboard_listing_plugin.ts | 71 +++++++++++++++++++ .../dashboard_listing_plugin/index.ts | 35 +++++++++ 11 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 test/plugin_functional/plugins/dashboard_listing_test_plugin/opensearch_dashboards.json create mode 100644 test/plugin_functional/plugins/dashboard_listing_test_plugin/package.json create mode 100644 test/plugin_functional/plugins/dashboard_listing_test_plugin/public/index.ts create mode 100644 test/plugin_functional/plugins/dashboard_listing_test_plugin/public/plugin.tsx create mode 100644 test/plugin_functional/plugins/dashboard_listing_test_plugin/tsconfig.json create mode 100644 test/plugin_functional/test_suites/dashboard_listing_plugin/dashboard_listing_plugin.ts create mode 100644 test/plugin_functional/test_suites/dashboard_listing_plugin/index.ts diff --git a/src/plugins/dashboard/public/application/legacy_app.js b/src/plugins/dashboard/public/application/legacy_app.js index 3ed961e54049..baacc69f7802 100644 --- a/src/plugins/dashboard/public/application/legacy_app.js +++ b/src/plugins/dashboard/public/application/legacy_app.js @@ -163,11 +163,19 @@ export function initDashboardApp(app, deps) { }; }; - $scope.editItem = ({ editUrl }) => { - history.push(editUrl); + $scope.editItem = ({ appId, editUrl }) => { + if (appId === 'dashboard') { + history.push(editUrl); + } else { + deps.core.application.navigateToUrl(editUrl); + } }; - $scope.viewItem = ({ viewUrl }) => { - history.push(deps.addBasePath(viewUrl)); + $scope.viewItem = ({ appId, viewUrl }) => { + if (appId === 'dashboard') { + history.push(viewUrl); + } else { + deps.core.application.navigateToUrl(viewUrl); + } }; $scope.delete = (dashboards) => { const ids = dashboards.map((d) => ({ id: d.id, appId: d.appId })); diff --git a/src/plugins/dashboard/public/application/listing/create_button.test.tsx b/src/plugins/dashboard/public/application/listing/create_button.test.tsx index 5d2a200f55df..9521df8590e6 100644 --- a/src/plugins/dashboard/public/application/listing/create_button.test.tsx +++ b/src/plugins/dashboard/public/application/listing/create_button.test.tsx @@ -57,7 +57,7 @@ describe('create button with props', () => { expect(createButtons.length).toBe(0); const createDropdown = findTestSubject(component, 'createMenuDropdown'); createDropdown.simulate('click'); - const contextMenus = findTestSubject(component, 'contextMenuItem'); + const contextMenus = findTestSubject(component, 'contextMenuItem-test'); expect(contextMenus.length).toBe(2); expect(contextMenus.at(0).prop('href')).toBe('test1'); }); diff --git a/src/plugins/dashboard/public/application/listing/create_button.tsx b/src/plugins/dashboard/public/application/listing/create_button.tsx index 04e6df883779..4959603fa271 100644 --- a/src/plugins/dashboard/public/application/listing/create_button.tsx +++ b/src/plugins/dashboard/public/application/listing/create_button.tsx @@ -38,7 +38,7 @@ const CreateButton = (props: CreateButtonProps) => { {provider.createLinkText} diff --git a/test/plugin_functional/config.ts b/test/plugin_functional/config.ts index e733a4e36368..ce027815a57f 100644 --- a/test/plugin_functional/config.ts +++ b/test/plugin_functional/config.ts @@ -52,6 +52,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('./test_suites/doc_views_links'), require.resolve('./test_suites/application_links'), require.resolve('./test_suites/data_plugin'), + require.resolve('./test_suites/dashboard_listing_plugin'), ], services: { ...functionalConfig.get('services'), diff --git a/test/plugin_functional/plugins/dashboard_listing_test_plugin/opensearch_dashboards.json b/test/plugin_functional/plugins/dashboard_listing_test_plugin/opensearch_dashboards.json new file mode 100644 index 000000000000..454d9ea58471 --- /dev/null +++ b/test/plugin_functional/plugins/dashboard_listing_test_plugin/opensearch_dashboards.json @@ -0,0 +1,9 @@ +{ + "id": "dashboard_listing_test_plugin", + "version": "0.0.1", + "opensearchDashboardsVersion": "opensearchDashboards", + "configPath": ["dashboard_listing_test_plugin"], + "server": false, + "ui": true, + "requiredPlugins": ["dashboard"] +} diff --git a/test/plugin_functional/plugins/dashboard_listing_test_plugin/package.json b/test/plugin_functional/plugins/dashboard_listing_test_plugin/package.json new file mode 100644 index 000000000000..0b593604a2ad --- /dev/null +++ b/test/plugin_functional/plugins/dashboard_listing_test_plugin/package.json @@ -0,0 +1,17 @@ +{ + "name": "dashboard_listing_test_plugin", + "version": "1.0.0", + "main": "target/test/plugin_functional/plugins/dashboard_listing_test_plugin", + "opensearchDashboards": { + "version": "opensearchDashboards", + "templateVersion": "1.0.0" + }, + "license": "Apache-2.0", + "scripts": { + "osd": "../../../../scripts/use_node ../../../../scripts/osd.js", + "build": "../../../../scripts/use_node ../../../../scripts/remove.js './target' && tsc" + }, + "devDependencies": { + "typescript": "4.0.2" + } +} diff --git a/test/plugin_functional/plugins/dashboard_listing_test_plugin/public/index.ts b/test/plugin_functional/plugins/dashboard_listing_test_plugin/public/index.ts new file mode 100644 index 000000000000..80ddbf8a3382 --- /dev/null +++ b/test/plugin_functional/plugins/dashboard_listing_test_plugin/public/index.ts @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { PluginInitializer } from 'opensearch-dashboards/public'; +import { + DashboardListingTestPlugin, + DashboardListingTestPluginSetup, + DashboardListingTestPluginStart, +} from './plugin'; + +export const plugin: PluginInitializer< + DashboardListingTestPluginSetup, + DashboardListingTestPluginStart +> = () => new DashboardListingTestPlugin(); diff --git a/test/plugin_functional/plugins/dashboard_listing_test_plugin/public/plugin.tsx b/test/plugin_functional/plugins/dashboard_listing_test_plugin/public/plugin.tsx new file mode 100644 index 000000000000..76a407f7c0d2 --- /dev/null +++ b/test/plugin_functional/plugins/dashboard_listing_test_plugin/public/plugin.tsx @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import * as React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { Router, Switch, Route, Link } from 'react-router-dom'; +import { CoreSetup, Plugin } from 'opensearch-dashboards/public'; + +export class DashboardListingTestPlugin + implements Plugin { + public setup(core: CoreSetup, setupDeps: SetupDependencies) { + const ID = 'dashboard_listing_test_plugin'; + const BASE_URL = core.http.basePath.prepend(`/app/${ID}#`); + setupDeps.dashboard.registerDashboardProvider({ + appId: ID, + savedObjectsType: 'dashboardTest', + savedObjectsName: 'Dashboard Test', + editUrlPathFn: (obj: SavedObject) => `${BASE_URL}/${obj.id}/edit`, + viewUrlPathFn: (obj: SavedObject) => `${BASE_URL}/${obj.id}`, + createLinkText: 'Test Dashboard', + createSortText: 'Test Dashboard', + createUrl: `${BASE_URL}/create`, + }); + + core.application.register({ + id: ID, + title: 'Dashboard Listing Test Plugin', + appRoute: `app/${ID}`, + async mount(context, { element }) { + render( +

Dashboard Listing Test Header

, + element + ); + + return () => unmountComponentAtNode(element); + }, + }); + } + + public start() {} + public stop() {} +} + +export type DashboardListingTestPluginSetup = ReturnType; +export type DashboardListingTestPluginStart = ReturnType; diff --git a/test/plugin_functional/plugins/dashboard_listing_test_plugin/tsconfig.json b/test/plugin_functional/plugins/dashboard_listing_test_plugin/tsconfig.json new file mode 100644 index 000000000000..f77a5eaffc30 --- /dev/null +++ b/test/plugin_functional/plugins/dashboard_listing_test_plugin/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target", + "skipLibCheck": true + }, + "include": [ + "index.ts", + "public/**/*.ts", + "public/**/*.tsx", + "../../../../typings/**/*", + ], + "exclude": [], + "references": [ + { "path": "../../../../src/core/tsconfig.json" } + ] +} diff --git a/test/plugin_functional/test_suites/dashboard_listing_plugin/dashboard_listing_plugin.ts b/test/plugin_functional/test_suites/dashboard_listing_plugin/dashboard_listing_plugin.ts new file mode 100644 index 000000000000..354cfac4fa87 --- /dev/null +++ b/test/plugin_functional/test_suites/dashboard_listing_plugin/dashboard_listing_plugin.ts @@ -0,0 +1,71 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import url from 'url'; +import expect from '@osd/expect'; + +const getPathWithHash = (absoluteUrl: string) => { + const parsed = url.parse(absoluteUrl); + return `${parsed.path}${parsed.hash ?? ''}`; +}; + +export default function ({ getService, getPageObjects }) { + const testSubjects = getService('testSubjects'); + const PageObjects = getPageObjects(['common', 'dashboard', 'header']); + const browser = getService('browser'); + const listingTable = getService('listingTable'); + const find = getService('find'); + + describe('dashboard listing plugin', function describeIndexTests() { + const dashboardName = 'Dashboard Test'; + + before(async () => { + await PageObjects.dashboard.initTests({ + opensearchDashboardsIndex: '../functional/fixtures/opensearch_archiver/dashboard/legacy', + }); + await PageObjects.dashboard.clickCreateDashboardPrompt(); + await PageObjects.dashboard.saveDashboard('default'); + await PageObjects.dashboard.gotoDashboardLandingPage(); + }); + + it('should be able to navigate to create a dashboard', async () => { + await testSubjects.click('createMenuDropdown'); + await testSubjects.click('contextMenuItem-dashboard'); + await PageObjects.dashboard.saveDashboard(dashboardName); + + await PageObjects.dashboard.gotoDashboardLandingPage(); + await listingTable.searchAndExpectItemsCount('dashboard', dashboardName, 1); + }); + + it('should be able to navigate to view dashboard', async () => { + await listingTable.clickItemLink('dashboard', dashboardName); + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await PageObjects.dashboard.getIsInViewMode(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + }); + + it('should be able to navigate to edit dashboard', async () => { + await listingTable.searchForItemWithName(dashboardName); + const editBttn = await find.allByCssSelector('.euiToolTipAnchor'); + await editBttn[0].click(); + await PageObjects.dashboard.clickCancelOutOfEditMode(); + await PageObjects.dashboard.gotoDashboardLandingPage(); + }); + + it('should be able to navigate to create a test dashboard', async () => { + await testSubjects.click('createMenuDropdown'); + await testSubjects.click('contextMenuItem-dashboard_listing_test_plugin'); + expect(getPathWithHash(await browser.getCurrentUrl())).to.eql( + '/app/dashboard_listing_test_plugin#/create' + ); + }); + }); +} diff --git a/test/plugin_functional/test_suites/dashboard_listing_plugin/index.ts b/test/plugin_functional/test_suites/dashboard_listing_plugin/index.ts new file mode 100644 index 000000000000..a84790824f64 --- /dev/null +++ b/test/plugin_functional/test_suites/dashboard_listing_plugin/index.ts @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export default function ({ getService, loadTestFile }) { + const browser = getService('browser'); + const opensearchArchiver = getService('opensearchArchiver'); + + async function loadLogstash() { + await browser.setWindowSize(1200, 900); + await opensearchArchiver.loadIfNeeded( + '../functional/fixtures/opensearch_archiver/logstash_functional' + ); + } + + async function unloadLogstash() { + await opensearchArchiver.unload( + '../functional/fixtures/opensearch_archiver/logstash_functional' + ); + } + + describe('dashboard listing plugin', () => { + before(loadLogstash); + after(unloadLogstash); + + loadTestFile(require.resolve('./dashboard_listing_plugin')); + }); +}