Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dashboard] Sharing via link to an expanded panel #190086

Merged
merged 98 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 92 commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
6d28f6e
sharing via link to expanded panel
rshen91 Aug 7, 2024
b532740
add comment
rshen91 Aug 14, 2024
35a84ed
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 14, 2024
0e702a4
Merge branch 'main' into expandedPanelId-link
rshen91 Aug 20, 2024
318443e
wip
rshen91 Aug 20, 2024
e5850cc
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 20, 2024
74e1c64
Merge remote-tracking branch 'origin/expandedPanelId-link' into expan…
rshen91 Aug 20, 2024
40b58a2
wip
rshen91 Aug 21, 2024
62bdd9b
got it working!
rshen91 Aug 21, 2024
80e2fd2
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 21, 2024
1b2fbb0
remove unnecessary changes
rshen91 Aug 21, 2024
3e4935e
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 21, 2024
af64338
clean up
rshen91 Aug 21, 2024
924a8a3
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 21, 2024
4226427
fix
rshen91 Aug 21, 2024
bf90e88
fix time restore boolean
rshen91 Aug 21, 2024
ecc366a
more fix
rshen91 Aug 21, 2024
0348004
fix helper function
rshen91 Aug 21, 2024
c335be3
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 21, 2024
1ba7b28
order of parameters
rshen91 Aug 22, 2024
a89027c
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 22, 2024
9dca988
fix
rshen91 Aug 22, 2024
5f58b34
order of stop watching state in dashboardapp
rshen91 Aug 22, 2024
8e592f2
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 22, 2024
d197ab3
refactor to avoid race
rshen91 Aug 22, 2024
bcdf7e3
mostly working
rshen91 Aug 26, 2024
fe64ceb
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 26, 2024
e39f6e2
fix
rshen91 Aug 26, 2024
3b1ee94
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 26, 2024
98b0fb4
clean up
rshen91 Aug 26, 2024
f588023
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 26, 2024
334f7de
Merge branch 'main' into expandedPanelId-link
rshen91 Aug 26, 2024
53f19f1
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Aug 29, 2024
5277709
wip history
rshen91 Sep 3, 2024
8833219
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 3, 2024
aaad93b
pair with Hannah about history
rshen91 Sep 3, 2024
dd8f508
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 3, 2024
ffa503c
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 4, 2024
02c4e99
revert unneeded changes
rshen91 Sep 4, 2024
8c388ba
Merge remote-tracking branch 'origin/expandedPanelId-link' into expan…
rshen91 Sep 4, 2024
3292e81
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 5, 2024
83c4462
change hook type to avoid collisions with state transfer
rshen91 Sep 5, 2024
b5ff1b7
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 5, 2024
d3d86d0
code review
rshen91 Sep 5, 2024
2226362
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 5, 2024
fe839bf
order of cleanup
rshen91 Sep 5, 2024
c8cfcdd
refactor
rshen91 Sep 9, 2024
21e74d5
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 9, 2024
7bb9aea
fix
rshen91 Sep 9, 2024
697e31a
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 9, 2024
d8f4066
fix
rshen91 Sep 9, 2024
f990a26
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 9, 2024
b69d56d
code review and pairing with Hannah
rshen91 Sep 10, 2024
4929113
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 10, 2024
b560671
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 10, 2024
28591e2
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 10, 2024
547ad52
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 11, 2024
2bb66e4
wip test
rshen91 Sep 11, 2024
792f33d
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 11, 2024
36f5a70
Merge remote-tracking branch 'origin/expandedPanelId-link' into expan…
rshen91 Sep 11, 2024
ba236a4
[CI] Auto-commit changed files from 'node scripts/yarn_deduplicate'
kibanamachine Sep 11, 2024
192f089
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 12, 2024
99f575f
add test
rshen91 Sep 13, 2024
b204837
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 13, 2024
10eca46
Merge remote-tracking branch 'origin/expandedPanelId-link' into expan…
rshen91 Sep 13, 2024
b8b691a
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Sep 13, 2024
8b2ff8a
expanded panel update test
rshen91 Sep 13, 2024
49745b4
Merge remote-tracking branch 'origin/expandedPanelId-link' into expan…
rshen91 Sep 13, 2024
fe94eb8
unit tests w hannah
rshen91 Sep 13, 2024
4d66d52
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 13, 2024
3129d45
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 16, 2024
4aaee31
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 16, 2024
cc06466
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 16, 2024
65a9147
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 16, 2024
6ac5521
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 17, 2024
0a89da4
code review
rshen91 Sep 17, 2024
4234e10
code review
rshen91 Sep 17, 2024
c0bcc10
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 17, 2024
599a92e
fix initial load of expanded panel returning undefined
rshen91 Sep 17, 2024
e2e8d03
fix code review
rshen91 Sep 17, 2024
e8272d5
merge
rshen91 Sep 17, 2024
31303e6
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 17, 2024
5208cae
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 17, 2024
04c4877
Get mocks working again after conflicts
Heenawter Sep 18, 2024
5f44194
working test
rshen91 Sep 18, 2024
d6c13a2
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 18, 2024
29a9551
before all block restoration
rshen91 Sep 18, 2024
d1097d0
test refactoring
rshen91 Sep 19, 2024
76e62d4
Update src/plugins/dashboard/public/dashboard_app/dashboard_app.test.tsx
rshen91 Sep 19, 2024
2a1ac13
remove redundant spy
rshen91 Sep 19, 2024
3d18a3d
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 19, 2024
b0fb938
Merge remote-tracking branch 'origin/expandedPanelId-link' into expan…
rshen91 Sep 19, 2024
4a8130c
[CI] Auto-commit changed files from 'yarn openapi:bundle'
kibanamachine Sep 19, 2024
d5b8ae9
Merge branch 'main' into expandedPanelId-link
rshen91 Sep 19, 2024
460084b
code review feedback
rshen91 Sep 19, 2024
008ca1c
Merge remote-tracking branch 'upstream/main' into expandedPanelId-link
rshen91 Sep 19, 2024
5456f8d
Merge remote-tracking branch 'origin/expandedPanelId-link' into expan…
rshen91 Sep 19, 2024
6eed21c
pairing with hannah tests
rshen91 Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions src/plugins/dashboard/public/dashboard_app/dashboard_app.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { render, waitFor } from '@testing-library/react';
import { MemoryHistory, createMemoryHistory } from 'history';
import React, { useEffect } from 'react';
import type { DashboardRendererProps } from '../dashboard_container/external_api/dashboard_renderer';
import { buildMockDashboard } from '../mocks';
import { DashboardApp } from './dashboard_app';

