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

[Reporting/Dashboard] Update integration to use v2 reports #108553

Merged
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
40ab51f
very wip, updating dashboard integration to use v2 reports. at the mo…
jloleysens Aug 13, 2021
56985bd
Merge branch 'master' into dashboard/update-report-to-use-v2
kibanamachine Aug 16, 2021
47ec77a
added missing dependency to hook
jloleysens Aug 16, 2021
1cb0766
added tests and refined ForwadedAppState interface
jloleysens Aug 16, 2021
adee42b
remove unused import
jloleysens Aug 16, 2021
3a93a16
updated test because generating a report from an unsaved report is po…
jloleysens Aug 17, 2021
9eacc30
migrated locator to forward state on history only, reordered methods …
jloleysens Aug 17, 2021
06ef623
remove unused import
jloleysens Aug 17, 2021
6cd42ba
update locator test and use panel index number if panelIndex does not…
jloleysens Aug 17, 2021
99b7479
ensure locator params are serializable
jloleysens Aug 17, 2021
db13ecd
- moved getSerializableRecord to locator.ts to ensure that the
jloleysens Aug 18, 2021
7c4260c
Merge branch 'master' into dashboard/update-report-to-use-v2
kibanamachine Aug 18, 2021
27d86a7
update generated api docs
jloleysens Aug 18, 2021
c9d09e7
remove unused variable
jloleysens Aug 18, 2021
8261f76
Merge branch 'master' into dashboard/update-report-to-use-v2
kibanamachine Aug 19, 2021
a002d5c
- removed SerializedRecord extension from dashboard locator params
jloleysens Aug 19, 2021
6116fc3
updated locator jest tests and SerializableRecord types
jloleysens Aug 19, 2021
f69d78f
explicitly map values to dashboardlocatorparams and export serializab…
jloleysens Aug 19, 2021
e3e7f7e
use serializable params type in embeddable
jloleysens Aug 19, 2021
9d97c06
Merge branch 'master' into dashboard/update-report-to-use-v2
kibanamachine Aug 20, 2021
566851e
Merge branch 'master' into dashboard/update-report-to-use-v2
kibanamachine Aug 23, 2021
d302131
factored out logic for converting panels to dashboard panels map
jloleysens Aug 23, 2021
84cbc7b
use "type =" instead of "interface"
jloleysens Aug 23, 2021
c3a8f4f
big update to locator params: type fixes and added options key
jloleysens Aug 23, 2021
4f2b82d
Merge branch 'master' into dashboard/update-report-to-use-v2
kibanamachine Aug 24, 2021
2ad676a
Merge branch 'master' into dashboard/update-report-to-use-v2
kibanamachine Aug 25, 2021
cb39ce9
added comment about why we are using "type" alias instead of "interfa…
jloleysens Aug 25, 2021
30978d9
simplify is v2 job param check
jloleysens Aug 25, 2021
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
Prev Previous commit
Next Next commit
update locator test and use panel index number if panelIndex does not…
… exist
jloleysens committed Aug 17, 2021

Verified

This commit was signed with the committer’s verified signature.
jloleysens Jean-Louis Leysens
commit 6cd42ba62842f01a47ed75b06e44b5f6cf0bb8fa
333 changes: 172 additions & 161 deletions src/plugins/dashboard/public/locator.test.ts
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ describe('dashboard locator', () => {
hashedItemStore.storage = mockStorage;
});

