diff --git a/src/plugins/data/common/es_query/filters/phrases_filter.ts b/src/plugins/data/common/es_query/filters/phrases_filter.ts
index 8a79472154493..2694461fc1930 100644
--- a/src/plugins/data/common/es_query/filters/phrases_filter.ts
+++ b/src/plugins/data/common/es_query/filters/phrases_filter.ts
@@ -41,11 +41,6 @@ export const buildPhrasesFilter = (
const type = FILTERS.PHRASES;
const key = field.name;
- const format = (f: IFieldType, value: any) =>
- f && f.format && f.format.convert ? f.format.convert(value) : value;
-
- const value = params.map((v: any) => format(field, v)).join(', ');
-
let should;
if (field.scripted) {
should = params.map((v: any) => ({
@@ -60,7 +55,7 @@ export const buildPhrasesFilter = (
}
return {
- meta: { index, type, key, value, params },
+ meta: { index, type, key, params },
query: {
bool: {
should,
diff --git a/src/plugins/data/common/es_query/filters/range_filter.ts b/src/plugins/data/common/es_query/filters/range_filter.ts
index 7bc7a8cff7487..9f1d9a5d08926 100644
--- a/src/plugins/data/common/es_query/filters/range_filter.ts
+++ b/src/plugins/data/common/es_query/filters/range_filter.ts
@@ -84,10 +84,7 @@ export const getRangeFilterField = (filter: RangeFilter) => {
};
const formatValue = (field: IFieldType, params: any[]) =>
- map(params, (val: any, key: string) => get(operators, key) + format(field, val)).join(' ');
-
-const format = (field: IFieldType, value: any) =>
- field && field.format && field.format.convert ? field.format.convert(value) : value;
+ map(params, (val: any, key: string) => get(operators, key) + val).join(' ');
// Creates a filter where the value for the given field is in the given range
// params should be an object containing `lt`, `lte`, `gt`, and/or `gte`
diff --git a/src/plugins/data/common/search/expressions/phrase_filter.test.ts b/src/plugins/data/common/search/expressions/phrase_filter.test.ts
index 39bd907513a0d..a61cc0bfd68ab 100644
--- a/src/plugins/data/common/search/expressions/phrase_filter.test.ts
+++ b/src/plugins/data/common/search/expressions/phrase_filter.test.ts
@@ -32,7 +32,6 @@ describe('interpreter/functions#phraseFilter', () => {
"something",
],
"type": "phrases",
- "value": "test, something",
},
"query": Object {
"bool": Object {
diff --git a/src/plugins/data/public/query/filter_manager/lib/get_display_value.test.ts b/src/plugins/data/public/query/filter_manager/lib/get_display_value.test.ts
new file mode 100644
index 0000000000000..48e1007534769
--- /dev/null
+++ b/src/plugins/data/public/query/filter_manager/lib/get_display_value.test.ts
@@ -0,0 +1,45 @@
+/*
+ * 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 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 or the Server
+ * Side Public License, v 1.
+ */
+
+import { stubIndexPattern, phraseFilter } from 'src/plugins/data/common/stubs';
+import { getDisplayValueFromFilter } from './get_display_value';
+
+describe('getDisplayValueFromFilter', () => {
+ it('returns the value if string', () => {
+ phraseFilter.meta.value = 'abc';
+ const displayValue = getDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
+ expect(displayValue).toBe('abc');
+ });
+
+ it('returns the value if undefined', () => {
+ phraseFilter.meta.value = undefined;
+ const displayValue = getDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
+ expect(displayValue).toBe('');
+ });
+
+ it('calls the value function if proivided', () => {
+ // The type of value currently doesn't match how it's used. Refactor needed.
+ phraseFilter.meta.value = jest.fn((x) => {
+ return 'abc';
+ }) as any;
+ const displayValue = getDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
+ expect(displayValue).toBe('abc');
+ expect(phraseFilter.meta.value).toHaveBeenCalledWith(undefined);
+ });
+
+ it('calls the value function if proivided, with formatter', () => {
+ stubIndexPattern.getFormatterForField = jest.fn().mockReturnValue('banana');
+ phraseFilter.meta.value = jest.fn((x) => {
+ return x + 'abc';
+ }) as any;
+ const displayValue = getDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
+ expect(stubIndexPattern.getFormatterForField).toHaveBeenCalledTimes(1);
+ expect(phraseFilter.meta.value).toHaveBeenCalledWith('banana');
+ expect(displayValue).toBe('bananaabc');
+ });
+});
diff --git a/src/plugins/data/public/query/filter_manager/lib/get_display_value.ts b/src/plugins/data/public/query/filter_manager/lib/get_display_value.ts
index 45c6167f600bc..1ccfaacb24e4b 100644
--- a/src/plugins/data/public/query/filter_manager/lib/get_display_value.ts
+++ b/src/plugins/data/public/query/filter_manager/lib/get_display_value.ts
@@ -28,11 +28,14 @@ function getValueFormatter(indexPattern?: IIndexPattern, key?: string) {
}
export function getDisplayValueFromFilter(filter: Filter, indexPatterns: IIndexPattern[]): string {
- if (typeof filter.meta.value === 'function') {
+ const { key, value } = filter.meta;
+ if (typeof value === 'function') {
const indexPattern = getIndexPatternFromFilter(filter, indexPatterns);
- const valueFormatter: any = getValueFormatter(indexPattern, filter.meta.key);
- return (filter.meta.value as any)(valueFormatter);
+ const valueFormatter = getValueFormatter(indexPattern, key);
+ // TODO: distinguish between FilterMeta which is serializable to mapped FilterMeta
+ // Where value can be a function.
+ return (value as any)(valueFormatter);
} else {
- return filter.meta.value || '';
+ return value || '';
}
}
diff --git a/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrases.ts b/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrases.ts
index bfd528264b00f..5601dd66e5206 100644
--- a/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrases.ts
+++ b/src/plugins/data/public/query/filter_manager/lib/mappers/map_phrases.ts
@@ -6,14 +6,29 @@
* Side Public License, v 1.
*/
-import { Filter, isPhrasesFilter } from '../../../../../common';
+import { Filter, FilterValueFormatter, isPhrasesFilter } from '../../../../../common';
+
+const getFormattedValueFn = (params: any) => {
+ return (formatter?: FilterValueFormatter) => {
+ return params
+ .map((v: any) => {
+ return formatter ? formatter.convert(v) : v;
+ })
+ .join(', ');
+ };
+};
export const mapPhrases = (filter: Filter) => {
if (!isPhrasesFilter(filter)) {
throw filter;
}
- const { type, key, value, params } = filter.meta;
+ const { type, key, params } = filter.meta;
- return { type, key, value, params };
+ return {
+ type,
+ key,
+ value: getFormattedValueFn(params),
+ params,
+ };
};
diff --git a/src/plugins/home/public/application/components/__snapshots__/home.test.js.snap b/src/plugins/home/public/application/components/__snapshots__/home.test.js.snap
index b949fa7995d30..153438b34eb47 100644
--- a/src/plugins/home/public/application/components/__snapshots__/home.test.js.snap
+++ b/src/plugins/home/public/application/components/__snapshots__/home.test.js.snap
@@ -1,819 +1,707 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`home change home route should render a link to change the default route in advanced settings if advanced settings is enabled 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home directories should not render directory entry when showOnHomePage is false 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home directories should render ADMIN directory entry in "Manage your data" panel 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home directories should render DATA directory entry in "Ingest your data" panel 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home directories should render solutions in the "solution section" 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
+ }
+ }
+ template="empty"
+>
+
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home header render 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home header should show "Dev tools" link if console is available 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home header should show "Manage" link if stack management is available 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home isNewKibanaInstance should safely handle execeptions 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home isNewKibanaInstance should set isNewKibanaInstance to false when there are index patterns 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home isNewKibanaInstance should set isNewKibanaInstance to true when there are no index patterns 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home should render home component 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home welcome should show the normal home page if loading fails 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home welcome should show the normal home page if welcome screen is disabled locally 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
exports[`home welcome should show the welcome screen if enabled, and there are no index patterns defined 1`] = `
@@ -824,53 +712,45 @@ exports[`home welcome should show the welcome screen if enabled, and there are n
`;
exports[`home welcome stores skip welcome setting if skipped 1`] = `
-
-
+ />,
+ "rightSideItems": Array [],
}
- />
-
-
+
+
+
+
+
+
+
+
+
+
`;
diff --git a/src/plugins/home/public/application/components/_home.scss b/src/plugins/home/public/application/components/_home.scss
index 913e1511a6314..34643433d6112 100644
--- a/src/plugins/home/public/application/components/_home.scss
+++ b/src/plugins/home/public/application/components/_home.scss
@@ -1,19 +1,3 @@
-@import '../../../../../core/public/mixins';
-
-.homWrapper {
- @include kibanaFullBodyMinHeight();
- background-color: $euiColorEmptyShade;
- display: flex;
- flex-direction: column;
-}
-
-.homContent {
- margin: 0 auto;
- max-width: 1200px;
- padding: $euiSizeXL $euiSize;
- width: 100%;
-}
-
.homData--expanded {
flex-direction: column;
diff --git a/src/plugins/home/public/application/components/_solutions_section.scss b/src/plugins/home/public/application/components/_solutions_section.scss
index a808d83916c2d..965447f689f98 100644
--- a/src/plugins/home/public/application/components/_solutions_section.scss
+++ b/src/plugins/home/public/application/components/_solutions_section.scss
@@ -1,7 +1,3 @@
-.homSolutions {
- margin-top: -($euiSizeXL + $euiSizeL + $euiSizeM);
-}
-
.homSolutions__content {
min-height: $euiSize * 16;
diff --git a/src/plugins/home/public/application/components/home.js b/src/plugins/home/public/application/components/home.js
index 3c1ba8eea22ca..fdaaeef01f47a 100644
--- a/src/plugins/home/public/application/components/home.js
+++ b/src/plugins/home/public/application/components/home.js
@@ -13,8 +13,9 @@ import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui';
import { METRIC_TYPE } from '@kbn/analytics';
import { i18n } from '@kbn/i18n';
import {
+ KibanaPageTemplate,
+ overviewPageActions,
OverviewPageFooter,
- OverviewPageHeader,
} from '../../../../../../src/plugins/kibana_react/public';
import { HOME_APP_BASE_PATH } from '../../../common/constants';
import { FeatureCatalogueCategory } from '../../services';
@@ -113,7 +114,7 @@ export class Home extends Component {
renderNormal() {
const { addBasePath, solutions, directories } = this.props;
- const { trackUiMetric } = getServices();
+ const { application, trackUiMetric } = getServices();
const devTools = this.findDirectoryById('console');
const addDataFeatures = this.getFeaturesByCategory(FeatureCatalogueCategory.DATA);
const manageDataFeatures = this.getFeaturesByCategory(FeatureCatalogueCategory.ADMIN);
@@ -124,58 +125,56 @@ export class Home extends Component {
}
return (
- ,
+ rightSideItems: overviewPageActions({
+ addBasePath,
+ application,
+ showDevToolsLink: true,
+ showManagementLink: true,
+ }),
+ }}
+ template="empty"
>
- }
- />
-
-
- {solutions.length ? (
-
- ) : null}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{
- trackUiMetric(METRIC_TYPE.CLICK, 'set_home_as_default_route');
- }}
- onChangeDefaultRoute={() => {
- trackUiMetric(METRIC_TYPE.CLICK, 'change_to_different_default_route');
- }}
+ solutions={solutions}
+ directories={directories}
/>
-
-
+ ) : null}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ trackUiMetric(METRIC_TYPE.CLICK, 'set_home_as_default_route');
+ }}
+ onChangeDefaultRoute={() => {
+ trackUiMetric(METRIC_TYPE.CLICK, 'change_to_different_default_route');
+ }}
+ />
+
);
}
diff --git a/src/plugins/home/public/application/components/home.test.js b/src/plugins/home/public/application/components/home.test.js
index 2fe74c8778c0f..fb5ebca5275cc 100644
--- a/src/plugins/home/public/application/components/home.test.js
+++ b/src/plugins/home/public/application/components/home.test.js
@@ -25,8 +25,8 @@ jest.mock('../kibana_services', () => ({
}));
jest.mock('../../../../../../src/plugins/kibana_react/public', () => ({
+ overviewPageActions: jest.fn().mockReturnValue([]),
OverviewPageFooter: jest.fn().mockReturnValue(<>>),
- OverviewPageHeader: jest.fn().mockReturnValue(<>>),
}));
describe('home', () => {
diff --git a/src/plugins/kibana_overview/public/components/_overview.scss b/src/plugins/kibana_overview/public/components/_overview.scss
index 12e2d9cd921ec..89f2b6272a4b8 100644
--- a/src/plugins/kibana_overview/public/components/_overview.scss
+++ b/src/plugins/kibana_overview/public/components/_overview.scss
@@ -1,18 +1,5 @@
-@import '../../../../core/public/mixins';
-
-.kbnOverviewWrapper {
- @include kibanaFullBodyMinHeight();
- background-color: $euiColorEmptyShade;
- display: flex;
- flex-direction: column;
-}
-
-.kbnOverviewContent {
- margin: 0 auto;
- max-width: 1200px;
- padding: $euiSizeXL $euiSize;
- width: 100%;
-
+.kbnOverviewApps__item,
+.kbnOverviewMore__item {
// Ensure card heights are stretched equally when wrapped with this element
.kbnRedirectCrossAppLinks {
align-items: flex-start;
@@ -109,11 +96,6 @@
}
}
-// Accounting for no `flush="both"` prop on EuiButtonEmpty
-.kbnOverviewDataAdd__actionButton {
- margin-right: 0;
-}
-
.kbnOverviewDataManage__item:not(:only-child) {
@include euiBreakpoint('m', 'l', 'xl') {
flex: 0 0 calc(50% - #{$euiSizeM * 2});
diff --git a/src/plugins/kibana_overview/public/components/add_data/__snapshots__/add_data.test.tsx.snap b/src/plugins/kibana_overview/public/components/add_data/__snapshots__/add_data.test.tsx.snap
index 25538d2eda287..fb32d2814c0fe 100644
--- a/src/plugins/kibana_overview/public/components/add_data/__snapshots__/add_data.test.tsx.snap
+++ b/src/plugins/kibana_overview/public/components/add_data/__snapshots__/add_data.test.tsx.snap
@@ -32,7 +32,7 @@ exports[`AddData render 1`] = `
= ({ addBasePath, features }) => {
= ({ addBasePath, isDarkTheme, apps }) =>
}
layout="horizontal"
paddingSize="none"
diff --git a/src/plugins/kibana_overview/public/components/overview/__snapshots__/overview.test.tsx.snap b/src/plugins/kibana_overview/public/components/overview/__snapshots__/overview.test.tsx.snap
index 2e7dc9a7ddc60..a32e27050fad1 100644
--- a/src/plugins/kibana_overview/public/components/overview/__snapshots__/overview.test.tsx.snap
+++ b/src/plugins/kibana_overview/public/components/overview/__snapshots__/overview.test.tsx.snap
@@ -1,10 +1,234 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Overview render 1`] = `
-,
+ "rightSideItems": Array [],
+ }
+ }
+ template="empty"
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ image="/plugins/kibanaOverview/assets/solutions_kibana_2x.png"
+ onClick={[Function]}
+ title="Kibana"
+ titleElement="h3"
+ titleSize="xs"
+ />
+
+
+
+
+
+ }
+ image="/plugins/kibanaOverview/assets/solutions_solution_2_2x.png"
+ onClick={[Function]}
+ title="Solution two"
+ titleElement="h3"
+ titleSize="xs"
+ />
+
+
+
+
+
+ }
+ image="/plugins/kibanaOverview/assets/solutions_solution_3_2x.png"
+ onClick={[Function]}
+ title="Solution three"
+ titleElement="h3"
+ titleSize="xs"
+ />
+
+
+
+
+
+ }
+ image="/plugins/kibanaOverview/assets/solutions_solution_4_2x.png"
+ onClick={[Function]}
+ title="Solution four"
+ titleElement="h3"
+ titleSize="xs"
+ />
+
+
+
+
+
+
+
+
+`;
+
+exports[`Overview without features 1`] = `
+
+ />,
+ "rightSideItems": Array [],
}
+ }
+ template="empty"
+>
+
+
-
-
-
-
+
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+ }
+ image="/plugins/kibanaOverview/assets/solutions_kibana_2x.png"
+ onClick={[Function]}
+ title="Kibana"
+ titleElement="h3"
+ titleSize="xs"
/>
-
-
-
-
+
+
-
-
-
- }
- image="/plugins/kibanaOverview/assets/solutions_kibana_2x.png"
- onClick={[Function]}
- title="Kibana"
- titleElement="h3"
- titleSize="xs"
- />
-
-
-
-
-
- }
- image="/plugins/kibanaOverview/assets/solutions_solution_2_2x.png"
- onClick={[Function]}
- title="Solution two"
- titleElement="h3"
- titleSize="xs"
- />
-
-
-
-
-
- }
- image="/plugins/kibanaOverview/assets/solutions_solution_3_2x.png"
- onClick={[Function]}
- title="Solution three"
- titleElement="h3"
- titleSize="xs"
- />
-
-
-
-
-
- }
- image="/plugins/kibanaOverview/assets/solutions_solution_4_2x.png"
- onClick={[Function]}
- title="Solution four"
- titleElement="h3"
- titleSize="xs"
- />
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Overview without features 1`] = `
-
+
+
+ }
+ image="/plugins/kibanaOverview/assets/solutions_solution_2_2x.png"
+ onClick={[Function]}
+ title="Solution two"
+ titleElement="h3"
+ titleSize="xs"
+ />
+
+
+
+
+
+ }
+ image="/plugins/kibanaOverview/assets/solutions_solution_3_2x.png"
+ onClick={[Function]}
+ title="Solution three"
+ titleElement="h3"
+ titleSize="xs"
+ />
+
+
+
+
+
+ }
+ image="/plugins/kibanaOverview/assets/solutions_solution_4_2x.png"
+ onClick={[Function]}
+ title="Solution four"
+ titleElement="h3"
+ titleSize="xs"
+ />
+
+
+
+
+
+
+
+
+`;
+
+exports[`Overview without solutions 1`] = `
+
+ />,
+ "rightSideItems": Array [],
}
+ }
+ template="empty"
+>
+
+
-
-
-
-
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- image="/plugins/kibanaOverview/assets/solutions_kibana_2x.png"
- onClick={[Function]}
- title="Kibana"
- titleElement="h3"
- titleSize="xs"
- />
-
-
-
-
-
- }
- image="/plugins/kibanaOverview/assets/solutions_solution_2_2x.png"
- onClick={[Function]}
- title="Solution two"
- titleElement="h3"
- titleSize="xs"
- />
-
-
-
-
-
- }
- image="/plugins/kibanaOverview/assets/solutions_solution_3_2x.png"
- onClick={[Function]}
- title="Solution three"
- titleElement="h3"
- titleSize="xs"
- />
-
-
-
-
-
- }
- image="/plugins/kibanaOverview/assets/solutions_solution_4_2x.png"
- onClick={[Function]}
- title="Solution four"
- titleElement="h3"
- titleSize="xs"
- />
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Overview without solutions 1`] = `
-
+
+
+
+
+
+
+
+
- }
+ onChangeDefaultRoute={[Function]}
+ onSetDefaultRoute={[Function]}
+ path="/app/kibana_overview"
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
`;
diff --git a/src/plugins/kibana_overview/public/components/overview/overview.test.tsx b/src/plugins/kibana_overview/public/components/overview/overview.test.tsx
index 6f97b04a6fdf1..9d260469625ad 100644
--- a/src/plugins/kibana_overview/public/components/overview/overview.test.tsx
+++ b/src/plugins/kibana_overview/public/components/overview/overview.test.tsx
@@ -21,8 +21,8 @@ jest.mock('../../../../../../src/plugins/kibana_react/public', () => ({
},
}),
RedirectAppLinks: jest.fn((element: JSX.Element) => element),
+ overviewPageActions: jest.fn().mockReturnValue([]),
OverviewPageFooter: jest.fn().mockReturnValue(<>>),
- OverviewPageHeader: jest.fn().mockReturnValue(<>>),
}));
jest.mock('../../lib/ui_metric', () => ({
diff --git a/src/plugins/kibana_overview/public/components/overview/overview.tsx b/src/plugins/kibana_overview/public/components/overview/overview.tsx
index 68c52b0395591..9bba923371f64 100644
--- a/src/plugins/kibana_overview/public/components/overview/overview.tsx
+++ b/src/plugins/kibana_overview/public/components/overview/overview.tsx
@@ -23,8 +23,9 @@ import { CoreStart } from 'kibana/public';
import {
RedirectAppLinks,
useKibana,
+ KibanaPageTemplate,
+ overviewPageActions,
OverviewPageFooter,
- OverviewPageHeader,
} from '../../../../../../src/plugins/kibana_react/public';
import { FetchResult } from '../../../../../../src/plugins/newsfeed/public';
import {
@@ -116,147 +117,149 @@ export const Overview: FC = ({ newsFetchResult, solutions, features }) =>
const remainingApps = kibanaApps.map(({ id }) => id).filter((id) => !mainApps.includes(id));
return (
-
- }
- />
-
-
- {isNewKibanaInstance ? (
-
- ) : (
- <>
-
-
-
-
-
-
-
- {mainApps.length ? (
- <>
-
- {mainApps.map(renderAppCard)}
-
-
-
- >
- ) : null}
+ ,
+ rightSideItems: overviewPageActions({
+ addBasePath,
+ application,
+ hidden: isNewKibanaInstance,
+ }),
+ }}
+ template="empty"
+ >
+ {isNewKibanaInstance ? (
+
+ ) : (
+ <>
+
+
+
+
+
+
- {remainingApps.length ? (
+ {mainApps.length ? (
+ <>
- {remainingApps.map(renderAppCard)}
+ {mainApps.map(renderAppCard)}
- ) : null}
-
-
+
+ >
+ ) : null}
-
- {newsFetchResult && newsFetchResult.feedItems.length ? (
-
-
-
- ) : null}
+ {remainingApps.length ? (
+
+ {remainingApps.map(renderAppCard)}
+
+ ) : null}
+
-
- {solutions.length ? (
-
-
-
-
-
-
+
+
+
+ {newsFetchResult && newsFetchResult.feedItems.length ? (
+
+
+
+ ) : null}
-
+
+ {solutions.length ? (
+
+
+
+
+
+
-
- {solutions.map(({ id, title, description, icon, path }) => (
-
-
-
- }
- image={addBasePath(getSolutionGraphicURL(snakeCase(id)))}
- title={title}
- titleElement="h3"
- titleSize="xs"
- onClick={() => {
- trackUiMetric(METRIC_TYPE.CLICK, `solution_panel_${id}`);
- }}
- />
-
-
- ))}
-
-
- ) : (
-
-
-
-
+
-
-
-
+
+ {solutions.map(({ id, title, description, icon, path }) => (
+
+
+
+ }
+ image={addBasePath(getSolutionGraphicURL(snakeCase(id)))}
+ title={title}
+ titleElement="h3"
+ titleSize="xs"
+ onClick={() => {
+ trackUiMetric(METRIC_TYPE.CLICK, `solution_panel_${id}`);
+ }}
+ />
+
+
+ ))}
- )}
-
-
- >
- )}
+
+ ) : (
+
+
+
+
-
+
+
+
+
+ )}
+
+
+ >
+ )}
-
{
- trackUiMetric(METRIC_TYPE.CLICK, 'set_kibana_overview_as_default_route');
- }}
- onChangeDefaultRoute={() => {
- trackUiMetric(METRIC_TYPE.CLICK, 'change_to_different_default_route');
- }}
- />
-
-
+
+
+ {
+ trackUiMetric(METRIC_TYPE.CLICK, 'set_kibana_overview_as_default_route');
+ }}
+ onChangeDefaultRoute={() => {
+ trackUiMetric(METRIC_TYPE.CLICK, 'change_to_different_default_route');
+ }}
+ />
+
);
};
diff --git a/src/plugins/kibana_react/public/overview_page/index.ts b/src/plugins/kibana_react/public/overview_page/index.ts
index cd4e9f6befc63..73b35f4d97a37 100644
--- a/src/plugins/kibana_react/public/overview_page/index.ts
+++ b/src/plugins/kibana_react/public/overview_page/index.ts
@@ -6,5 +6,5 @@
* Side Public License, v 1.
*/
+export * from './overview_page_actions';
export * from './overview_page_footer';
-export * from './overview_page_header';
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_actions/__snapshots__/overview_page_actions.test.tsx.snap b/src/plugins/kibana_react/public/overview_page/overview_page_actions/__snapshots__/overview_page_actions.test.tsx.snap
new file mode 100644
index 0000000000000..10910f8b87b12
--- /dev/null
+++ b/src/plugins/kibana_react/public/overview_page/overview_page_actions/__snapshots__/overview_page_actions.test.tsx.snap
@@ -0,0 +1,101 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`overviewPageActions all buttons 1`] = `
+Array [
+
+
+ Add data
+
+ ,
+
+
+ Manage
+
+ ,
+
+
+ Dev tools
+
+ ,
+]
+`;
+
+exports[`overviewPageActions no buttons 1`] = `Array []`;
+
+exports[`overviewPageActions only add data button 1`] = `
+Array [
+
+
+ Add data
+
+ ,
+]
+`;
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_header/index.ts b/src/plugins/kibana_react/public/overview_page/overview_page_actions/index.ts
similarity index 89%
rename from src/plugins/kibana_react/public/overview_page/overview_page_header/index.ts
rename to src/plugins/kibana_react/public/overview_page/overview_page_actions/index.ts
index 7017068afd460..8684d6a8ca4e4 100644
--- a/src/plugins/kibana_react/public/overview_page/overview_page_header/index.ts
+++ b/src/plugins/kibana_react/public/overview_page/overview_page_actions/index.ts
@@ -6,4 +6,4 @@
* Side Public License, v 1.
*/
-export * from './overview_page_header';
+export * from './overview_page_actions';
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_actions/overview_page_actions.test.tsx b/src/plugins/kibana_react/public/overview_page/overview_page_actions/overview_page_actions.test.tsx
new file mode 100644
index 0000000000000..f324d56196144
--- /dev/null
+++ b/src/plugins/kibana_react/public/overview_page/overview_page_actions/overview_page_actions.test.tsx
@@ -0,0 +1,51 @@
+/*
+ * 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 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 or the Server
+ * Side Public License, v 1.
+ */
+
+import { overviewPageActions } from './overview_page_actions';
+import { ApplicationStart } from 'kibana/public';
+
+jest.mock('../../app_links', () => ({
+ RedirectAppLinks: jest.fn((element: JSX.Element) => element),
+}));
+
+afterAll(() => jest.clearAllMocks());
+
+const addBasePathMock = jest.fn((path: string) => (path ? path : 'path'));
+
+const applicationStartMock = ({
+ capabilities: { navLinks: { management: true, dev_tools: true } },
+} as unknown) as ApplicationStart;
+
+describe('overviewPageActions', () => {
+ test('only add data button', () => {
+ const array = overviewPageActions({
+ addBasePath: addBasePathMock,
+ application: applicationStartMock,
+ });
+ expect(array).toMatchSnapshot();
+ });
+
+ test('all buttons', () => {
+ const array = overviewPageActions({
+ addBasePath: addBasePathMock,
+ application: applicationStartMock,
+ showDevToolsLink: true,
+ showManagementLink: true,
+ });
+ expect(array).toMatchSnapshot();
+ });
+
+ test('no buttons', () => {
+ const array = overviewPageActions({
+ addBasePath: addBasePathMock,
+ application: applicationStartMock,
+ hidden: true,
+ });
+ expect(array).toMatchSnapshot();
+ });
+});
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_actions/overview_page_actions.tsx b/src/plugins/kibana_react/public/overview_page/overview_page_actions/overview_page_actions.tsx
new file mode 100644
index 0000000000000..c3f0acd059494
--- /dev/null
+++ b/src/plugins/kibana_react/public/overview_page/overview_page_actions/overview_page_actions.tsx
@@ -0,0 +1,88 @@
+/*
+ * 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 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 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { EuiButtonEmpty } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { ApplicationStart } from 'kibana/public';
+import { RedirectAppLinks } from '../../app_links';
+
+interface Props {
+ addBasePath: (path: string) => string;
+ application: ApplicationStart;
+ hidden?: boolean;
+ showDevToolsLink?: boolean;
+ showManagementLink?: boolean;
+}
+
+export const overviewPageActions = ({
+ addBasePath,
+ application,
+ hidden,
+ showDevToolsLink,
+ showManagementLink,
+}: Props) => {
+ const {
+ management: isManagementEnabled,
+ dev_tools: isDevToolsEnabled,
+ } = application.capabilities.navLinks;
+
+ const actionAddData = (
+
+
+ {i18n.translate('kibana-react.kbnOverviewPageHeader.addDataButtonLabel', {
+ defaultMessage: 'Add data',
+ })}
+
+
+ );
+
+ const actionStackManagement =
+ showManagementLink && isManagementEnabled ? (
+
+
+ {i18n.translate('kibana-react.kbnOverviewPageHeader.stackManagementButtonLabel', {
+ defaultMessage: 'Manage',
+ })}
+
+
+ ) : null;
+
+ const actionDevTools =
+ showDevToolsLink && isDevToolsEnabled ? (
+
+
+ {i18n.translate('kibana-react.kbnOverviewPageHeader.devToolsButtonLabel', {
+ defaultMessage: 'Dev tools',
+ })}
+
+
+ ) : null;
+
+ const actions = [actionAddData, actionStackManagement, actionDevTools];
+
+ return !hidden ? actions.filter((obj) => obj) : [];
+};
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_header/__snapshots__/overview_page_header.test.tsx.snap b/src/plugins/kibana_react/public/overview_page/overview_page_header/__snapshots__/overview_page_header.test.tsx.snap
deleted file mode 100644
index 61faefb600191..0000000000000
--- a/src/plugins/kibana_react/public/overview_page/overview_page_header/__snapshots__/overview_page_header.test.tsx.snap
+++ /dev/null
@@ -1,69 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`OverviewPageHeader render 1`] = `
-
-`;
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_header/_overview_page_header.scss b/src/plugins/kibana_react/public/overview_page/overview_page_header/_overview_page_header.scss
deleted file mode 100644
index 80087195e7dbd..0000000000000
--- a/src/plugins/kibana_react/public/overview_page/overview_page_header/_overview_page_header.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-.kbnOverviewPageHeader {
- background-color: $euiPageBackgroundColor;
- border-bottom: $euiBorderWidthThin solid $euiColorLightShade;
-}
-
-.kbnOverviewPageHeader__inner {
- margin: 0 auto;
- max-width: 1200px;
- padding: $euiSizeXL $euiSize;
-
- .kbnOverviewPageHeader--hasOverlap & {
- padding-bottom: $euiSizeXL + $euiSizeL;
- }
-}
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_header/index.scss b/src/plugins/kibana_react/public/overview_page/overview_page_header/index.scss
deleted file mode 100644
index 3e8fcc537736a..0000000000000
--- a/src/plugins/kibana_react/public/overview_page/overview_page_header/index.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import './overview_page_header';
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_header/overview_page_header.test.tsx b/src/plugins/kibana_react/public/overview_page/overview_page_header/overview_page_header.test.tsx
deleted file mode 100644
index f339bed58bb49..0000000000000
--- a/src/plugins/kibana_react/public/overview_page/overview_page_header/overview_page_header.test.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 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 or the Server
- * Side Public License, v 1.
- */
-
-import React from 'react';
-import { OverviewPageHeader } from './overview_page_header';
-import { shallowWithIntl } from '@kbn/test/jest';
-
-jest.mock('../../app_links', () => ({
- RedirectAppLinks: jest.fn((element: JSX.Element) => element),
-}));
-
-jest.mock('../../context', () => ({
- useKibana: jest.fn().mockReturnValue({
- services: {
- application: { capabilities: { navLinks: { management: true, dev_tools: true } } },
- notifications: { toast: { addSuccess: jest.fn() } },
- },
- }),
-}));
-
-afterAll(() => jest.clearAllMocks());
-
-const mockTitle = 'Page Title';
-const addBasePathMock = jest.fn((path: string) => (path ? path : 'path'));
-
-describe('OverviewPageHeader', () => {
- test('render', () => {
- const component = shallowWithIntl(
-
- );
- expect(component).toMatchSnapshot();
- });
-});
diff --git a/src/plugins/kibana_react/public/overview_page/overview_page_header/overview_page_header.tsx b/src/plugins/kibana_react/public/overview_page/overview_page_header/overview_page_header.tsx
deleted file mode 100644
index cba1e093dedf3..0000000000000
--- a/src/plugins/kibana_react/public/overview_page/overview_page_header/overview_page_header.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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 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 or the Server
- * Side Public License, v 1.
- */
-
-import React, { FC } from 'react';
-import {
- EuiButtonEmpty,
- EuiFlexGroup,
- EuiFlexItem,
- EuiIcon,
- EuiTitle,
- IconType,
-} from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import { CoreStart } from 'kibana/public';
-import { RedirectAppLinks } from '../../app_links';
-import { useKibana } from '../../context';
-
-import './index.scss';
-
-interface Props {
- hideToolbar?: boolean;
- iconType?: IconType;
- overlap?: boolean;
- showDevToolsLink?: boolean;
- showManagementLink?: boolean;
- title: JSX.Element | string;
- addBasePath: (path: string) => string;
-}
-
-export const OverviewPageHeader: FC = ({
- hideToolbar,
- iconType,
- overlap,
- showDevToolsLink,
- showManagementLink,
- title,
- addBasePath,
-}) => {
- const {
- services: { application },
- } = useKibana();
-
- const {
- management: isManagementEnabled,
- dev_tools: isDevToolsEnabled,
- } = application.capabilities.navLinks;
-
- return (
-
-
-
-
-
- {iconType && (
-
-
-
- )}
-
-
-
-
-
-
-
-
-
- {!hideToolbar && (
-
-
-
-
-
- {i18n.translate('kibana-react.kbnOverviewPageHeader.addDataButtonLabel', {
- defaultMessage: 'Add data',
- })}
-
-
-
-
- {showManagementLink && isManagementEnabled ? (
-
-
-
- {i18n.translate(
- 'kibana-react.kbnOverviewPageHeader.stackManagementButtonLabel',
- {
- defaultMessage: 'Manage',
- }
- )}
-
-
-
- ) : null}
-
- {showDevToolsLink && isDevToolsEnabled ? (
-
-
-
- {i18n.translate('kibana-react.kbnOverviewPageHeader.devToolsButtonLabel', {
- defaultMessage: 'Dev tools',
- })}
-
-
-
- ) : null}
-
-
- )}
-
-
-
- );
-};
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx
index fa3b6b56a18b9..9cc1cede549b6 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx
@@ -31,8 +31,8 @@ import { RedirectAppLinks } from '../../../../../../../../../../../src/plugins/k
import type { TimeRange } from '../../../../../../../../../../../src/plugins/data/public';
import { esKuery } from '../../../../../../../../../../../src/plugins/data/public';
import { LogStream } from '../../../../../../../../../infra/public';
-import type { Agent } from '../../../../../types';
-import { useStartServices } from '../../../../../hooks';
+import type { Agent, AgentPolicy } from '../../../../../types';
+import { useLink, useStartServices } from '../../../../../hooks';
import { DEFAULT_DATE_RANGE } from './constants';
import { DatasetFilter } from './filter_dataset';
@@ -51,6 +51,7 @@ const DatePickerFlexItem = styled(EuiFlexItem)`
export interface AgentLogsProps {
agent: Agent;
+ agentPolicy?: AgentPolicy;
state: AgentLogsState;
}
@@ -64,251 +65,298 @@ export interface AgentLogsState {
export const AgentLogsUrlStateHelper = createStateContainerReactHelpers();
-export const AgentLogsUI: React.FunctionComponent = memo(({ agent, state }) => {
- const { data, application, http } = useStartServices();
- const { update: updateState } = AgentLogsUrlStateHelper.useTransitions();
+const AgentPolicyLogsNotEnabledCallout: React.FunctionComponent<{ agentPolicy: AgentPolicy }> = ({
+ agentPolicy,
+}) => {
+ const { getHref } = useLink();
- // Util to convert date expressions (returned by datepicker) to timestamps (used by LogStream)
- const getDateRangeTimestamps = useCallback(
- (timeRange: TimeRange) => {
- const { min, max } = data.query.timefilter.timefilter.calculateBounds(timeRange);
- return min && max
- ? {
- start: min.valueOf(),
- end: max.valueOf(),
- }
- : undefined;
- },
- [data.query.timefilter.timefilter]
+ return (
+
+
+ }
+ >
+
+
+
+ ),
+ }}
+ />
+
+
);
+};
- const tryUpdateDateRange = useCallback(
- (timeRange: TimeRange) => {
- const timestamps = getDateRangeTimestamps(timeRange);
- if (timestamps) {
- updateState({
- start: timeRange.from,
- end: timeRange.to,
- });
- }
- },
- [getDateRangeTimestamps, updateState]
- );
+export const AgentLogsUI: React.FunctionComponent = memo(
+ ({ agent, agentPolicy, state }) => {
+ const { data, application, http } = useStartServices();
+ const { update: updateState } = AgentLogsUrlStateHelper.useTransitions();
+
+ // Util to convert date expressions (returned by datepicker) to timestamps (used by LogStream)
+ const getDateRangeTimestamps = useCallback(
+ (timeRange: TimeRange) => {
+ const { min, max } = data.query.timefilter.timefilter.calculateBounds(timeRange);
+ return min && max
+ ? {
+ start: min.valueOf(),
+ end: max.valueOf(),
+ }
+ : undefined;
+ },
+ [data.query.timefilter.timefilter]
+ );
+
+ const tryUpdateDateRange = useCallback(
+ (timeRange: TimeRange) => {
+ const timestamps = getDateRangeTimestamps(timeRange);
+ if (timestamps) {
+ updateState({
+ start: timeRange.from,
+ end: timeRange.to,
+ });
+ }
+ },
+ [getDateRangeTimestamps, updateState]
+ );
- const [dateRangeTimestamps, setDateRangeTimestamps] = useState<{ start: number; end: number }>(
- getDateRangeTimestamps({
- from: state.start,
- to: state.end,
- }) ||
+ const [dateRangeTimestamps, setDateRangeTimestamps] = useState<{ start: number; end: number }>(
getDateRangeTimestamps({
- from: DEFAULT_DATE_RANGE.start,
- to: DEFAULT_DATE_RANGE.end,
- })!
- );
+ from: state.start,
+ to: state.end,
+ }) ||
+ getDateRangeTimestamps({
+ from: DEFAULT_DATE_RANGE.start,
+ to: DEFAULT_DATE_RANGE.end,
+ })!
+ );
- // Attempts to parse for timestamps when start/end date expressions change
- // If invalid date expressions, set expressions back to default
- // Otherwise set the new timestamps
- useEffect(() => {
- const timestampsFromDateRange = getDateRangeTimestamps({
- from: state.start,
- to: state.end,
- });
- if (!timestampsFromDateRange) {
- tryUpdateDateRange({
- from: DEFAULT_DATE_RANGE.start,
- to: DEFAULT_DATE_RANGE.end,
+ // Attempts to parse for timestamps when start/end date expressions change
+ // If invalid date expressions, set expressions back to default
+ // Otherwise set the new timestamps
+ useEffect(() => {
+ const timestampsFromDateRange = getDateRangeTimestamps({
+ from: state.start,
+ to: state.end,
});
- } else {
- setDateRangeTimestamps(timestampsFromDateRange);
- }
- }, [state.start, state.end, getDateRangeTimestamps, tryUpdateDateRange]);
+ if (!timestampsFromDateRange) {
+ tryUpdateDateRange({
+ from: DEFAULT_DATE_RANGE.start,
+ to: DEFAULT_DATE_RANGE.end,
+ });
+ } else {
+ setDateRangeTimestamps(timestampsFromDateRange);
+ }
+ }, [state.start, state.end, getDateRangeTimestamps, tryUpdateDateRange]);
- // Query validation helper
- const isQueryValid = useCallback((testQuery: string) => {
- try {
- esKuery.fromKueryExpression(testQuery);
- return true;
- } catch (err) {
- return false;
- }
- }, []);
+ // Query validation helper
+ const isQueryValid = useCallback((testQuery: string) => {
+ try {
+ esKuery.fromKueryExpression(testQuery);
+ return true;
+ } catch (err) {
+ return false;
+ }
+ }, []);
- // User query state
- const [draftQuery, setDraftQuery] = useState(state.query);
- const [isDraftQueryValid, setIsDraftQueryValid] = useState(isQueryValid(state.query));
- const onUpdateDraftQuery = useCallback(
- (newDraftQuery: string, runQuery?: boolean) => {
- setDraftQuery(newDraftQuery);
- if (isQueryValid(newDraftQuery)) {
- setIsDraftQueryValid(true);
- if (runQuery) {
- updateState({ query: newDraftQuery });
+ // User query state
+ const [draftQuery, setDraftQuery] = useState(state.query);
+ const [isDraftQueryValid, setIsDraftQueryValid] = useState(isQueryValid(state.query));
+ const onUpdateDraftQuery = useCallback(
+ (newDraftQuery: string, runQuery?: boolean) => {
+ setDraftQuery(newDraftQuery);
+ if (isQueryValid(newDraftQuery)) {
+ setIsDraftQueryValid(true);
+ if (runQuery) {
+ updateState({ query: newDraftQuery });
+ }
+ } else {
+ setIsDraftQueryValid(false);
}
- } else {
- setIsDraftQueryValid(false);
- }
- },
- [isQueryValid, updateState]
- );
+ },
+ [isQueryValid, updateState]
+ );
- // Build final log stream query from agent id, datasets, log levels, and user input
- const logStreamQuery = useMemo(
- () =>
- buildQuery({
- agentId: agent.id,
- datasets: state.datasets,
- logLevels: state.logLevels,
- userQuery: state.query,
- }),
- [agent.id, state.datasets, state.logLevels, state.query]
- );
+ // Build final log stream query from agent id, datasets, log levels, and user input
+ const logStreamQuery = useMemo(
+ () =>
+ buildQuery({
+ agentId: agent.id,
+ datasets: state.datasets,
+ logLevels: state.logLevels,
+ userQuery: state.query,
+ }),
+ [agent.id, state.datasets, state.logLevels, state.query]
+ );
- // Generate URL to pass page state to Logs UI
- const viewInLogsUrl = useMemo(
- () =>
- http.basePath.prepend(
- url.format({
- pathname: '/app/logs/stream',
- search: stringify({
- logPosition: encode({
- start: state.start,
- end: state.end,
- streamLive: false,
+ // Generate URL to pass page state to Logs UI
+ const viewInLogsUrl = useMemo(
+ () =>
+ http.basePath.prepend(
+ url.format({
+ pathname: '/app/logs/stream',
+ search: stringify({
+ logPosition: encode({
+ start: state.start,
+ end: state.end,
+ streamLive: false,
+ }),
+ logFilter: encode({
+ expression: logStreamQuery,
+ kind: 'kuery',
+ }),
}),
- logFilter: encode({
- expression: logStreamQuery,
- kind: 'kuery',
- }),
- }),
- })
- ),
- [http.basePath, state.start, state.end, logStreamQuery]
- );
-
- const agentVersion = agent.local_metadata?.elastic?.agent?.version;
- const isLogFeatureAvailable = useMemo(() => {
- if (!agentVersion) {
- return false;
- }
- const agentVersionWithPrerelease = semverCoerce(agentVersion)?.version;
- if (!agentVersionWithPrerelease) {
- return false;
- }
- return semverGte(agentVersionWithPrerelease, '7.11.0');
- }, [agentVersion]);
+ })
+ ),
+ [http.basePath, state.start, state.end, logStreamQuery]
+ );
- // Set absolute height on logs component (needed to render correctly in Safari)
- // based on available height, or 600px, whichever is greater
- const [logsPanelRef, { height: measuredlogPanelHeight }] = useMeasure();
- const logPanelHeight = useMemo(() => Math.max(measuredlogPanelHeight, 600), [
- measuredlogPanelHeight,
- ]);
+ const agentVersion = agent.local_metadata?.elastic?.agent?.version;
+ const isLogFeatureAvailable = useMemo(() => {
+ if (!agentVersion) {
+ return false;
+ }
+ const agentVersionWithPrerelease = semverCoerce(agentVersion)?.version;
+ if (!agentVersionWithPrerelease) {
+ return false;
+ }
+ return semverGte(agentVersionWithPrerelease, '7.11.0');
+ }, [agentVersion]);
- if (!isLogFeatureAvailable) {
- return (
-
-
-
- ),
- }}
- />
- }
- />
- );
- }
+ // Set absolute height on logs component (needed to render correctly in Safari)
+ // based on available height, or 600px, whichever is greater
+ const [logsPanelRef, { height: measuredlogPanelHeight }] = useMeasure();
+ const logPanelHeight = useMemo(() => Math.max(measuredlogPanelHeight, 600), [
+ measuredlogPanelHeight,
+ ]);
- return (
-
-
-
-
-
+
+
+ ),
+ }}
/>
-
-
-
- {
- const currentDatasets = [...state.datasets];
- const datasetPosition = currentDatasets.indexOf(dataset);
- if (datasetPosition >= 0) {
- currentDatasets.splice(datasetPosition, 1);
- updateState({ datasets: currentDatasets });
- } else {
- updateState({ datasets: [...state.datasets, dataset] });
- }
- }}
+ }
+ />
+ );
+ }
+
+ return (
+
+ {agentPolicy && !agentPolicy.monitoring_enabled?.includes('logs') && (
+
+ )}
+
+
+
+
- {
- const currentLevels = [...state.logLevels];
- const levelPosition = currentLevels.indexOf(level);
- if (levelPosition >= 0) {
- currentLevels.splice(levelPosition, 1);
- updateState({ logLevels: currentLevels });
- } else {
- updateState({ logLevels: [...state.logLevels, level] });
- }
+
+
+
+ {
+ const currentDatasets = [...state.datasets];
+ const datasetPosition = currentDatasets.indexOf(dataset);
+ if (datasetPosition >= 0) {
+ currentDatasets.splice(datasetPosition, 1);
+ updateState({ datasets: currentDatasets });
+ } else {
+ updateState({ datasets: [...state.datasets, dataset] });
+ }
+ }}
+ />
+ {
+ const currentLevels = [...state.logLevels];
+ const levelPosition = currentLevels.indexOf(level);
+ if (levelPosition >= 0) {
+ currentLevels.splice(levelPosition, 1);
+ updateState({ logLevels: currentLevels });
+ } else {
+ updateState({ logLevels: [...state.logLevels, level] });
+ }
+ }}
+ />
+
+
+
+ {
+ tryUpdateDateRange({
+ from: start,
+ to: end,
+ });
}}
/>
-
-
-
- {
- tryUpdateDateRange({
- from: start,
- to: end,
- });
- }}
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-});
+
+
+
+
+
+
+ );
+ }
+);
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx
index ff31ffef03925..0e2c01f095f3e 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx
@@ -22,57 +22,57 @@ import { DEFAULT_LOGS_STATE, STATE_STORAGE_KEY } from './constants';
import type { AgentLogsProps, AgentLogsState } from './agent_logs';
import { AgentLogsUI, AgentLogsUrlStateHelper } from './agent_logs';
-export const AgentLogs: React.FunctionComponent> = memo(
- ({ agent }) => {
- const stateContainer = useMemo(
- () =>
- createStateContainer<
- AgentLogsState,
- {
- update: PureTransition]>;
- }
- >(
- {
- ...DEFAULT_LOGS_STATE,
- ...getStateFromKbnUrl(STATE_STORAGE_KEY, window.location.href),
- },
- {
- update: (state) => (updatedState) => ({ ...state, ...updatedState }),
- }
- ),
- []
- );
+export const AgentLogs: React.FunctionComponent<
+ Pick
+> = memo(({ agent, agentPolicy }) => {
+ const stateContainer = useMemo(
+ () =>
+ createStateContainer<
+ AgentLogsState,
+ {
+ update: PureTransition]>;
+ }
+ >(
+ {
+ ...DEFAULT_LOGS_STATE,
+ ...getStateFromKbnUrl(STATE_STORAGE_KEY, window.location.href),
+ },
+ {
+ update: (state) => (updatedState) => ({ ...state, ...updatedState }),
+ }
+ ),
+ []
+ );
- const AgentLogsConnected = useMemo(
- () =>
- AgentLogsUrlStateHelper.connect((state) => ({
- state: state || DEFAULT_LOGS_STATE,
- }))(AgentLogsUI),
- []
- );
+ const AgentLogsConnected = useMemo(
+ () =>
+ AgentLogsUrlStateHelper.connect((state) => ({
+ state: state || DEFAULT_LOGS_STATE,
+ }))(AgentLogsUI),
+ []
+ );
- const [isSyncReady, setIsSyncReady] = useState(false);
+ const [isSyncReady, setIsSyncReady] = useState(false);
- useEffect(() => {
- const stateStorage = createKbnUrlStateStorage();
- const { start, stop } = syncState({
- storageKey: STATE_STORAGE_KEY,
- stateContainer: stateContainer as INullableBaseStateContainer,
- stateStorage,
- });
- start();
- setIsSyncReady(true);
+ useEffect(() => {
+ const stateStorage = createKbnUrlStateStorage();
+ const { start, stop } = syncState({
+ storageKey: STATE_STORAGE_KEY,
+ stateContainer: stateContainer as INullableBaseStateContainer,
+ stateStorage,
+ });
+ start();
+ setIsSyncReady(true);
- return () => {
- stop();
- stateContainer.set(DEFAULT_LOGS_STATE);
- };
- }, [stateContainer]);
+ return () => {
+ stop();
+ stateContainer.set(DEFAULT_LOGS_STATE);
+ };
+ }, [stateContainer]);
- return (
-
- {isSyncReady ? : null}
-
- );
- }
-);
+ return (
+
+ {isSyncReady ? : null}
+
+ );
+});
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx
index ce213808563e6..559cefc5fc720 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx
@@ -306,7 +306,7 @@ const AgentDetailsPageContent: React.FunctionComponent<{
{
- return ;
+ return ;
}}
/>
{
} = useMlKibana();
const helpLink = docLinks.links.ml.guide;
return (
-
+ <>
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+ }
+ body={
-
-
-
-
-
+ }
+ />
+
+
+
-
+ >
);
};
diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/access_denied_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/access_denied_page.tsx
index 0d785f1918b0b..4858db1ee55bc 100644
--- a/x-pack/plugins/ml/public/application/management/jobs_list/components/access_denied_page.tsx
+++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/access_denied_page.tsx
@@ -5,59 +5,39 @@
* 2.0.
*/
-import React, { Fragment } from 'react';
+import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
-import { i18n } from '@kbn/i18n';
-import {
- EuiCallOut,
- EuiPage,
- EuiPageBody,
- EuiPageContentBody,
- EuiPageContentHeader,
- EuiPageContentHeaderSection,
- EuiSpacer,
- EuiText,
- EuiTitle,
-} from '@elastic/eui';
+import { EuiEmptyPrompt, EuiPageContent } from '@elastic/eui';
export const AccessDeniedPage = () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ <>
+
+
+
+
+ }
+ body={
+
+
+
+ }
+ />
+
+ >
);
diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/insufficient_license_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/insufficient_license_page.tsx
index 22951e950045b..6d0c3639d939c 100644
--- a/x-pack/plugins/ml/public/application/management/jobs_list/components/insufficient_license_page.tsx
+++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/insufficient_license_page.tsx
@@ -5,78 +5,54 @@
* 2.0.
*/
-import React, { FC, Fragment } from 'react';
+import React, { FC } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
-import { i18n } from '@kbn/i18n';
import { CoreStart } from 'kibana/public';
-import {
- EuiCallOut,
- EuiPage,
- EuiPageBody,
- EuiPageContentBody,
- EuiPageContentHeader,
- EuiPageContentHeaderSection,
- EuiSpacer,
- EuiText,
- EuiTitle,
- EuiLink,
-} from '@elastic/eui';
+import { EuiEmptyPrompt, EuiLink, EuiPageContent } from '@elastic/eui';
interface Props {
basePath: CoreStart['http']['basePath'];
}
export const InsufficientLicensePage: FC = ({ basePath }) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ),
- }}
- />
-
-
-
-
-
-
-
+ <>
+
+
+
+
+ }
+ body={
+
+
+
+
+ ),
+ }}
+ />
+
+ }
+ />
+
+ >
);
diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx
index ca62ef9aaf0af..77f0e6123dfad 100644
--- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx
+++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx
@@ -8,18 +8,15 @@
import React, { useEffect, useState, Fragment, FC, useMemo, useCallback } from 'react';
import { Router } from 'react-router-dom';
import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
import { CoreStart } from 'kibana/public';
import {
EuiButtonEmpty,
- EuiFlexGroup,
- EuiFlexItem,
- EuiPageContent,
EuiPageContentBody,
+ EuiPageHeader,
EuiSpacer,
EuiTabbedContent,
- EuiText,
- EuiTitle,
EuiTabbedContentTab,
} from '@elastic/eui';
@@ -176,6 +173,19 @@ export const JobsListPage: FC<{
defaultMessage: 'Analytics jobs docs',
});
+ const docsLink = (
+
+ {currentTabId === 'anomaly_detection_jobs' ? anomalyDetectionDocsLabel : analyticsDocsLabel}
+
+ );
+
function renderTabs() {
return (
-
+ }
+ description={
+
+ }
+ rightSideItems={[docsLink]}
+ bottomBorder
+ />
+
+
+
+
-
-
-
-
- {i18n.translate('xpack.ml.management.jobsList.jobsListTitle', {
- defaultMessage: 'Machine Learning Jobs',
- })}
-
-
-
-
- {currentTabId === 'anomaly_detection_jobs'
- ? anomalyDetectionDocsLabel
- : analyticsDocsLabel}
-
-
-
-
-
-
-
- {i18n.translate('xpack.ml.management.jobsList.jobsListTagline', {
- defaultMessage: 'View machine learning analytics and anomaly detection jobs.',
- })}
-
-
-
-
- {spacesEnabled && (
- <>
- setShowSyncFlyout(true)}>
- {i18n.translate('xpack.ml.management.jobsList.syncFlyoutButton', {
- defaultMessage: 'Synchronize saved objects',
- })}
-
- {showSyncFlyout && }
-
- >
- )}
- {renderTabs()}
-
-
+ {spacesEnabled && (
+ <>
+ setShowSyncFlyout(true)}>
+ {i18n.translate('xpack.ml.management.jobsList.syncFlyoutButton', {
+ defaultMessage: 'Synchronize saved objects',
+ })}
+
+ {showSyncFlyout && }
+
+ >
+ )}
+ {renderTabs()}
+
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index e243c620ea35d..4c69c6f106873 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -13623,7 +13623,6 @@
"xpack.maps.visTypeAlias.description": "マップを作成し、複数のレイヤーとインデックスを使用して、スタイルを設定します。",
"xpack.maps.visTypeAlias.title": "マップ",
"xpack.ml.accessDenied.description": "ML プラグインへのアクセスパーミッションがありません",
- "xpack.ml.accessDenied.label": "パーミッションがありません",
"xpack.ml.accessDeniedLabel": "アクセスが拒否されました",
"xpack.ml.accessDeniedTabLabel": "アクセス拒否",
"xpack.ml.actions.applyEntityFieldsFiltersTitle": "値でフィルター",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 6304f192bca6d..9230021c296da 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -13801,7 +13801,6 @@
"xpack.maps.visTypeAlias.description": "使用多个图层和索引创建地图并提供样式。",
"xpack.maps.visTypeAlias.title": "Maps",
"xpack.ml.accessDenied.description": "您无权访问 ML 插件",
- "xpack.ml.accessDenied.label": "权限不足",
"xpack.ml.accessDeniedLabel": "访问被拒绝",
"xpack.ml.accessDeniedTabLabel": "访问被拒绝",
"xpack.ml.actions.applyEntityFieldsFiltersTitle": "筛留值",