diff --git a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap
new file mode 100644
index 000000000000..d433fdd10b52
--- /dev/null
+++ b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap
@@ -0,0 +1,5400 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`dashboard listing hideWriteControls 1`] = `
+
+
+
+
+
+
+
+
+ }
+ />
+ }
+ tableColumns={
+ Array [
+ Object {
+ "field": "title",
+ "name": "Title",
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "type",
+ "name": "Type",
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "description",
+ "name": "Description",
+ "sortable": true,
+ },
+ Object {
+ "data-test-subj": "updated-at",
+ "dataType": "date",
+ "description": "Last update of the saved object",
+ "field": "updated_at",
+ "name": "Last updated",
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ tableListTitle="Dashboards"
+ toastNotifications={
+ Object {
+ "add": [MockFunction],
+ "addDanger": [MockFunction],
+ "addError": [MockFunction],
+ "addInfo": [MockFunction],
+ "addSuccess": [MockFunction],
+ "addWarning": [MockFunction],
+ "get$": [MockFunction],
+ "remove": [MockFunction],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`dashboard listing render table listing with initial filters from URL 1`] = `
+
+
+
+
+
+
+ }
+ createItem={[Function]}
+ deleteItems={[Function]}
+ editItem={[Function]}
+ entityName="dashboard"
+ entityNamePlural="dashboards"
+ findItems={[Function]}
+ headingId="dashboardListingHeading"
+ initialFilter="dashboard"
+ initialPageSize={10}
+ listingLimit={100}
+ noItemsFragment={
+
+
+
+ }
+ body={
+
+
+
+
+
+
+
+ ,
+ }
+ }
+ />
+
+
+ }
+ iconType="dashboardApp"
+ title={
+
+
+
+ }
+ />
+ }
+ tableColumns={
+ Array [
+ Object {
+ "field": "title",
+ "name": "Title",
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "type",
+ "name": "Type",
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "description",
+ "name": "Description",
+ "sortable": true,
+ },
+ Object {
+ "data-test-subj": "updated-at",
+ "dataType": "date",
+ "description": "Last update of the saved object",
+ "field": "updated_at",
+ "name": "Last updated",
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ tableListTitle="Dashboards"
+ toastNotifications={
+ Object {
+ "add": [MockFunction],
+ "addDanger": [MockFunction],
+ "addError": [MockFunction],
+ "addInfo": [MockFunction],
+ "addSuccess": [MockFunction],
+ "addWarning": [MockFunction],
+ "get$": [MockFunction],
+ "remove": [MockFunction],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`dashboard listing renders call to action when no dashboards exist 1`] = `
+
+
+
+
+
+
+ }
+ createItem={[Function]}
+ deleteItems={[Function]}
+ editItem={[Function]}
+ entityName="dashboard"
+ entityNamePlural="dashboards"
+ findItems={[Function]}
+ headingId="dashboardListingHeading"
+ initialFilter=""
+ initialPageSize={10}
+ listingLimit={100}
+ noItemsFragment={
+
+
+
+ }
+ body={
+
+
+
+
+
+
+
+ ,
+ }
+ }
+ />
+
+
+ }
+ iconType="dashboardApp"
+ title={
+
+
+
+ }
+ />
+ }
+ tableColumns={
+ Array [
+ Object {
+ "field": "title",
+ "name": "Title",
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "type",
+ "name": "Type",
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "description",
+ "name": "Description",
+ "sortable": true,
+ },
+ Object {
+ "data-test-subj": "updated-at",
+ "dataType": "date",
+ "description": "Last update of the saved object",
+ "field": "updated_at",
+ "name": "Last updated",
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ tableListTitle="Dashboards"
+ toastNotifications={
+ Object {
+ "add": [MockFunction],
+ "addDanger": [MockFunction],
+ "addError": [MockFunction],
+ "addInfo": [MockFunction],
+ "addSuccess": [MockFunction],
+ "addWarning": [MockFunction],
+ "get$": [MockFunction],
+ "remove": [MockFunction],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`dashboard listing renders table rows 1`] = `
+
+
+
+
+
+
+ }
+ createItem={[Function]}
+ deleteItems={[Function]}
+ editItem={[Function]}
+ entityName="dashboard"
+ entityNamePlural="dashboards"
+ findItems={[Function]}
+ headingId="dashboardListingHeading"
+ initialFilter=""
+ initialPageSize={10}
+ listingLimit={100}
+ noItemsFragment={
+
+
+
+ }
+ body={
+
+
+
+
+
+
+
+ ,
+ }
+ }
+ />
+
+
+ }
+ iconType="dashboardApp"
+ title={
+
+
+
+ }
+ />
+ }
+ tableColumns={
+ Array [
+ Object {
+ "field": "title",
+ "name": "Title",
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "type",
+ "name": "Type",
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "description",
+ "name": "Description",
+ "sortable": true,
+ },
+ Object {
+ "data-test-subj": "updated-at",
+ "dataType": "date",
+ "description": "Last update of the saved object",
+ "field": "updated_at",
+ "name": "Last updated",
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ tableListTitle="Dashboards"
+ toastNotifications={
+ Object {
+ "add": [MockFunction],
+ "addDanger": [MockFunction],
+ "addError": [MockFunction],
+ "addInfo": [MockFunction],
+ "addSuccess": [MockFunction],
+ "addWarning": [MockFunction],
+ "get$": [MockFunction],
+ "remove": [MockFunction],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`dashboard listing renders warning when listingLimit is exceeded 1`] = `
+
+
+
+
+
+
+ }
+ createItem={[Function]}
+ deleteItems={[Function]}
+ editItem={[Function]}
+ entityName="dashboard"
+ entityNamePlural="dashboards"
+ findItems={[Function]}
+ headingId="dashboardListingHeading"
+ initialFilter=""
+ initialPageSize={10}
+ listingLimit={1}
+ noItemsFragment={
+
+
+
+ }
+ body={
+
+
+
+
+
+
+
+ ,
+ }
+ }
+ />
+
+
+ }
+ iconType="dashboardApp"
+ title={
+
+
+
+ }
+ />
+ }
+ tableColumns={
+ Array [
+ Object {
+ "field": "title",
+ "name": "Title",
+ "render": [Function],
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "type",
+ "name": "Type",
+ "sortable": true,
+ },
+ Object {
+ "dataType": "string",
+ "field": "description",
+ "name": "Description",
+ "sortable": true,
+ },
+ Object {
+ "data-test-subj": "updated-at",
+ "dataType": "date",
+ "description": "Last update of the saved object",
+ "field": "updated_at",
+ "name": "Last updated",
+ "render": [Function],
+ "sortable": true,
+ },
+ ]
+ }
+ tableListTitle="Dashboards"
+ toastNotifications={
+ Object {
+ "add": [MockFunction],
+ "addDanger": [MockFunction],
+ "addError": [MockFunction],
+ "addInfo": [MockFunction],
+ "addSuccess": [MockFunction],
+ "addWarning": [MockFunction],
+ "get$": [MockFunction],
+ "remove": [MockFunction],
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/src/plugins/dashboard/public/application/components/dashboard_listing/dashboard_listing.test.tsx b/src/plugins/dashboard/public/application/components/dashboard_listing/dashboard_listing.test.tsx
index 3d9c8404be5e..edbd0298876b 100644
--- a/src/plugins/dashboard/public/application/components/dashboard_listing/dashboard_listing.test.tsx
+++ b/src/plugins/dashboard/public/application/components/dashboard_listing/dashboard_listing.test.tsx
@@ -9,28 +9,6 @@
* GitHub history for details.
*/
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// TODO:
-// Rewrite the dashboard listing tests for the new component
-// https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4051
jest.mock(
'lodash',
() => ({
@@ -46,63 +24,85 @@ jest.mock(
{ virtual: true }
);
+let mockURLsearch =
+ '?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))';
+
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useLocation: () => ({
+ search: mockURLsearch,
+ pathname: '',
+ hash: '',
+ state: undefined,
+ }),
+}));
+
import React from 'react';
-import { shallow } from 'enzyme';
+import { mount } from 'enzyme';
import { DashboardListing } from './dashboard_listing';
-
-const find = (num: number) => {
- const hits = [];
- for (let i = 0; i < num; i++) {
- hits.push({
- id: `dashboard${i}`,
- title: `dashboard${i} title`,
- description: `dashboard${i} desc`,
- });
- }
- return Promise.resolve({
- total: num,
- hits,
- });
-};
-
-test.skip('renders empty page in before initial fetch to avoid flickering', () => {
- const component = shallow(
- {}}
- createItem={() => {}}
- editItem={() => {}}
- viewItem={() => {}}
- dashboardItemCreatorClickHandler={() => {}}
- dashboardItemCreators={() => []}
- initialPageSize={10}
- listingLimit={1000}
- hideWriteControls={false}
- core={{ notifications: { toasts: {} }, uiSettings: { get: jest.fn(() => 10) } }}
- />
+import { createDashboardServicesMock } from '../../utils/mocks';
+import { OpenSearchDashboardsContextProvider } from 'src/plugins/opensearch_dashboards_react/public';
+import { I18nProvider } from '@osd/i18n/react';
+import { IOsdUrlStateStorage } from 'src/plugins/opensearch_dashboards_utils/public';
+
+function wrapDashboardListingInContext(mockServices: any) {
+ const osdUrlStateStorage = ({
+ set: jest.fn(),
+ get: jest.fn(() => ({ linked: false })),
+ flush: jest.fn(),
+ } as unknown) as IOsdUrlStateStorage;
+ const services = {
+ ...mockServices,
+ osdUrlStateStorage,
+ dashboardProviders: () => {
+ return {
+ dashboard: {
+ appId: '1',
+ savedObjectsName: 'dashboardSavedObjects',
+ viewUrlPathFn: jest.fn(),
+ editUrlPathFn: jest.fn(),
+ },
+ };
+ },
+ };
+
+ return (
+
+
+
+
+
);
- expect(component).toMatchSnapshot();
-});
+}
+
+describe('dashboard listing', () => {
+ let mockServices: any;
+
+ beforeEach(() => {
+ mockServices = createDashboardServicesMock();
+ mockServices.savedObjectsClient.find = () => {
+ const hits: any[] = [];
+ for (let i = 0; i < 2; i++) {
+ hits.push({
+ type: `dashboard`,
+ id: `dashboard${i}`,
+ attributes: {
+ title: `dashboard${i}`,
+ description: `dashboard${i} desc`,
+ },
+ });
+ }
+ return Promise.resolve({
+ savedObjects: hits,
+ });
+ };
+ mockServices.dashboardConfig.getHideWriteControls = () => false;
+ mockServices.savedObjectsPublic.settings.getListingLimit = () => 100;
+ });
-describe.skip('after fetch', () => {
- test('initialFilter', async () => {
- const component = shallow(
- {}}
- createItem={() => {}}
- editItem={() => {}}
- viewItem={() => {}}
- dashboardItemCreatorClickHandler={() => {}}
- dashboardItemCreators={() => []}
- listingLimit={1000}
- hideWriteControls={false}
- initialPageSize={10}
- initialFilter="my dashboard"
- core={{ notifications: { toasts: {} }, uiSettings: { get: jest.fn(() => 10) } }}
- />
- );
+ test('renders table rows', async () => {
+ const component = mount(wrapDashboardListingInContext(mockServices));
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
@@ -112,22 +112,16 @@ describe.skip('after fetch', () => {
expect(component).toMatchSnapshot();
});
- test('renders table rows', async () => {
- const component = shallow(
- {}}
- createItem={() => {}}
- editItem={() => {}}
- viewItem={() => {}}
- dashboardItemCreatorClickHandler={() => {}}
- dashboardItemCreators={() => []}
- listingLimit={1000}
- initialPageSize={10}
- hideWriteControls={false}
- core={{ notifications: { toasts: {} }, uiSettings: { get: jest.fn(() => 10) } }}
- />
- );
+ test('renders call to action when no dashboards exist', async () => {
+ // savedObjectsClient.find() needs to find no dashboard
+ mockServices.savedObjectsClient.find = () => {
+ const hits: any[] = [];
+ return Promise.resolve({
+ total: 0,
+ hits,
+ });
+ };
+ const component = mount(wrapDashboardListingInContext(mockServices));
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
@@ -137,22 +131,12 @@ describe.skip('after fetch', () => {
expect(component).toMatchSnapshot();
});
- test('renders call to action when no dashboards exist', async () => {
- const component = shallow(
- {}}
- createItem={() => {}}
- editItem={() => {}}
- viewItem={() => {}}
- dashboardItemCreatorClickHandler={() => {}}
- dashboardItemCreators={() => []}
- listingLimit={1}
- initialPageSize={10}
- hideWriteControls={false}
- core={{ notifications: { toasts: {} }, uiSettings: { get: jest.fn(() => 10) } }}
- />
- );
+ test('hideWriteControls', async () => {
+ // dashboardConfig.getHideWriteControls() to true
+ mockServices.dashboardConfig.getHideWriteControls = () => {
+ return true;
+ };
+ const component = mount(wrapDashboardListingInContext(mockServices));
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
@@ -162,22 +146,10 @@ describe.skip('after fetch', () => {
expect(component).toMatchSnapshot();
});
- test('hideWriteControls', async () => {
- const component = shallow(
- {}}
- createItem={() => {}}
- editItem={() => {}}
- viewItem={() => {}}
- dashboardItemCreatorClickHandler={() => {}}
- dashboardItemCreators={() => []}
- listingLimit={1}
- initialPageSize={10}
- hideWriteControls={true}
- core={{ notifications: { toasts: {} }, uiSettings: { get: jest.fn(() => 10) } }}
- />
- );
+ test('renders warning when listingLimit is exceeded', async () => {
+ mockServices.savedObjectsPublic.settings.getListingLimit = () => 1;
+
+ const component = mount(wrapDashboardListingInContext(mockServices));
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
@@ -187,22 +159,11 @@ describe.skip('after fetch', () => {
expect(component).toMatchSnapshot();
});
- test('renders warning when listingLimit is exceeded', async () => {
- const component = shallow(
- {}}
- createItem={() => {}}
- editItem={() => {}}
- viewItem={() => {}}
- dashboardItemCreatorClickHandler={() => {}}
- dashboardItemCreators={() => []}
- listingLimit={1}
- initialPageSize={10}
- hideWriteControls={false}
- core={{ notifications: { toasts: {} }, uiSettings: { get: jest.fn(() => 10) } }}
- />
- );
+ test('render table listing with initial filters from URL', async () => {
+ mockURLsearch =
+ '?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&filter=dashboard';
+
+ const component = mount(wrapDashboardListingInContext(mockServices));
// Ensure all promises resolve
await new Promise((resolve) => process.nextTick(resolve));
diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap
new file mode 100644
index 000000000000..14247831d6fa
--- /dev/null
+++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap
@@ -0,0 +1,5136 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Dashboard top nav render in embed mode 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Dashboard top nav render in embed mode, components can be forced show by appending URL param 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Dashboard top nav render in full screen mode with appended URL param but none of the componenets can be forced show 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Dashboard top nav render in full screen mode, no componenets should be shown 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Dashboard top nav render with all components 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/dashboard_top_nav.test.tsx b/src/plugins/dashboard/public/application/components/dashboard_top_nav/dashboard_top_nav.test.tsx
new file mode 100644
index 000000000000..3dafdf447d45
--- /dev/null
+++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/dashboard_top_nav.test.tsx
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+jest.mock(
+ 'lodash',
+ () => ({
+ ...jest.requireActual('lodash'),
+ // mock debounce to fire immediately with no internal timer
+ debounce: (func: any) => {
+ function debounced(this: any, ...args: any[]) {
+ return func.apply(this, args);
+ }
+ return debounced;
+ },
+ }),
+ { virtual: true }
+);
+
+import { I18nProvider } from '@osd/i18n/react';
+import { OpenSearchDashboardsContextProvider } from 'src/plugins/opensearch_dashboards_react/public';
+import { DashboardTopNav } from './dashboard_top_nav';
+import React from 'react';
+import { DashboardAppState, DashboardAppStateContainer } from '../../../types';
+import { Dashboard } from '../../../dashboard';
+import { DashboardContainer } from '../../embeddable';
+import { createDashboardServicesMock } from '../../utils/mocks';
+import { mount } from 'enzyme';
+import { TopNavMenu } from 'src/plugins/navigation/public';
+import { dashboardAppStateStub } from '../../utils/stubs';
+
+let mockURL = '?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))';
+
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useLocation: () => ({
+ search: mockURL,
+ pathname: '',
+ hash: '',
+ state: undefined,
+ }),
+}));
+
+function wrapDashboardTopNavInContext(mockServices: any, currentState: DashboardAppState) {
+ const services = {
+ ...mockServices,
+ dashboardCapabilities: {
+ saveQuery: true,
+ },
+ navigation: {
+ ui: { TopNavMenu },
+ },
+ };
+
+ const topNavProps = {
+ isChromeVisible: false,
+ savedDashboardInstance: {},
+ appState: {
+ getState: () => currentState,
+ } as DashboardAppStateContainer,
+ dashboard: {} as Dashboard,
+ currentAppState: currentState,
+ isEmbeddableRendered: true,
+ currentContainer: {} as DashboardContainer,
+ indexPatterns: [],
+ dashboardIdFromUrl: '',
+ };
+
+ return (
+
+
+
+
+
+ );
+}
+
+describe('Dashboard top nav', () => {
+ let mockServices: any;
+ let currentState: DashboardAppState;
+
+ beforeEach(() => {
+ mockServices = createDashboardServicesMock();
+ currentState = dashboardAppStateStub;
+ });
+
+ test('render with all components', async () => {
+ const component = mount(wrapDashboardTopNavInContext(mockServices, currentState));
+
+ // Ensure all promises resolve
+ await new Promise((resolve) => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('render in full screen mode, no componenets should be shown', async () => {
+ currentState.fullScreenMode = true;
+ const component = mount(wrapDashboardTopNavInContext(mockServices, currentState));
+
+ // Ensure all promises resolve
+ await new Promise((resolve) => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('render in full screen mode with appended URL param but none of the componenets can be forced show', async () => {
+ currentState.fullScreenMode = true;
+ mockURL =
+ '?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&show-time-filter=true';
+ const component = mount(wrapDashboardTopNavInContext(mockServices, currentState));
+
+ // Ensure all promises resolve
+ await new Promise((resolve) => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('render in embed mode', async () => {
+ mockURL =
+ '?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&embed=true';
+ const component = mount(wrapDashboardTopNavInContext(mockServices, currentState));
+
+ // Ensure all promises resolve
+ await new Promise((resolve) => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('render in embed mode, components can be forced show by appending URL param', async () => {
+ mockURL =
+ '?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&embed=true&show-time-filter=true';
+ const component = mount(wrapDashboardTopNavInContext(mockServices, currentState));
+
+ // Ensure all promises resolve
+ await new Promise((resolve) => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('render in embed mode, and force hide filter bar', async () => {
+ mockURL =
+ '?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&embed=true&hide-filter-bar=true';
+ const component = mount(wrapDashboardTopNavInContext(mockServices, currentState));
+
+ // Ensure all promises resolve
+ await new Promise((resolve) => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ expect(component).toMatchSnapshot();
+ });
+});
diff --git a/src/plugins/dashboard/public/application/utils/mocks.ts b/src/plugins/dashboard/public/application/utils/mocks.ts
index 9c2dfc30a184..84720b0bcbc4 100644
--- a/src/plugins/dashboard/public/application/utils/mocks.ts
+++ b/src/plugins/dashboard/public/application/utils/mocks.ts
@@ -34,5 +34,14 @@ export const createDashboardServicesMock = () => {
opensearchDashboardsVersion,
usageCollection,
embeddable,
+ savedObjectsClient: {
+ find: jest.fn(),
+ },
+ savedObjectsPublic: {
+ settings: {
+ getPerPage: () => 10,
+ getListingLimit: jest.fn(),
+ },
+ },
} as unknown) as jest.Mocked;
};
diff --git a/src/plugins/dashboard/public/application/utils/use/use_dashboard_app_state.test.ts b/src/plugins/dashboard/public/application/utils/use/use_dashboard_app_state.test.ts
index 1d2c661876e2..f1a83cf4d8a7 100644
--- a/src/plugins/dashboard/public/application/utils/use/use_dashboard_app_state.test.ts
+++ b/src/plugins/dashboard/public/application/utils/use/use_dashboard_app_state.test.ts
@@ -87,7 +87,7 @@ describe('useDashboardAppAndGlobalState', () => {
expect(createDashboardGlobalAndAppState).toHaveBeenCalledWith({
services: mockServices,
stateDefaults: dashboardAppStateStub,
- osdUrlStateStorage: undefined,
+ osdUrlStateStorage: mockServices.osdUrlStateStorage,
savedDashboardInstance,
});
expect(mockServices.data.query.filterManager.setAppFilters).toHaveBeenCalledWith(
diff --git a/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts b/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts
index 47c5b44fe7e5..7cc0a46b2a55 100644
--- a/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts
+++ b/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts
@@ -146,6 +146,18 @@ export const useSavedDashboardInstance = ({
return;
}
+ /*
+ * The else if block prevents error when user clicks on one dashboard,
+ * and before it loads the next screen, user clicks a different dashboard right after.
+ * In this situation, there can be two useSavedDashboardInstance() executing, one shortly after another.
+ * The first running instance might already set the dashboardId before the second running instance
+ * execute the following if else block.
+ * The second running will go into the else if block because dashboardId
+ * is already set but it is a different value than dashboardIdFromUrl and savedDashboardInstance?.savedDashboard?.id.
+ * Therefore, to avoid errors and to actually load the second dashboard correctly,
+ * we need to reset the state by calling setSavedDashboardInstance({})
+ * and then called getSavedDashboardInstance() again using the current dashboardIdFromUrl value.
+ */
if (!dashboardId.current) {
dashboardId.current = dashboardIdFromUrl || 'new';
getSavedDashboardInstance();