Skip to content

Commit 027d763

Browse files
Merge branch '7.x' into backport/7.x/pr-88675
2 parents a3d593b + 0a797e7 commit 027d763

31 files changed

+1039
-720
lines changed

src/plugins/dashboard/public/application/listing/dashboard_listing.tsx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@
99
import { FormattedMessage } from '@kbn/i18n/react';
1010
import { EuiLink, EuiButton, EuiEmptyPrompt } from '@elastic/eui';
1111
import React, { Fragment, useCallback, useEffect, useMemo } from 'react';
12-
1312
import { attemptLoadDashboardByTitle } from '../lib';
1413
import { DashboardAppServices, DashboardRedirect } from '../types';
1514
import { getDashboardBreadcrumb, dashboardListingTable } from '../../dashboard_strings';
1615
import { ApplicationStart, SavedObjectsFindOptionsReference } from '../../../../../core/public';
17-
1816
import { syncQueryStateWithUrl } from '../../services/data';
1917
import { IKbnUrlStateStorage } from '../../services/kibana_utils';
2018
import { TableListView, useKibana } from '../../services/kibana_react';
2119
import { SavedObjectsTaggingApi } from '../../services/saved_objects_tagging_oss';
20+
import { getDashboardListItemLink } from './get_dashboard_list_item_link';
2221