test('creates a link to a saved dashboard', async () => {
test('creates a link to an unsaved dashboard', async () => {
const definition = new DashboardAppLocatorDefinition({
useHashedUrl: false,
getDashboardFilterFields: async (dashboardId: string) => [],
@@ -26,7 +26,7 @@ describe('dashboard locator', () => {

expect(location).toMatchObject({
app: 'dashboards',
path: '#/create?_a=()&_g=()',
path: '#/create?_g=()',
state: {},
});
});
@@ -42,8 +42,14 @@ describe('dashboard locator', () => {

expect(location).toMatchObject({
app: 'dashboards',
path: '#/create?_a=()&_g=(time:(from:now-15m,mode:relative,to:now))',
state: {},
path: '#/create?_g=(time:(from:now-15m,mode:relative,to:now))',
state: {
timeRange: {
from: 'now-15m',
mode: 'relative',
to: 'now',
},
},
});
});

@@ -82,8 +88,48 @@ describe('dashboard locator', () => {

expect(location).toMatchObject({
app: 'dashboards',
path: `#/view/123?_a=(filters:!((meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),query:(language:kuery,query:bye))&_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),refreshInterval:(pause:!f,value:300),time:(from:now-15m,mode:relative,to:now))`,
state: {},
path: `#/view/123?_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),refreshInterval:(pause:!f,value:300),time:(from:now-15m,mode:relative,to:now))`,
state: {
dashboardId: '123',
filters: [
{
meta: {
alias: null,
disabled: false,
negate: false,
},
query: {
query: 'hi',
},
},
{
$state: {
store: 'globalState',
},
meta: {
alias: null,
disabled: false,
negate: false,
},
query: {
query: 'hi',
},
},
],
query: {
language: 'kuery',
query: 'bye',
},
refreshInterval: {
pause: false,
value: 300,
},
timeRange: {
from: 'now-15m',
mode: 'relative',
to: 'now',
},
},
});
});

@@ -103,8 +149,25 @@ describe('dashboard locator', () => {

expect(location).toMatchObject({
app: 'dashboards',
path: `#/view/123?_a=(filters:!(),query:(language:kuery,query:bye))&_g=(filters:!(),refreshInterval:(pause:!f,value:300),time:(from:now-15m,mode:relative,to:now))&searchSessionId=__sessionSearchId__`,
state: {},
path: `#/view/123?_g=(filters:!(),refreshInterval:(pause:!f,value:300),time:(from:now-15m,mode:relative,to:now))&searchSessionId=__sessionSearchId__`,
state: {
dashboardId: '123',
filters: [],
query: {
language: 'kuery',
query: 'bye',
},
refreshInterval: {
pause: false,
value: 300,
},
searchSessionId: '__sessionSearchId__',
timeRange: {
from: 'now-15m',
mode: 'relative',
to: 'now',
},
},
});
});

@@ -119,10 +182,11 @@ describe('dashboard locator', () => {

expect(location).toMatchObject({
app: 'dashboards',
path: `#/create?_a=(savedQuery:__savedQueryId__)&_g=()`,
state: {},
path: `#/create?_g=()`,
state: {
savedQuery: '__savedQueryId__',
},
});
expect(location.path).toContain('__savedQueryId__');
});

test('panels', async () => {
@@ -136,8 +200,19 @@ describe('dashboard locator', () => {

expect(location).toMatchObject({
app: 'dashboards',
path: `#/create?_a=(panels:!((fakePanelContent:fakePanelContent)))&_g=()`,
state: {},
path: `#/create?_g=()`,
state: {
panels: {
'0': {
explicitInput: {
id: undefined,
},
gridData: undefined,
panelRefName: undefined,
type: undefined,
},
},
},
});
});

@@ -224,16 +299,64 @@ describe('dashboard locator', () => {
filters: [appliedFilter],
});

expect(location1.path).toEqual(expect.stringContaining('query:savedfilter1'));
expect(location1.path).toEqual(expect.stringContaining('query:appliedfilter'));
expect(location1.path).toMatchInlineSnapshot(`"#/view/dashboard1?_g=(filters:!())"`);
expect(location1.state).toMatchObject({
dashboardId: 'dashboard1',
filters: [
{
meta: {
alias: null,
disabled: false,
negate: false,
},
query: {
query: 'savedfilter1',
},
},
{
meta: {
alias: null,
disabled: false,
negate: false,
},
query: {
query: 'appliedfilter',
},
},
],
});

const location2 = await definition.getLocation({
dashboardId: 'dashboard2',
filters: [appliedFilter],
});

expect(location2.path).toEqual(expect.stringContaining('query:savedfilter2'));
expect(location2.path).toEqual(expect.stringContaining('query:appliedfilter'));
expect(location2.path).toMatchInlineSnapshot(`"#/view/dashboard2?_g=(filters:!())"`);
expect(location2.state).toMatchObject({
dashboardId: 'dashboard2',
filters: [
{
meta: {
alias: null,
disabled: false,
negate: false,
},
query: {
query: 'savedfilter2',
},
},
{
meta: {
alias: null,
disabled: false,
negate: false,
},
query: {
query: 'appliedfilter',
},
},
],
});
});

test("doesn't fail if can't retrieve filters from destination dashboard", async () => {
@@ -252,8 +375,22 @@ describe('dashboard locator', () => {
filters: [appliedFilter],
});

expect(location.path).not.toEqual(expect.stringContaining('query:savedfilter1'));
expect(location.path).toEqual(expect.stringContaining('query:appliedfilter'));
expect(location.path).toMatchInlineSnapshot(`"#/view/dashboard1?_g=(filters:!())"`);
expect(location.state).toMatchObject({
dashboardId: 'dashboard1',
filters: [
{
meta: {
alias: null,
disabled: false,
negate: false,
},
query: {
query: 'appliedfilter',
},
},
],
});
});

test('can enforce empty filters', async () => {
@@ -273,11 +410,12 @@ describe('dashboard locator', () => {
preserveSavedFilters: false,
});

expect(location.path).not.toEqual(expect.stringContaining('query:savedfilter1'));
expect(location.path).not.toEqual(expect.stringContaining('query:appliedfilter'));
expect(location.path).toMatchInlineSnapshot(
`"#/view/dashboard1?_a=(filters:!())&_g=(filters:!())"`
);
expect(location.path).toMatchInlineSnapshot(`"#/view/dashboard1?_g=(filters:!())"`);
expect(location.state).toMatchObject({
dashboardId: 'dashboard1',
filters: [],
preserveSavedFilters: false,
});
});

test('no filters in result url if no filters applied', async () => {
@@ -295,8 +433,10 @@ describe('dashboard locator', () => {
dashboardId: 'dashboard1',
});

expect(location.path).not.toEqual(expect.stringContaining('filters'));
expect(location.path).toMatchInlineSnapshot(`"#/view/dashboard1?_a=()&_g=()"`);
expect(location.path).toMatchInlineSnapshot(`"#/view/dashboard1?_g=()"`);
expect(location.state).toMatchObject({
dashboardId: 'dashboard1',
});
});

test('can turn off preserving filters', async () => {
@@ -316,151 +456,22 @@ describe('dashboard locator', () => {
preserveSavedFilters: false,
});

expect(location.path).not.toEqual(expect.stringContaining('query:savedfilter1'));
expect(location.path).toEqual(expect.stringContaining('query:appliedfilter'));
});
});

describe('forwarding app state on history.location.state', () => {
test('creates a link with query and filters', async () => {
const definition = new DashboardAppLocatorDefinition({
useHashedUrl: false,
getDashboardFilterFields: async (dashboardId: string) => [],
});
const location = await definition.getLocation({
useHash: false,
forwardStateToHistory: true,
timeRange: { to: 'now', from: 'now-15m', mode: 'relative' },
refreshInterval: { pause: false, value: 300 },
dashboardId: '123',
expect(location.path).toMatchInlineSnapshot(`"#/view/dashboard1?_g=(filters:!())"`);
expect(location.state).toMatchObject({
dashboardId: 'dashboard1',
filters: [
{
meta: {
alias: null,
disabled: false,
negate: false,
},
query: { query: 'hi' },
},
{
meta: {
alias: null,
disabled: false,
negate: false,
},
query: { query: 'hi' },
$state: {
store: esFilters.FilterStateStore.GLOBAL_STATE,
query: {
query: 'appliedfilter',
},
},
],
query: { query: 'bye', language: 'kuery' },
panels: [
{
embeddableConfig: {},
gridData: {
h: 1,
i: 'test',
w: 1,
x: 1,
y: 1,
},
panelIndex: 'test',
type: 'test',
version: '8.0.0',
},
] as any,
});

expect(location).toMatchObject({
app: 'dashboards',
path: `#/view/123?_g=(filters:!(('$state':(store:globalState),meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),refreshInterval:(pause:!f,value:300),time:(from:now-15m,mode:relative,to:now))`,
state: {
panels: {
test: {
explicitInput: {
id: 'test',
},
gridData: {
h: 1,
i: 'test',
w: 1,
x: 1,
y: 1,
},
panelRefName: undefined,
type: 'test',
},
},
},
});
});

test('preserving time range', async () => {
const definition = new DashboardAppLocatorDefinition({
useHashedUrl: true,
getDashboardFilterFields: async (dashboardId: string) => [],
});
const location = await definition.getLocation({
forwardStateToHistory: true,
useHash: false,
timeRange: { to: 'now', from: 'now-15m', mode: 'relative' },
panels: [
{
embeddableConfig: {},
gridData: {
h: 1,
i: 'test',
w: 1,
x: 1,
y: 1,
},
panelIndex: 'test',
type: 'test',
version: '8.0.0',
},
] as any,
});

expect(location.path).toBe('#/create?_g=(time:(from:now-15m,mode:relative,to:now))');
expect(location.state).toEqual({
filters: undefined,
forwardStateToHistory: true,
panels: {
test: {
explicitInput: {
id: 'test',
},
gridData: {
h: 1,
i: 'test',
w: 1,
x: 1,
y: 1,
},
panelRefName: undefined,
type: 'test',
},
},
});
});

test('searchSessionId', async () => {
const definition = new DashboardAppLocatorDefinition({
useHashedUrl: true,
getDashboardFilterFields: async (dashboardId: string) => [],
});
const location = await definition.getLocation({
forwardStateToHistory: true,
searchSessionId: 'test',
useHash: false,
});

expect(location.path).toBe('#/create?_g=()&searchSessionId=test');
expect(location.state).toEqual({
filters: undefined,
forwardStateToHistory: true,
panels: {},
preserveSavedFilters: false,
});
});
});
27 changes: 14 additions & 13 deletions src/plugins/dashboard/public/locator.ts
Original file line number Diff line number Diff line change
@@ -122,24 +122,25 @@ export class DashboardAppLocatorDefinition implements LocatorDefinition<Dashboar
}
};

const { filters, panels, ...restParams } = params;
const state: ForwardedDashboardState = restParams;

// leave filters `undefined` if no filters was applied
// in this case dashboard will restore saved filters on its own
const filters = params.filters && [
state.filters = params.filters && [
...(await getSavedFiltersFromDestinationDashboardIfNeeded()),
...params.filters,
];

const panelsMap: DashboardPanelMap = {};

params.panels?.forEach((panel) => {
panelsMap[panel.panelIndex] = convertSavedDashboardPanelToPanelState(panel);
});

const state: ForwardedDashboardState = {
...params,
panels: (panelsMap as unknown) as DashboardPanelMap & SerializableRecord,
filters,
};
const hasPanels = Boolean(params.panels?.length);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happened to query, viewMode and savedQuery ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are forwarded to the app on history.location.state (see the ForwardedDashboardState interface).

let panelsMap: undefined | DashboardPanelMap;
if (hasPanels) {
panelsMap = {};
params.panels?.forEach((panel, idx) => {
panelsMap![panel.panelIndex ?? String(idx)] = convertSavedDashboardPanelToPanelState(panel);
});
}
state.panels = panelsMap;

let path = `#/${hash}`;
path = setStateToKbnUrl<QueryState>(
@@ -160,7 +161,7 @@ export class DashboardAppLocatorDefinition implements LocatorDefinition<Dashboar
return {
app: DashboardConstants.DASHBOARDS_ID,
path,
state,
state: cleanEmptyKeys(state),
};
};
}