import * as dashboardRendererStuff from '../dashboard_container/external_api/lazy_dashboard_renderer';
import { DashboardApi } from '..';

/* These tests circumvent the need to test the router and legacy code
/* the dashboard app will be passed the expanded panel id from the DashboardRouter through mountApp()
/* @link https://github.com/elastic/kibana/pull/190086/
*/

describe('Dashboard App', () => {
Heenawter marked this conversation as resolved.
Show resolved Hide resolved
const mockDashboard = buildMockDashboard();
let mockHistory: MemoryHistory;
let historySpy: jest.SpyInstance;
let mockDashboardApiExpandedPanel: string | undefined;
const expandPanelSpyInRouter = jest.spyOn(mockDashboard, 'expandPanel');
Heenawter marked this conversation as resolved.
Show resolved Hide resolved

beforeEach(() => {
mockHistory = createMemoryHistory();
historySpy = jest.spyOn(mockHistory, 'replace');

/**
* Mock the LazyDashboardRenderer component to avoid rendering the actual dashboard
* and hitting errors that aren't relevant
*/
jest
.spyOn(dashboardRendererStuff, 'LazyDashboardRenderer')
// we need overwrite the onApiAvailable prop to get the dashboard Api in the dashboard app
.mockImplementation(({ onApiAvailable }: DashboardRendererProps) => {
useEffect(() => {
// mock up similar to the onApiAvailable in DashboardApp
if (mockDashboardApiExpandedPanel) {
mockDashboard.expandPanel(mockDashboardApiExpandedPanel);
}
onApiAvailable?.(mockDashboard as DashboardApi);
}, [onApiAvailable]);

return <div>Test renderer</div>;
});
Heenawter marked this conversation as resolved.
Show resolved Hide resolved

// reset the spies before each test
historySpy.mockClear();
});

it('test the default behavior without an expandedPanel id passed as a prop to the DashboardApp', async () => {
render(<DashboardApp redirectTo={jest.fn()} history={mockHistory} />);

await waitFor(() => {
// this value should be undefined by default
expect(mockDashboard.expandedPanelId.getValue()).toBe(undefined);
// history should not be called
expect(historySpy).toHaveBeenCalledTimes(0);
expect(mockHistory.location.pathname).toBe('/');
});

// simulate expanding a panel
mockDashboard.expandPanel('123');

await waitFor(() => {
expect(mockDashboard.expandedPanelId.getValue()).toBe('123');
expect(historySpy).toHaveBeenCalledTimes(1);
expect(mockHistory.location.pathname).toBe('/create/123');
});
});

it('test that the expanded panel behavior subject and history is called when passed as a prop to the DashboardApp', async () => {
Heenawter marked this conversation as resolved.
Show resolved Hide resolved
render(<DashboardApp redirectTo={jest.fn()} history={mockHistory} expandedPanelId="456" />);

await waitFor(() => {
expect(expandPanelSpyInRouter).toHaveBeenCalled();
Heenawter marked this conversation as resolved.
Show resolved Hide resolved
expect(historySpy).toHaveBeenCalledTimes(0);
});

// simulate minimizing a panel
mockDashboard.expandedPanelId.next(undefined);
await waitFor(() => {
Heenawter marked this conversation as resolved.
Show resolved Hide resolved
expect(mockDashboard.expandedPanelId.getValue()).toBe(undefined);
expect(historySpy).toHaveBeenCalledTimes(1);
expect(mockHistory.location.pathname).toBe('/create');
});
});
});
19 changes: 17 additions & 2 deletions src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
DashboardAppNoDataPage,
isDashboardAppInNoDataState,
} from './no_data/dashboard_app_no_data';
import { loadAndRemoveDashboardState } from './url/url_utils';
import { loadAndRemoveDashboardState, startSyncingExpandedPanelState } from './url/url_utils';
import {
getSessionURLObservable,
getSearchSessionIdFromURL,
Expand Down Expand Up @@ -53,13 +53,15 @@ export interface DashboardAppProps {
savedDashboardId?: string;
redirectTo: DashboardRedirect;
embedSettings?: DashboardEmbedSettings;
expandedPanelId?: string;
}

export function DashboardApp({
savedDashboardId,
embedSettings,
redirectTo,
history,
expandedPanelId,
}: DashboardAppProps) {
const [showNoDataPage, setShowNoDataPage] = useState<boolean>(false);
const [regenerateId, setRegenerateId] = useState(uuidv4());
Expand Down Expand Up @@ -183,6 +185,12 @@ export function DashboardApp({
getScreenshotContext,
]);

useEffect(() => {
if (!dashboardApi) return;
const { stopWatchingExpandedPanel } = startSyncingExpandedPanelState({ dashboardApi, history });
return () => stopWatchingExpandedPanel();
}, [dashboardApi, history]);

/**
* When the dashboard container is created, or re-created, start syncing dashboard state with the URL
*/
Expand Down Expand Up @@ -221,7 +229,14 @@ export function DashboardApp({
<DashboardRenderer
key={regenerateId}
locator={locator}
onApiAvailable={setDashboardApi}
onApiAvailable={(dashboard) => {
if (dashboard && !dashboardApi) {
setDashboardApi(dashboard);
if (expandedPanelId) {
dashboard?.expandPanel(expandedPanelId);
}
}
}}
dashboardRedirect={redirectTo}
savedObjectId={savedDashboardId}
showPlainSpinner={showPlainSpinner}
Expand Down
11 changes: 9 additions & 2 deletions src/plugins/dashboard/public/dashboard_app/dashboard_router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ export async function mountApp({
};
};

const renderDashboard = (routeProps: RouteComponentProps<{ id?: string }>) => {
const renderDashboard = (
routeProps: RouteComponentProps<{ id?: string; expandedPanelId?: string }>
) => {
const routeParams = parse(routeProps.history.location.search);
if (routeParams.embed === 'true' && !globalEmbedSettings) {
globalEmbedSettings = getDashboardEmbedSettings(routeParams);
Expand All @@ -112,6 +114,7 @@ export async function mountApp({
embedSettings={globalEmbedSettings}
savedDashboardId={routeProps.match.params.id}
redirectTo={redirect}
expandedPanelId={routeProps.match.params.expandedPanelId}
/>
);
};
Expand Down Expand Up @@ -154,7 +157,11 @@ export async function mountApp({
<HashRouter>
<Routes>
<Route
path={[CREATE_NEW_DASHBOARD_URL, `${VIEW_DASHBOARD_URL}/:id`]}
path={[
CREATE_NEW_DASHBOARD_URL,
`${VIEW_DASHBOARD_URL}/:id/:expandedPanelId`,
`${VIEW_DASHBOARD_URL}/:id`,
]}
render={renderDashboard}
/>
<Route exact path={LANDING_PAGE_PATH} render={renderListingPage} />
Expand Down
27 changes: 26 additions & 1 deletion src/plugins/dashboard/public/dashboard_app/url/url_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
*/

import _ from 'lodash';
import { skip } from 'rxjs';
import semverSatisfies from 'semver/functions/satisfies';
import { History } from 'history';

import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public';
import { replaceUrlHashQuery } from '@kbn/kibana-utils-plugin/common';
Expand All @@ -21,9 +23,10 @@ import {
} from '../../../common';
import { pluginServices } from '../../services/plugin_services';
import { getPanelTooOldErrorString } from '../_dashboard_app_strings';
import { DASHBOARD_STATE_STORAGE_KEY } from '../../dashboard_constants';
import { DASHBOARD_STATE_STORAGE_KEY, createDashboardEditUrl } from '../../dashboard_constants';
import { SavedDashboardPanel } from '../../../common/content_management';
import { migrateLegacyQuery } from '../../services/dashboard_content_management/lib/load_dashboard_state';
import { DashboardApi } from '../../dashboard_api/types';

/**
* We no longer support loading panels from a version older than 7.3 in the URL.
Expand Down Expand Up @@ -84,3 +87,25 @@ export const loadAndRemoveDashboardState = (

return partialState;
};

export const startSyncingExpandedPanelState = ({
dashboardApi,
history,
}: {
dashboardApi: DashboardApi;
history: History;
}) => {
const expandedPanelSubscription = dashboardApi?.expandedPanelId
// skip the first value because we don't want to trigger a history.replace on initial load
.pipe(skip(1))
.subscribe((expandedPanelId) => {
history.replace({
...history.location,
pathname: `${createDashboardEditUrl(dashboardApi.savedObjectId.value)}${
Boolean(expandedPanelId) ? `/${expandedPanelId}` : ''
}`,
});
});
const stopWatchingExpandedPanel = () => expandedPanelSubscription.unsubscribe();
return { stopWatchingExpandedPanel };
};
12 changes: 10 additions & 2 deletions test/functional/page_objects/dashboard_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,16 @@ export class DashboardPageObject extends FtrService {
public getDashboardIdFromUrl(url: string) {
const urlSubstring = '#/view/';
const startOfIdIndex = url.indexOf(urlSubstring) + urlSubstring.length;
const endIndex = url.indexOf('?');
const id = url.substring(startOfIdIndex, endIndex < 0 ? url.length : endIndex);
const endIndexOfFilters = url.indexOf('?');
const endIndexOfMax = url.substring(startOfIdIndex).indexOf('/');
if (endIndexOfMax === -1) {
return url.substring(startOfIdIndex, endIndexOfFilters);
}
const endIndex =
endIndexOfFilters + startOfIdIndex > endIndexOfMax
? endIndexOfFilters + startOfIdIndex
: endIndexOfMax + startOfIdIndex;
const id = url.substring(startOfIdIndex, endIndex < 0 ? url.length : endIndex + startOfIdIndex);
return id;
}

Expand Down