2322
export interface DashboardListingProps {
2423
kbnUrlStateStorage: IKbnUrlStateStorage;
@@ -83,8 +82,13 @@ export const DashboardListing = ({
8382

8483
const tableColumns = useMemo(
8584
() =>
86-
getTableColumns((id) => redirectTo({ destination: 'dashboard', id }), savedObjectsTagging),
87-
[savedObjectsTagging, redirectTo]
85+
getTableColumns(
86+
core.application,
87+
kbnUrlStateStorage,
88+
core.uiSettings.get('state:storeInSessionStorage'),
89+
savedObjectsTagging
90+
),
91+
[core.application, core.uiSettings, kbnUrlStateStorage, savedObjectsTagging]
8892
);
8993

9094
const noItemsFragment = useMemo(
@@ -99,7 +103,6 @@ export const DashboardListing = ({
99103
(filter: string) => {
100104
let searchTerm = filter;
101105
let references: SavedObjectsFindOptionsReference[] | undefined;
102-
103106
if (savedObjectsTagging) {
104107
const parsed = savedObjectsTagging.ui.parseSearchQuery(filter, {
105108
useName: true,
@@ -164,17 +167,25 @@ export const DashboardListing = ({
164167
};
165168

166169
const getTableColumns = (
167-
redirectTo: (id?: string) => void,
170+
application: ApplicationStart,
171+
kbnUrlStateStorage: IKbnUrlStateStorage,
172+
useHash: boolean,
168173
savedObjectsTagging?: SavedObjectsTaggingApi
169174
) => {
170175
return [
171176
{
172177
field: 'title',
173178
name: dashboardListingTable.getTitleColumnName(),
174179
sortable: true,
175-
render: (field: string, record: { id: string; title: string }) => (
180+
render: (field: string, record: { id: string; title: string; timeRestore: boolean }) => (
176181
<EuiLink
177-
onClick={() => redirectTo(record.id)}
182+
href={getDashboardListItemLink(
183+
application,
184+
kbnUrlStateStorage,
185+
useHash,
186+
record.id,
187+
record.timeRestore
188+
)}
178189
data-test-subj={`dashboardListingTitleLink-${record.title.split(' ').join('-')}`}
179190
>
180191
{field}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* and the Server Side Public License, v 1; you may not use this file except in
5+
* compliance with, at your election, the Elastic License or the Server Side
6+
* Public License, v 1.
7+
*/
8+
9+
import { getDashboardListItemLink } from './get_dashboard_list_item_link';
10+
import { ApplicationStart } from 'kibana/public';
11+
import { esFilters } from '../../../../data/public';
12+
import { createHashHistory } from 'history';
13+
import { createKbnUrlStateStorage } from '../../../../kibana_utils/public';
14+
import { GLOBAL_STATE_STORAGE_KEY } from '../../url_generator';
15+
16+
const DASHBOARD_ID = '13823000-99b9-11ea-9eb6-d9e8adceb647';
17+
18+
const application = ({
19+
getUrlForApp: jest.fn((appId: string, options?: { path?: string; absolute?: boolean }) => {
20+
return `/app/${appId}${options?.path}`;
21+
}),
22+
} as unknown) as ApplicationStart;
23+
24+
const history = createHashHistory();
25+
const kbnUrlStateStorage = createKbnUrlStateStorage({
26+
history,
27+
useHash: false,
28+
});
29+
kbnUrlStateStorage.set(GLOBAL_STATE_STORAGE_KEY, { time: { from: 'now-7d', to: 'now' } });
30+
31+
describe('listing dashboard link', () => {
32+
test('creates a link to a dashboard without the timerange query if time is saved on the dashboard', async () => {
33+
const url = getDashboardListItemLink(
34+
application,
35+
kbnUrlStateStorage,
36+
false,
37+
DASHBOARD_ID,
38+
true
39+
);
40+
expect(url).toMatchInlineSnapshot(`"/app/dashboards#/view/${DASHBOARD_ID}?_g=()"`);
41+
});
42+
43+
test('creates a link to a dashboard with the timerange query if time is not saved on the dashboard', async () => {
44+
const url = getDashboardListItemLink(
45+
application,
46+
kbnUrlStateStorage,
47+
false,
48+
DASHBOARD_ID,
49+
false
50+
);
51+
expect(url).toMatchInlineSnapshot(
52+
`"/app/dashboards#/view/${DASHBOARD_ID}?_g=(time:(from:now-7d,to:now))"`
53+
);
54+
});
55+
});
56+
57+
describe('when global time changes', () => {
58+
beforeEach(() => {
59+
kbnUrlStateStorage.set(GLOBAL_STATE_STORAGE_KEY, {
60+
time: {
61+
from: '2021-01-05T11:45:53.375Z',
62+
to: '2021-01-21T11:46:00.990Z',
63+
},
64+
});
65+
});
66+
67+
test('propagates the correct time on the query', async () => {
68+
const url = getDashboardListItemLink(
69+
application,
70+
kbnUrlStateStorage,
71+
false,
72+
DASHBOARD_ID,
73+
false
74+
);
75+
expect(url).toMatchInlineSnapshot(
76+
`"/app/dashboards#/view/${DASHBOARD_ID}?_g=(time:(from:'2021-01-05T11:45:53.375Z',to:'2021-01-21T11:46:00.990Z'))"`
77+
);
78+
});
79+
});
80+
81+
describe('when global refreshInterval changes', () => {
82+
beforeEach(() => {
83+
kbnUrlStateStorage.set(GLOBAL_STATE_STORAGE_KEY, {
84+
refreshInterval: { pause: false, value: 300 },
85+
});
86+
});
87+
88+
test('propagates the refreshInterval on the query', async () => {
89+
const url = getDashboardListItemLink(
90+
application,
91+
kbnUrlStateStorage,
92+
false,
93+
DASHBOARD_ID,
94+
false
95+
);
96+
expect(url).toMatchInlineSnapshot(
97+
`"/app/dashboards#/view/${DASHBOARD_ID}?_g=(refreshInterval:(pause:!f,value:300))"`
98+
);
99+
});
100+
});
101+
102+
describe('when global filters change', () => {
103+
beforeEach(() => {
104+
const filters = [
105+
{
106+
meta: {
107+
alias: null,
108+
disabled: false,
109+
negate: false,
110+
},
111+
query: { query: 'q1' },
112+
},
113+
{
114+
meta: {
115+
alias: null,
116+
disabled: false,
117+
negate: false,
118+
},
119+
query: { query: 'q1' },
120+
$state: {
121+
store: esFilters.FilterStateStore.GLOBAL_STATE,
122+
},
123+
},
124+
];
125+
kbnUrlStateStorage.set(GLOBAL_STATE_STORAGE_KEY, {
126+
filters,
127+
});
128+
});
129+
130+
test('propagates the filters on the query', async () => {
131+
const url = getDashboardListItemLink(
132+
application,
133+
kbnUrlStateStorage,
134+
false,
135+
DASHBOARD_ID,
136+
false
137+
);
138+
expect(url).toMatchInlineSnapshot(
139+
`"/app/dashboards#/view/${DASHBOARD_ID}?_g=(filters:!((meta:(alias:!n,disabled:!f,negate:!f),query:(query:q1)),('$state':(store:globalState),meta:(alias:!n,disabled:!f,negate:!f),query:(query:q1))))"`
140+
);
141+
});
142+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* and the Server Side Public License, v 1; you may not use this file except in
5+
* compliance with, at your election, the Elastic License or the Server Side
6+
* Public License, v 1.
7+
*/
8+
import { ApplicationStart } from 'kibana/public';
9+
import { QueryState } from '../../../../data/public';
10+
import { setStateToKbnUrl } from '../../../../kibana_utils/public';
11+
import { createDashboardEditUrl, DashboardConstants } from '../../dashboard_constants';
12+
import { GLOBAL_STATE_STORAGE_KEY } from '../../url_generator';
13+
import { IKbnUrlStateStorage } from '../../services/kibana_utils';
14+
15+
export const getDashboardListItemLink = (
16+
application: ApplicationStart,
17+
kbnUrlStateStorage: IKbnUrlStateStorage,
18+
useHash: boolean,
19+
id: string,
20+
timeRestore: boolean
21+
) => {
22+
let url = application.getUrlForApp(DashboardConstants.DASHBOARDS_ID, {
23+
path: `#${createDashboardEditUrl(id)}`,
24+
});
25+
const globalStateInUrl = kbnUrlStateStorage.get<QueryState>(GLOBAL_STATE_STORAGE_KEY) || {};
26+
27+
if (timeRestore) {
28+
delete globalStateInUrl.time;
29+
delete globalStateInUrl.refreshInterval;
30+
}
31+
url = setStateToKbnUrl<QueryState>(GLOBAL_STATE_STORAGE_KEY, globalStateInUrl, { useHash }, url);
32+
return url;
33+
};

src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ describe('QueryStringInput', () => {
8989
jest.clearAllMocks();
9090
});
9191

92-
it('Should render the given query', async () => {
92+
it.skip('Should render the given query', async () => {
9393
const { getByText } = render(
9494
wrapQueryStringInputInContext({
9595
query: kqlQuery,

src/plugins/discover/public/application/angular/discover.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {
2424
import { getSortArray } from './doc_table';
2525
import * as columnActions from './doc_table/actions/columns';
2626
import indexTemplateLegacy from './discover_legacy.html';
27-
import indexTemplateGrid from './discover_datagrid.html';
2827
import { addHelpMenuToAppChrome } from '../components/help_menu/help_menu_util';
2928
import { discoverResponseHandler } from './response_handler';
3029
import {
@@ -112,9 +111,7 @@ app.config(($routeProvider) => {
112111
};
113112
const discoverRoute = {
114113
...defaults,
115-
template: getServices().uiSettings.get('doc_table:legacy', true)
116-
? indexTemplateLegacy
117-
: indexTemplateGrid,
114+
template: indexTemplateLegacy,
118115
reloadOnSearch: false,
119116
resolve: {
120117
savedObjects: function ($route, Promise) {

src/plugins/discover/public/application/angular/discover_legacy.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<discover-app>
2-
<discover-legacy
2+
<discover
33
fetch="fetch"
44
fetch-counter="fetchCounter"
55
fetch-error="fetchError"
@@ -31,5 +31,5 @@
3131
update-saved-query-id="updateSavedQueryId"
3232
use-new-fields-api="useNewFieldsApi"
3333
>
34-
</discover-legacy>
34+
</discover>
3535
</discover-app>

src/plugins/discover/public/application/angular/doc_table/create_doc_table_react.tsx

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
import angular, { auto, ICompileService, IScope } from 'angular';
1010
import { render } from 'react-dom';
1111
import React, { useRef, useEffect } from 'react';
12+
import { EuiButtonEmpty } from '@elastic/eui';
13+
import { FormattedMessage } from '@kbn/i18n/react';
1214
import { getServices, IIndexPattern } from '../../../kibana_services';
1315
import { IndexPatternField } from '../../../../../data/common/index_patterns';
16+
1417
export type AngularScope = IScope;
1518

1619
export interface AngularDirective {
@@ -83,9 +86,11 @@ export interface DocTableLegacyProps {
8386
indexPattern: IIndexPattern;
8487
minimumVisibleRows: number;
8588
onAddColumn?: (column: string) => void;
89+
onBackToTop: () => void;
8690
onSort?: (sort: string[][]) => void;
8791
onMoveColumn?: (columns: string, newIdx: number) => void;
8892
onRemoveColumn?: (column: string) => void;
93+
sampleSize: number;
8994
sort?: string[][];
9095
useNewFieldsApi?: boolean;
9196
}
@@ -120,5 +125,31 @@ export function DocTableLegacy(renderProps: DocTableLegacyProps) {
120125
return renderFn(ref.current, renderProps);
121126
}
122127
}, [renderFn, renderProps]);
123-
return <div ref={ref} />;
128+
return (
129+
<div>
130+
<div ref={ref} />
131+
{renderProps.rows.length === renderProps.sampleSize ? (
132+
<div
133+
className="dscTable__footer"
134+
data-test-subj="discoverDocTableFooter"
135+
tabIndex={-1}
136+
id="discoverBottomMarker"
137+
>
138+
<FormattedMessage
139+
id="discover.howToSeeOtherMatchingDocumentsDescription"
140+
defaultMessage="These are the first {sampleSize} documents matching
141+
your search, refine your search to see others."
142+
values={{ sampleSize: renderProps.sampleSize }}
143+
/>
144+
<EuiButtonEmpty onClick={renderProps.onBackToTop}>
145+
<FormattedMessage id="discover.backToTopLinkText" defaultMessage="Back to top." />
146+
</EuiButtonEmpty>
147+
</div>
148+
) : (
149+
<span tabIndex={-1} id="discoverBottomMarker">
150+
&#8203;
151+
</span>
152+
)}
153+
</div>
154+
);
124155
}

src/plugins/discover/public/application/components/create_discover_directive.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@ export function createDiscoverDirective(reactDirective: any) {
1717
['histogramData', { watchDepth: 'reference' }],
1818
['hits', { watchDepth: 'reference' }],
1919
['indexPattern', { watchDepth: 'reference' }],
20+
['minimumVisibleRows', { watchDepth: 'reference' }],
2021
['onAddColumn', { watchDepth: 'reference' }],
2122
['onAddFilter', { watchDepth: 'reference' }],
2223
['onChangeInterval', { watchDepth: 'reference' }],
24+
['onMoveColumn', { watchDepth: 'reference' }],
2325
['onRemoveColumn', { watchDepth: 'reference' }],
2426
['onSetColumns', { watchDepth: 'reference' }],
27+
['onSkipBottomButtonClick', { watchDepth: 'reference' }],
2528
['onSort', { watchDepth: 'reference' }],
2629
['opts', { watchDepth: 'reference' }],
2730
['resetQuery', { watchDepth: 'reference' }],
2831
['resultState', { watchDepth: 'reference' }],
2932
['rows', { watchDepth: 'reference' }],
33+
['savedSearch', { watchDepth: 'reference' }],
3034
['searchSource', { watchDepth: 'reference' }],
31-
['setColumns', { watchDepth: 'reference' }],
3235
['setIndexPattern', { watchDepth: 'reference' }],
3336
['showSaveQuery', { watchDepth: 'reference' }],
3437
['state', { watchDepth: 'reference' }],

0 commit comments

Comments
 (0)