diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx
index d5eef0c05129d..5f50cfd842b67 100644
--- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx
+++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.test.tsx
@@ -41,6 +41,7 @@ import { uiActionsPluginMock } from '../../../../ui_actions/public/mocks';
import { getStubPluginServices } from '../../../../presentation_util/public';
const presentationUtil = getStubPluginServices();
+const theme = coreMock.createStart().theme;
const options: DashboardContainerServices = {
// TODO: clean up use of any
@@ -55,7 +56,7 @@ const options: DashboardContainerServices = {
uiActions: {} as any,
uiSettings: uiSettingsServiceMock.createStartContract(),
http: coreMock.createStart().http,
- theme: coreMock.createStart().theme,
+ theme,
presentationUtil,
};
@@ -251,6 +252,7 @@ test('DashboardContainer in edit mode shows edit mode actions', async () => {
overlays={{} as any}
inspector={inspector}
SavedObjectFinder={() => null}
+ theme={theme}
/>
diff --git a/src/plugins/dashboard/public/application/listing/__snapshots__/dashboard_listing.test.tsx.snap b/src/plugins/dashboard/public/application/listing/__snapshots__/dashboard_listing.test.tsx.snap
index 2f383adb3f5c3..598254ad2173f 100644
--- a/src/plugins/dashboard/public/application/listing/__snapshots__/dashboard_listing.test.tsx.snap
+++ b/src/plugins/dashboard/public/application/listing/__snapshots__/dashboard_listing.test.tsx.snap
@@ -96,6 +96,14 @@ exports[`after fetch When given a title that matches multiple dashboards, filter
]
}
tableListTitle="Dashboards"
+ theme={
+ Object {
+ "theme$": Observable {
+ "_isScalar": false,
+ "_subscribe": [Function],
+ },
+ }
+ }
toastNotifications={
Object {
"add": [MockFunction],
@@ -208,6 +216,14 @@ exports[`after fetch initialFilter 1`] = `
]
}
tableListTitle="Dashboards"
+ theme={
+ Object {
+ "theme$": Observable {
+ "_isScalar": false,
+ "_subscribe": [Function],
+ },
+ }
+ }
toastNotifications={
Object {
"add": [MockFunction],
@@ -319,6 +335,14 @@ exports[`after fetch renders all table rows 1`] = `
]
}
tableListTitle="Dashboards"
+ theme={
+ Object {
+ "theme$": Observable {
+ "_isScalar": false,
+ "_subscribe": [Function],
+ },
+ }
+ }
toastNotifications={
Object {
"add": [MockFunction],
@@ -430,6 +454,14 @@ exports[`after fetch renders call to action when no dashboards exist 1`] = `
]
}
tableListTitle="Dashboards"
+ theme={
+ Object {
+ "theme$": Observable {
+ "_isScalar": false,
+ "_subscribe": [Function],
+ },
+ }
+ }
toastNotifications={
Object {
"add": [MockFunction],
@@ -552,6 +584,14 @@ exports[`after fetch renders call to action with continue when no dashboards exi
]
}
tableListTitle="Dashboards"
+ theme={
+ Object {
+ "theme$": Observable {
+ "_isScalar": false,
+ "_subscribe": [Function],
+ },
+ }
+ }
toastNotifications={
Object {
"add": [MockFunction],
@@ -663,6 +703,14 @@ exports[`after fetch renders warning when listingLimit is exceeded 1`] = `
]
}
tableListTitle="Dashboards"
+ theme={
+ Object {
+ "theme$": Observable {
+ "_isScalar": false,
+ "_subscribe": [Function],
+ },
+ }
+ }
toastNotifications={
Object {
"add": [MockFunction],
@@ -744,6 +792,14 @@ exports[`after fetch showWriteControls 1`] = `
]
}
tableListTitle="Dashboards"
+ theme={
+ Object {
+ "theme$": Observable {
+ "_isScalar": false,
+ "_subscribe": [Function],
+ },
+ }
+ }
toastNotifications={
Object {
"add": [MockFunction],
diff --git a/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx b/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx
index deb8671edb97d..5b53fc47e06a4 100644
--- a/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx
+++ b/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx
@@ -297,6 +297,7 @@ export const DashboardListing = ({
listingLimit,
tableColumns,
}}
+ theme={core.theme}
>
{
return {
@@ -22,6 +23,8 @@ jest.mock('@kbn/i18n', () => {
};
});
+const theme = themeServiceMock.createStartContract();
+
describe('handleResponse', () => {
const notifications = notificationServiceMock.createStartContract();
@@ -37,7 +40,7 @@ describe('handleResponse', () => {
timed_out: true,
},
} as IKibanaSearchResponse;
- const result = handleResponse(request, response);
+ const result = handleResponse(request, response, theme);
expect(result).toBe(response);
expect(notifications.toasts.addWarning).toBeCalled();
expect((notifications.toasts.addWarning as jest.Mock).mock.calls[0][0].title).toMatch(
@@ -57,7 +60,7 @@ describe('handleResponse', () => {
},
},
} as IKibanaSearchResponse;
- const result = handleResponse(request, response);
+ const result = handleResponse(request, response, theme);
expect(result).toBe(response);
expect(notifications.toasts.addWarning).toBeCalled();
expect((notifications.toasts.addWarning as jest.Mock).mock.calls[0][0].title).toMatch(
@@ -70,7 +73,7 @@ describe('handleResponse', () => {
const response = {
rawResponse: {},
} as IKibanaSearchResponse;
- const result = handleResponse(request, response);
+ const result = handleResponse(request, response, theme);
expect(result).toBe(response);
});
});
diff --git a/src/plugins/data/public/search/fetch/handle_response.tsx b/src/plugins/data/public/search/fetch/handle_response.tsx
index 10b2f69a2a320..618efcb702ec4 100644
--- a/src/plugins/data/public/search/fetch/handle_response.tsx
+++ b/src/plugins/data/public/search/fetch/handle_response.tsx
@@ -11,11 +11,16 @@ import { i18n } from '@kbn/i18n';
import { EuiSpacer } from '@elastic/eui';
import { IKibanaSearchResponse } from 'src/plugins/data/common';
import { ShardFailureOpenModalButton } from '../../ui/shard_failure_modal';
+import { ThemeServiceStart } from '../../../../../core/public';
import { toMountPoint } from '../../../../kibana_react/public';
import { getNotifications } from '../../services';
import type { SearchRequest } from '..';
-export function handleResponse(request: SearchRequest, response: IKibanaSearchResponse) {
+export function handleResponse(
+ request: SearchRequest,
+ response: IKibanaSearchResponse,
+ theme: ThemeServiceStart
+) {
const { rawResponse } = response;
if (rawResponse.timed_out) {
@@ -45,8 +50,14 @@ export function handleResponse(request: SearchRequest, response: IKibanaSearchRe
<>
{description}
-
- >
+
+ >,
+ { theme$: theme.theme$ }
);
getNotifications().toasts.addWarning({ title, text });
diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts
index 142fa94c96162..968dd870489fe 100644
--- a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts
+++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts
@@ -8,7 +8,7 @@
import type { MockedKeys } from '@kbn/utility-types/jest';
import { CoreSetup, CoreStart } from '../../../../../core/public';
-import { coreMock } from '../../../../../core/public/mocks';
+import { coreMock, themeServiceMock } from '../../../../../core/public/mocks';
import { IEsSearchRequest } from '../../../common/search';
import { SearchInterceptor } from './search_interceptor';
import { AbortError } from '../../../../kibana_utils/public';
@@ -120,6 +120,7 @@ describe('SearchInterceptor', () => {
uiSettings: mockCoreSetup.uiSettings,
http: mockCoreSetup.http,
session: sessionService,
+ theme: themeServiceMock.createSetupContract(),
});
});
diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts
index 9e968c9bae8a0..8c7bfe68fd54b 100644
--- a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts
+++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts
@@ -21,7 +21,7 @@ import {
tap,
} from 'rxjs/operators';
import { PublicMethodsOf } from '@kbn/utility-types';
-import { CoreSetup, CoreStart, ToastsSetup } from 'kibana/public';
+import { CoreSetup, CoreStart, ThemeServiceSetup, ToastsSetup } from 'kibana/public';
import { i18n } from '@kbn/i18n';
import { BatchedFunc, BfetchPublicSetup } from 'src/plugins/bfetch/public';
import {
@@ -60,6 +60,7 @@ export interface SearchInterceptorDeps {
toasts: ToastsSetup;
usageCollector?: SearchUsageCollector;
session: ISessionService;
+ theme: ThemeServiceSetup;
}
const MAX_CACHE_ITEMS = 50;
@@ -377,7 +378,7 @@ export class SearchInterceptor {
private showTimeoutErrorToast = (e: SearchTimeoutError, sessionId?: string) => {
this.deps.toasts.addDanger({
title: 'Timed out',
- text: toMountPoint(e.getErrorMessage(this.application)),
+ text: toMountPoint(e.getErrorMessage(this.application), { theme$: this.deps.theme.theme$ }),
});
};
@@ -392,7 +393,9 @@ export class SearchInterceptor {
this.deps.toasts.addWarning(
{
title: 'Your search session is still running',
- text: toMountPoint(SearchSessionIncompleteWarning(this.docLinks)),
+ text: toMountPoint(SearchSessionIncompleteWarning(this.docLinks), {
+ theme$: this.deps.theme.theme$,
+ }),
},
{
toastLifeTimeMs: 60000,
@@ -423,14 +426,14 @@ export class SearchInterceptor {
title: i18n.translate('data.search.esErrorTitle', {
defaultMessage: 'Cannot retrieve search results',
}),
- text: toMountPoint(e.getErrorMessage(this.application)),
+ text: toMountPoint(e.getErrorMessage(this.application), { theme$: this.deps.theme.theme$ }),
});
} else if (e.constructor.name === 'HttpFetchError') {
this.deps.toasts.addDanger({
title: i18n.translate('data.search.httpErrorTitle', {
defaultMessage: 'Cannot retrieve your data',
}),
- text: toMountPoint(getHttpError(e.message)),
+ text: toMountPoint(getHttpError(e.message), { theme$: this.deps.theme.theme$ }),
});
} else {
this.deps.toasts.addError(e, {
diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts
index 76aae8582287d..311a863a74933 100644
--- a/src/plugins/data/public/search/search_service.ts
+++ b/src/plugins/data/public/search/search_service.ts
@@ -46,7 +46,7 @@ import {
esRawResponse,
} from '../../common/search';
import { AggsService, AggsStartDependencies } from './aggs';
-import { IndexPatternsContract } from '..';
+import { IKibanaSearchResponse, IndexPatternsContract, SearchRequest } from '..';
import { ISearchInterceptor, SearchInterceptor } from './search_interceptor';
import { SearchUsageCollector, createUsageCollector } from './collectors';
import { UsageCollectionSetup } from '../../../usage_collection/public';
@@ -88,7 +88,7 @@ export class SearchService implements Plugin {
constructor(private initializerContext: PluginInitializerContext) {}
public setup(
- { http, getStartServices, notifications, uiSettings }: CoreSetup,
+ { http, getStartServices, notifications, uiSettings, theme }: CoreSetup,
{ bfetch, expressions, usageCollection, nowProvider }: SearchServiceSetupDependencies
): ISearchSetup {
this.usageCollector = createUsageCollector(getStartServices, usageCollection);
@@ -112,6 +112,7 @@ export class SearchService implements Plugin {
startServices: getStartServices(),
usageCollector: this.usageCollector!,
session: this.sessionService,
+ theme,
});
expressions.registerFunction(
@@ -173,7 +174,7 @@ export class SearchService implements Plugin {
}
public start(
- { http, uiSettings }: CoreStart,
+ { http, theme, uiSettings }: CoreStart,
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
): ISearchStart {
const search = ((request, options = {}) => {
@@ -186,7 +187,8 @@ export class SearchService implements Plugin {
const searchSourceDependencies: SearchSourceDependencies = {
getConfig: uiSettings.get.bind(uiSettings),
search,
- onResponse: handleResponse,
+ onResponse: (request: SearchRequest, response: IKibanaSearchResponse) =>
+ handleResponse(request, response, theme),
};
return {
diff --git a/src/plugins/data/public/services.ts b/src/plugins/data/public/services.ts
index c1a0ae1ac1b53..5c52a1e695359 100644
--- a/src/plugins/data/public/services.ts
+++ b/src/plugins/data/public/services.ts
@@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
-import { NotificationsStart, CoreStart } from 'src/core/public';
+import { NotificationsStart, CoreStart, ThemeServiceStart } from 'src/core/public';
import { createGetterSetter } from '../../kibana_utils/public';
import { IndexPatternsContract } from './data_views';
import { DataPublicPluginStart } from './types';
@@ -24,3 +24,5 @@ export const [getIndexPatterns, setIndexPatterns] =
export const [getSearchService, setSearchService] =
createGetterSetter('Search');
+
+export const [getTheme, setTheme] = createGetterSetter('Theme');
diff --git a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx
index bb5e61bdb1946..e5da2bb9f089d 100644
--- a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx
+++ b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx
@@ -24,7 +24,6 @@ import {
EuiSuperUpdateButton,
OnRefreshProps,
} from '@elastic/eui';
-
import { IDataPluginServices, IIndexPattern, TimeRange, TimeHistoryContract, Query } from '../..';
import { useKibana, withKibana } from '../../../../kibana_react/public';
import QueryStringInputUI from './query_string_input';
diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx
index a0b214d1be8c7..6464f02dd7cb7 100644
--- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx
+++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx
@@ -40,6 +40,7 @@ import type { SuggestionsListSize } from '../typeahead/suggestions_component';
import { SuggestionsComponent } from '..';
import { getFieldSubtypeNested, KIBANA_USER_QUERY_LANGUAGE_KEY } from '../../../common';
import { onRaf } from '../utils';
+import { getTheme } from '../../services';
export interface QueryStringInputProps {
indexPatterns: Array;
@@ -487,7 +488,8 @@ export default class QueryStringInputUI extends PureComponent {
-
+ ,
+ { theme$: getTheme().theme$ }
),
});
}
diff --git a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.test.tsx b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.test.tsx
index 28822cbd71ca7..b8289bc23cf01 100644
--- a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.test.tsx
+++ b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.test.tsx
@@ -8,18 +8,22 @@
import { openModal } from './shard_failure_open_modal_button.test.mocks';
import React from 'react';
+import { themeServiceMock } from 'src/core/public/mocks';
import { mountWithIntl } from '@kbn/test/jest';
import ShardFailureOpenModalButton from './shard_failure_open_modal_button';
import { shardFailureRequest } from './__mocks__/shard_failure_request';
import { shardFailureResponse } from './__mocks__/shard_failure_response';
import { findTestSubject } from '@elastic/eui/lib/test';
+const theme = themeServiceMock.createStartContract();
+
describe('ShardFailureOpenModalButton', () => {
it('triggers the openModal function when "Show details" button is clicked', () => {
const component = mountWithIntl(
);
diff --git a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.tsx b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.tsx
index 32ebd83aa47f0..585268824fb93 100644
--- a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.tsx
+++ b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.tsx
@@ -12,6 +12,7 @@ import { EuiButton, EuiTextAlign } from '@elastic/eui';
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { getOverlays } from '../../services';
+import { ThemeServiceStart } from '../../../../../core/public';
import { toMountPoint } from '../../../../kibana_react/public';
import { ShardFailureModal } from './shard_failure_modal';
import { ShardFailureRequest } from './shard_failure_types';
@@ -20,6 +21,7 @@ import { ShardFailureRequest } from './shard_failure_types';
export interface ShardFailureOpenModalButtonProps {
request: ShardFailureRequest;
response: estypes.SearchResponse;
+ theme: ThemeServiceStart;
title: string;
}
@@ -28,6 +30,7 @@ export interface ShardFailureOpenModalButtonProps {
export default function ShardFailureOpenModalButton({
request,
response,
+ theme,
title,
}: ShardFailureOpenModalButtonProps) {
function onClick() {
@@ -38,7 +41,8 @@ export default function ShardFailureOpenModalButton({
response={response}
title={title}
onClose={() => modal.close()}
- />
+ />,
+ { theme$: theme.theme$ }
),
{
className: 'shardFailureModal',
diff --git a/src/plugins/data_view_editor/public/open_editor.tsx b/src/plugins/data_view_editor/public/open_editor.tsx
index 98843d6d1698a..fcf0fad5a32b0 100644
--- a/src/plugins/data_view_editor/public/open_editor.tsx
+++ b/src/plugins/data_view_editor/public/open_editor.tsx
@@ -79,7 +79,8 @@ export const getEditorOpener =
requireTimestampField={requireTimestampField}
/>
-
+ ,
+ { theme$: core.theme.theme$ }
),
{
hideCloseButton: true,
diff --git a/src/plugins/data_view_field_editor/public/open_delete_modal.tsx b/src/plugins/data_view_field_editor/public/open_delete_modal.tsx
index 84e3885ddb605..f44367d16d08d 100644
--- a/src/plugins/data_view_field_editor/public/open_delete_modal.tsx
+++ b/src/plugins/data_view_field_editor/public/open_delete_modal.tsx
@@ -75,7 +75,8 @@ export const getFieldDeleteModalOpener =
fieldsToDelete={fieldsToDelete}
closeModal={closeModal}
confirmDelete={onConfirmDelete}
- />
+ />,
+ { theme$: core.theme.theme$ }
)
);
diff --git a/src/plugins/data_view_field_editor/public/open_editor.tsx b/src/plugins/data_view_field_editor/public/open_editor.tsx
index 277d7f5c549ae..c66e8183b9ab6 100644
--- a/src/plugins/data_view_field_editor/public/open_editor.tsx
+++ b/src/plugins/data_view_field_editor/public/open_editor.tsx
@@ -128,7 +128,8 @@ export const getFieldEditorOpener =
fieldFormats={fieldFormats}
uiSettings={uiSettings}
/>
-
+ ,
+ { theme$: core.theme.theme$ }
),
{
className: euiFlyoutClassname,
diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.test.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.test.tsx
index dd78b00f9775e..f85f7bb254826 100644
--- a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.test.tsx
+++ b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.test.tsx
@@ -11,7 +11,9 @@ import { shallow } from 'enzyme';
import { IndexPattern } from 'src/plugins/data/public';
import { IndexedFieldItem } from '../../types';
import { Table, renderFieldName, getConflictModalContent } from './table';
-import { overlayServiceMock } from 'src/core/public/mocks';
+import { overlayServiceMock, themeServiceMock } from 'src/core/public/mocks';
+
+const theme = themeServiceMock.createStartContract();
const indexPattern = {
timeFieldName: 'timestamp',
@@ -89,6 +91,7 @@ const renderTable = (
editField={editField}
deleteField={() => {}}
openModal={overlayServiceMock.createStartContract().openModal}
+ theme={theme}
/>
);
diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx
index 6a82d0380629c..7e915e3c930a5 100644
--- a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx
+++ b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/table.tsx
@@ -7,7 +7,7 @@
*/
import React, { PureComponent } from 'react';
-import { OverlayModalStart } from 'src/core/public';
+import { OverlayModalStart, ThemeServiceStart } from 'src/core/public';
import {
EuiIcon,
@@ -179,6 +179,7 @@ interface IndexedFieldProps {
editField: (field: IndexedFieldItem) => void;
deleteField: (fieldName: string) => void;
openModal: OverlayModalStart['open'];
+ theme: ThemeServiceStart;
}
const getItems = (conflictDescriptions: IndexedFieldItem['conflictDescriptions']) => {
@@ -311,7 +312,8 @@ export const getConflictModalContent = ({
const getConflictBtn = (
fieldName: string,
conflictDescriptions: IndexedFieldItem['conflictDescriptions'],
- openModal: IndexedFieldProps['openModal']
+ openModal: IndexedFieldProps['openModal'],
+ theme: ThemeServiceStart
) => {
const onClick = () => {
const overlayRef = openModal(
@@ -322,7 +324,8 @@ const getConflictBtn = (
},
fieldName,
conflictDescriptions,
- })
+ }),
+ { theme$: theme.theme$ }
)
);
};
@@ -355,7 +358,12 @@ export class Table extends PureComponent {
{type === 'conflict' && conflictDescription ? '' : type}
{field.conflictDescriptions
- ? getConflictBtn(field.name, field.conflictDescriptions, this.props.openModal)
+ ? getConflictBtn(
+ field.name,
+ field.conflictDescriptions,
+ this.props.openModal,
+ this.props.theme
+ )
: ''}
);
diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx
index a72c87655fd63..29b8d82a99704 100644
--- a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx
+++ b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx
@@ -8,7 +8,7 @@
import React, { Component } from 'react';
import { createSelector } from 'reselect';
-import { OverlayStart } from 'src/core/public';
+import { OverlayStart, ThemeServiceStart } from 'src/core/public';
import { IndexPatternField, IndexPattern } from '../../../../../../plugins/data/public';
import { useKibana } from '../../../../../../plugins/kibana_react/public';
import { Table } from './components/table';
@@ -28,6 +28,7 @@ interface IndexedFieldsTableProps {
fieldWildcardMatcher: (filters: any[]) => (val: any) => boolean;
userEditPermission: boolean;
openModal: OverlayStart['openModal'];
+ theme: ThemeServiceStart;
}
interface IndexedFieldsTableState {
@@ -129,6 +130,7 @@ class IndexedFields extends Component this.props.helpers.editField(field.name)}
deleteField={(fieldName) => this.props.helpers.deleteField(fieldName)}
openModal={this.props.openModal}
+ theme={this.props.theme}
/>
);
diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx
index b5940fa8d1bb0..58b064fa79893 100644
--- a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx
+++ b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx
@@ -80,7 +80,7 @@ export function Tabs({
location,
refreshFields,
}: TabsProps) {
- const { application, uiSettings, docLinks, dataViewFieldEditor, overlays } =
+ const { application, uiSettings, docLinks, dataViewFieldEditor, overlays, theme } =
useKibana().services;
const [fieldFilter, setFieldFilter] = useState('');
const [indexedFieldTypeFilter, setIndexedFieldTypeFilter] = useState('');
@@ -236,6 +236,7 @@ export function Tabs({
getFieldInfo,
}}
openModal={overlays.openModal}
+ theme={theme}
/>
)}
@@ -295,6 +296,7 @@ export function Tabs({
DeleteRuntimeFieldProvider,
refreshFields,
overlays,
+ theme,
]
);
diff --git a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx
index 6e0e7ffc9091d..4bc0a204f68a1 100644
--- a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx
+++ b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx
@@ -14,7 +14,7 @@ import { i18n } from '@kbn/i18n';
import { I18nProvider } from '@kbn/i18n-react';
import { StartServicesAccessor } from 'src/core/public';
-import { KibanaContextProvider } from '../../../kibana_react/public';
+import { KibanaContextProvider, KibanaThemeProvider } from '../../../kibana_react/public';
import { ManagementAppMountParams } from '../../../management/public';
import {
IndexPatternTableWithRouter,
@@ -39,7 +39,7 @@ export async function mountManagementSection(
params: ManagementAppMountParams
) {
const [
- { chrome, application, uiSettings, notifications, overlays, http, docLinks },
+ { chrome, application, uiSettings, notifications, overlays, http, docLinks, theme },
{ data, dataViewFieldEditor, dataViewEditor },
indexPatternManagementStart,
] = await getStartServices();
@@ -67,25 +67,27 @@ export async function mountManagementSection(
ReactDOM.render(
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
,
params.element
);
diff --git a/src/plugins/data_views/public/data_views/redirect_no_index_pattern.tsx b/src/plugins/data_views/public/data_views/redirect_no_index_pattern.tsx
index 086cd92a92d82..fc7b8c9eb42b6 100644
--- a/src/plugins/data_views/public/data_views/redirect_no_index_pattern.tsx
+++ b/src/plugins/data_views/public/data_views/redirect_no_index_pattern.tsx
@@ -18,7 +18,8 @@ export const onRedirectNoIndexPattern =
(
capabilities: CoreStart['application']['capabilities'],
navigateToApp: CoreStart['application']['navigateToApp'],
- overlays: CoreStart['overlays']
+ overlays: CoreStart['overlays'],
+ theme: CoreStart['theme']
) =>
() => {
const canManageIndexPatterns = capabilities.management.kibana.indexPatterns;
@@ -38,7 +39,9 @@ export const onRedirectNoIndexPattern =
// give them a friendly info message instead of a terse error message
bannerId = overlays.banners.replace(
bannerId,
- toMountPoint()
+ toMountPoint(, {
+ theme$: theme.theme$,
+ })
);
// hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around
diff --git a/src/plugins/data_views/public/plugin.ts b/src/plugins/data_views/public/plugin.ts
index 4a00ea91a47bd..bf092d3fae177 100644
--- a/src/plugins/data_views/public/plugin.ts
+++ b/src/plugins/data_views/public/plugin.ts
@@ -45,7 +45,7 @@ export class DataViewsPublicPlugin
core: CoreStart,
{ fieldFormats }: DataViewsPublicStartDependencies
): DataViewsPublicPluginStart {
- const { uiSettings, http, notifications, savedObjects, overlays, application } = core;
+ const { uiSettings, http, notifications, savedObjects, theme, overlays, application } = core;
return new DataViewsService({
uiSettings: new UiSettingsPublicToCommon(uiSettings),
@@ -59,7 +59,8 @@ export class DataViewsPublicPlugin
onRedirectNoIndexPattern: onRedirectNoIndexPattern(
application.capabilities,
application.navigateToApp,
- overlays
+ overlays,
+ theme
),
getCanSave: () => Promise.resolve(application.capabilities.indexPatterns.save === true),
});
diff --git a/src/plugins/discover/public/application/main/discover_main_route.tsx b/src/plugins/discover/public/application/main/discover_main_route.tsx
index b2576a3b5d582..dd1d036b811a2 100644
--- a/src/plugins/discover/public/application/main/discover_main_route.tsx
+++ b/src/plugins/discover/public/application/main/discover_main_route.tsx
@@ -122,6 +122,7 @@ export function DiscoverMainRoute({ services, history }: DiscoverMainProps) {
onBeforeRedirect() {
getUrlTracker().setTrackedUrl('/');
},
+ theme: core.theme,
})(e);
}
}
@@ -139,6 +140,7 @@ export function DiscoverMainRoute({ services, history }: DiscoverMainProps) {
id,
services,
toastNotifications,
+ core.theme,
]);
useEffect(() => {
diff --git a/src/plugins/embeddable/public/lib/embeddables/error_embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/error_embeddable.tsx
index f4c650507add9..70c30d314fc82 100644
--- a/src/plugins/embeddable/public/lib/embeddables/error_embeddable.tsx
+++ b/src/plugins/embeddable/public/lib/embeddables/error_embeddable.tsx
@@ -9,10 +9,11 @@
import { EuiText, EuiIcon, EuiSpacer } from '@elastic/eui';
import React from 'react';
import ReactDOM from 'react-dom';
-import { Markdown } from '../../../../kibana_react/public';
+import { KibanaThemeProvider, Markdown } from '../../../../kibana_react/public';
import { Embeddable } from './embeddable';
import { EmbeddableInput, EmbeddableOutput, IEmbeddable } from './i_embeddable';
import { IContainer } from '../containers';
+import { getTheme } from '../../services';
export const ERROR_EMBEDDABLE_TYPE = 'error';
@@ -37,8 +38,13 @@ export class ErrorEmbeddable extends Embeddable
@@ -49,9 +55,16 @@ export class ErrorEmbeddable extends Embeddable
- ,
- dom
+
);
+ const content =
+ theme && theme.theme$ ? (
+ {node}
+ ) : (
+ node
+ );
+
+ ReactDOM.render(content, dom);
}
public destroy() {
diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx
index 78bd337b21e52..8d313030556c6 100644
--- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx
+++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx
@@ -31,7 +31,7 @@ import {
import { inspectorPluginMock } from '../../../../inspector/public/mocks';
import { EuiBadge } from '@elastic/eui';
import { embeddablePluginMock } from '../../mocks';
-import { applicationServiceMock } from '../../../../../core/public/mocks';
+import { applicationServiceMock, themeServiceMock } from '../../../../../core/public/mocks';
const actionRegistry = new Map();
const triggerRegistry = new Map();
@@ -44,6 +44,7 @@ const trigger: Trigger = {
};
const embeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any);
const applicationMock = applicationServiceMock.createStartContract();
+const theme = themeServiceMock.createStartContract();
actionRegistry.set(editModeAction.id, editModeAction);
triggerRegistry.set(trigger.id, trigger);
@@ -152,6 +153,7 @@ test('HelloWorldContainer in view mode hides edit mode actions', async () => {
overlays={{} as any}
inspector={inspector}
SavedObjectFinder={() => null}
+ theme={theme}
/>
);
@@ -191,6 +193,7 @@ const renderInEditModeAndOpenContextMenu = async (
application={applicationMock}
inspector={inspector}
SavedObjectFinder={() => null}
+ theme={theme}
/>
);
@@ -298,6 +301,7 @@ test('HelloWorldContainer in edit mode shows edit mode actions', async () => {
application={applicationMock}
inspector={inspector}
SavedObjectFinder={() => null}
+ theme={theme}
/>
);
@@ -360,6 +364,7 @@ test('Panel title customize link does not exist in view mode', async () => {
application={applicationMock}
inspector={inspector}
SavedObjectFinder={() => null}
+ theme={theme}
/>
);
@@ -395,6 +400,7 @@ test('Runs customize panel action on title click when in edit mode', async () =>
application={applicationMock}
inspector={inspector}
SavedObjectFinder={() => null}
+ theme={theme}
/>
);
@@ -443,6 +449,7 @@ test('Updates when hidePanelTitles is toggled', async () => {
application={applicationMock}
inspector={inspector}
SavedObjectFinder={() => null}
+ theme={theme}
/>
);
@@ -497,6 +504,7 @@ test('Check when hide header option is false', async () => {
inspector={inspector}
SavedObjectFinder={() => null}
hideHeader={false}
+ theme={theme}
/>
);
@@ -535,6 +543,7 @@ test('Check when hide header option is true', async () => {
inspector={inspector}
SavedObjectFinder={() => null}
hideHeader={true}
+ theme={theme}
/>
);
@@ -567,6 +576,7 @@ test('Should work in minimal way rendering only the inspector action', async ()
getActions={() => Promise.resolve([])}
inspector={inspector}
hideHeader={false}
+ theme={theme}
/>
);
diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx
index 6748e9f3b1d08..2e501984dfa76 100644
--- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx
+++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx
@@ -12,7 +12,7 @@ import React from 'react';
import { Subscription } from 'rxjs';
import deepEqual from 'fast-deep-equal';
import { buildContextMenuForActions, UiActionsService, Action } from '../ui_actions';
-import { CoreStart, OverlayStart } from '../../../../../core/public';
+import { CoreStart, OverlayStart, ThemeServiceStart } from '../../../../../core/public';
import { toMountPoint } from '../../../../kibana_react/public';
import { UsageCollectionStart } from '../../../../usage_collection/public';
@@ -83,6 +83,7 @@ interface Props {
showBadges?: boolean;
showNotifications?: boolean;
containerContext?: EmbeddableContainerContext;
+ theme: ThemeServiceStart;
}
interface State {
@@ -347,8 +348,7 @@ export class EmbeddablePanel extends React.Component {
) {
return actions;
}
-
- const createGetUserData = (overlays: OverlayStart) =>
+ const createGetUserData = (overlays: OverlayStart, theme: ThemeServiceStart) =>
async function getUserData(context: { embeddable: IEmbeddable }) {
return new Promise<{ title: string | undefined; hideTitle?: boolean }>((resolve) => {
const session = overlays.openModal(
@@ -360,7 +360,8 @@ export class EmbeddablePanel extends React.Component {
resolve({ title, hideTitle });
}}
cancel={() => session.close()}
- />
+ />,
+ { theme$: theme.theme$ }
),
{
'data-test-subj': 'customizePanel',
@@ -373,13 +374,16 @@ export class EmbeddablePanel extends React.Component {
// registry.
return {
...actions,
- customizePanelTitle: new CustomizePanelTitleAction(createGetUserData(this.props.overlays)),
+ customizePanelTitle: new CustomizePanelTitleAction(
+ createGetUserData(this.props.overlays, this.props.theme)
+ ),
addPanel: new AddPanelAction(
this.props.getEmbeddableFactory,
this.props.getAllEmbeddableFactories,
this.props.overlays,
this.props.notifications,
this.props.SavedObjectFinder,
+ this.props.theme,
this.props.reportUiCounter
),
removePanel: new RemovePanelAction(),
diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx
index 224cb80478769..fe6a9ea3c22b3 100644
--- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx
+++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx
@@ -16,7 +16,7 @@ import {
} from '../../../../test_samples/embeddables/filterable_embeddable';
import { FilterableEmbeddableFactory } from '../../../../test_samples/embeddables/filterable_embeddable_factory';
import { FilterableContainer } from '../../../../test_samples/embeddables/filterable_container';
-import { coreMock } from '../../../../../../../../core/public/mocks';
+import { coreMock, themeServiceMock } from '../../../../../../../../core/public/mocks';
import { ContactCardEmbeddable } from '../../../../test_samples';
import { EmbeddableStart } from '../../../../../plugin';
import { embeddablePluginMock } from '../../../../../mocks';
@@ -25,6 +25,7 @@ import { defaultTrigger } from '../../../../../../../ui_actions/public/triggers'
const { setup, doStart } = embeddablePluginMock.createInstance();
setup.registerEmbeddableFactory(FILTERABLE_EMBEDDABLE, new FilterableEmbeddableFactory());
const getFactory = doStart().getEmbeddableFactory;
+const theme = themeServiceMock.createStartContract();
let container: FilterableContainer;
let embeddable: FilterableEmbeddable;
@@ -37,7 +38,8 @@ beforeEach(async () => {
() => [] as any,
start.overlays,
start.notifications,
- () => null
+ () => null,
+ theme
);
const derivedFilter: MockFilter = {
@@ -72,7 +74,8 @@ test('Is not compatible when container is in view mode', async () => {
() => [] as any,
start.overlays,
start.notifications,
- () => null
+ () => null,
+ theme
);
container.updateInput({ viewMode: ViewMode.VIEW });
expect(
diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts
index 49be1c3ce0123..d766c509782a0 100644
--- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts
+++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts
@@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
import { Action, ActionExecutionContext } from 'src/plugins/ui_actions/public';
-import { NotificationsStart, OverlayStart } from 'src/core/public';
+import { NotificationsStart, OverlayStart, ThemeServiceStart } from 'src/core/public';
import { EmbeddableStart } from 'src/plugins/embeddable/public/plugin';
import { ViewMode } from '../../../../types';
import { openAddPanelFlyout } from './open_add_panel_flyout';
@@ -31,6 +31,7 @@ export class AddPanelAction implements Action {
private readonly overlays: OverlayStart,
private readonly notifications: NotificationsStart,
private readonly SavedObjectFinder: React.ComponentType,
+ private readonly theme: ThemeServiceStart,
private readonly reportUiCounter?: UsageCollectionStart['reportUiCounter']
) {}
@@ -63,6 +64,7 @@ export class AddPanelAction implements Action {
notifications: this.notifications,
SavedObjectFinder: this.SavedObjectFinder,
reportUiCounter: this.reportUiCounter,
+ theme: this.theme,
});
}
}
diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx
index fe54b3d134aa0..00c6f99abda09 100644
--- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx
+++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx
@@ -7,7 +7,7 @@
*/
import React from 'react';
-import { NotificationsStart, OverlayRef, OverlayStart } from 'src/core/public';
+import { NotificationsStart, OverlayRef, OverlayStart, ThemeServiceStart } from 'src/core/public';
import { EmbeddableStart } from '../../../../../plugin';
import { toMountPoint } from '../../../../../../../kibana_react/public';
import { IContainer } from '../../../../containers';
@@ -23,6 +23,7 @@ export function openAddPanelFlyout(options: {
SavedObjectFinder: React.ComponentType;
showCreateNewMenu?: boolean;
reportUiCounter?: UsageCollectionStart['reportUiCounter'];
+ theme: ThemeServiceStart;
}): OverlayRef {
const {
embeddable,
@@ -33,6 +34,7 @@ export function openAddPanelFlyout(options: {
SavedObjectFinder,
showCreateNewMenu,
reportUiCounter,
+ theme,
} = options;
const flyoutSession = overlays.openFlyout(
toMountPoint(
@@ -49,7 +51,8 @@ export function openAddPanelFlyout(options: {
reportUiCounter={reportUiCounter}
SavedObjectFinder={SavedObjectFinder}
showCreateNewMenu={showCreateNewMenu}
- />
+ />,
+ { theme$: theme.theme$ }
),
{
'data-test-subj': 'dashboardAddPanel',
diff --git a/src/plugins/embeddable/public/mocks.tsx b/src/plugins/embeddable/public/mocks.tsx
index 94eb5e5cc6a02..44d2b395a48c3 100644
--- a/src/plugins/embeddable/public/mocks.tsx
+++ b/src/plugins/embeddable/public/mocks.tsx
@@ -20,7 +20,7 @@ import {
ReferenceOrValueEmbeddable,
} from '.';
import { EmbeddablePublicPlugin } from './plugin';
-import { coreMock } from '../../../core/public/mocks';
+import { coreMock, themeServiceMock } from '../../../core/public/mocks';
import { UiActionsService } from './lib/ui_actions';
import { CoreStart } from '../../../core/public';
import { Start as InspectorStart } from '../../inspector/public';
@@ -43,6 +43,8 @@ interface CreateEmbeddablePanelMockArgs {
SavedObjectFinder: React.ComponentType;
}
+const theme = themeServiceMock.createStartContract();
+
export const createEmbeddablePanelMock = ({
getActions,
getEmbeddableFactory,
@@ -64,6 +66,7 @@ export const createEmbeddablePanelMock = ({
overlays={overlays || ({} as any)}
inspector={inspector || ({} as any)}
SavedObjectFinder={SavedObjectFinder || (() => null)}
+ theme={theme}
/>
);
};
diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx
index 465c5d741d5a9..041207f2f2380 100644
--- a/src/plugins/embeddable/public/plugin.tsx
+++ b/src/plugins/embeddable/public/plugin.tsx
@@ -52,6 +52,7 @@ import {
getTelemetryFunction,
} from '../common/lib';
import { getAllMigrations } from '../common/lib/get_all_migrations';
+import { setTheme } from './services';
export interface EmbeddableSetupDependencies {
uiActions: UiActionsSetup;
@@ -119,6 +120,7 @@ export class EmbeddablePublicPlugin implements Plugin
);
diff --git a/src/plugins/embeddable/public/services.ts b/src/plugins/embeddable/public/services.ts
new file mode 100644
index 0000000000000..96088e086a771
--- /dev/null
+++ b/src/plugins/embeddable/public/services.ts
@@ -0,0 +1,12 @@
+/*
+ * 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 { ThemeServiceSetup } from 'src/core/public';
+import { createGetterSetter } from '../../kibana_utils/public';
+
+export const [getTheme, setTheme] = createGetterSetter('Theme');
diff --git a/src/plugins/inspector/public/plugin.tsx b/src/plugins/inspector/public/plugin.tsx
index e561a9719b3fb..14a141f7c2ec1 100644
--- a/src/plugins/inspector/public/plugin.tsx
+++ b/src/plugins/inspector/public/plugin.tsx
@@ -106,7 +106,8 @@ export class InspectorPublicPlugin implements Plugin {
uiSettings: core.uiSettings,
share: startDeps.share,
}}
- />
+ />,
+ { theme$: core.theme.theme$ }
),
{
'data-test-subj': 'inspectorPanel',
diff --git a/src/plugins/kibana_react/public/notifications/create_notifications.tsx b/src/plugins/kibana_react/public/notifications/create_notifications.tsx
index 2e59e611fc421..8eb16a5580ab3 100644
--- a/src/plugins/kibana_react/public/notifications/create_notifications.tsx
+++ b/src/plugins/kibana_react/public/notifications/create_notifications.tsx
@@ -24,8 +24,8 @@ export const createNotifications = (services: KibanaServices): KibanaReactNotifi
throw new TypeError('Could not show notification as notifications service is not available.');
}
services.notifications!.toasts.add({
- title: toMountPoint(title),
- text: toMountPoint(<>{body || null}>),
+ title: toMountPoint(title, { theme$: services.theme?.theme$ }),
+ text: toMountPoint(<>{body || null}>, { theme$: services.theme?.theme$ }),
color,
iconType,
toastLifeTimeMs,
diff --git a/src/plugins/kibana_react/public/overlays/create_react_overlays.tsx b/src/plugins/kibana_react/public/overlays/create_react_overlays.tsx
index 3274699e4bd69..4349e39d04fd5 100644
--- a/src/plugins/kibana_react/public/overlays/create_react_overlays.tsx
+++ b/src/plugins/kibana_react/public/overlays/create_react_overlays.tsx
@@ -20,12 +20,18 @@ export const createReactOverlays = (services: KibanaServices): KibanaReactOverla
const openFlyout: KibanaReactOverlays['openFlyout'] = (node, options?) => {
checkCoreService();
- return services.overlays!.openFlyout(toMountPoint(<>{node}>), options);
+ return services.overlays!.openFlyout(
+ toMountPoint(<>{node}>, { theme$: services.theme?.theme$ }),
+ options
+ );
};
const openModal: KibanaReactOverlays['openModal'] = (node, options?) => {
checkCoreService();
- return services.overlays!.openModal(toMountPoint(<>{node}>), options);
+ return services.overlays!.openModal(
+ toMountPoint(<>{node}>, { theme$: services.theme?.theme$ }),
+ options
+ );
};
const overlays: KibanaReactOverlays = {
diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx
index 3663f156c69cb..bdc5ca30216bc 100644
--- a/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx
+++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.test.tsx
@@ -10,6 +10,7 @@ import { EuiEmptyPrompt } from '@elastic/eui';
import { shallowWithIntl } from '@kbn/test/jest';
import { ToastsStart } from 'kibana/public';
import React from 'react';
+import { themeServiceMock } from '../../../../../src/core/public/mocks';
import { TableListView } from './table_list_view';
const requiredProps = {
@@ -24,6 +25,7 @@ const requiredProps = {
tableCaption: 'test caption',
toastNotifications: {} as ToastsStart,
findItems: jest.fn(() => Promise.resolve({ total: 0, hits: [] })),
+ theme: themeServiceMock.createStartContract(),
};
describe('TableListView', () => {
diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx
index 65c62543538d0..dd023d522dbb6 100644
--- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx
+++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx
@@ -20,7 +20,7 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
-import { HttpFetchError, ToastsStart } from 'kibana/public';
+import { ThemeServiceStart, HttpFetchError, ToastsStart } from 'kibana/public';
import { debounce, keyBy, sortBy, uniq } from 'lodash';
import React from 'react';
import { KibanaPageTemplate } from '../page_template';
@@ -57,6 +57,7 @@ export interface TableListViewProps {
*/
tableCaption: string;
searchFilters?: SearchFilterConfig[];
+ theme: ThemeServiceStart;
}
export interface TableListViewState {
@@ -177,7 +178,8 @@ class TableListView extends React.Component<
id="kibana-react.tableListView.listing.unableToDeleteDangerMessage"
defaultMessage="Unable to delete {entityName}(s)"
values={{ entityName: this.props.entityName }}
- />
+ />,
+ { theme$: this.props.theme.theme$ }
),
text: `${error}`,
});
diff --git a/src/plugins/kibana_react/public/theme/kibana_theme_provider.tsx b/src/plugins/kibana_react/public/theme/kibana_theme_provider.tsx
index 65d640f34a2ca..56ca7642f1cde 100644
--- a/src/plugins/kibana_react/public/theme/kibana_theme_provider.tsx
+++ b/src/plugins/kibana_react/public/theme/kibana_theme_provider.tsx
@@ -21,8 +21,9 @@ const defaultTheme: CoreTheme = {
darkMode: false,
};
-// IMPORTANT: This code has been copied to the `interactive_setup` plugin, any changes here should be applied there too.
-// That copy and this comment can be removed once https://github.com/elastic/kibana/issues/119204 is implemented.
+/* IMPORTANT: This code has been copied to the `interactive_setup` plugin, any changes here should be applied there too.
+That copy and this comment can be removed once https://github.com/elastic/kibana/issues/119204 is implemented.*/
+// IMPORTANT: This code has been copied to the `kibana_utils` plugin, to avoid cyclical dependency, any changes here should be applied there too.
export const KibanaThemeProvider: FC = ({ theme$, children }) => {
const theme = useObservable(theme$, defaultTheme);
diff --git a/src/plugins/kibana_react/public/theme/utils.ts b/src/plugins/kibana_react/public/theme/utils.ts
index 161f3a5e36b76..fe8092949d431 100644
--- a/src/plugins/kibana_react/public/theme/utils.ts
+++ b/src/plugins/kibana_react/public/theme/utils.ts
@@ -10,8 +10,9 @@ import { COLOR_MODES_STANDARD } from '@elastic/eui';
import type { EuiThemeColorModeStandard } from '@elastic/eui';
import type { CoreTheme } from '../../../../core/public';
-// IMPORTANT: This code has been copied to the `interactive_setup` plugin, any changes here should be applied there too.
-// That copy and this comment can be removed once https://github.com/elastic/kibana/issues/119204 is implemented.
+/* IMPORTANT: This code has been copied to the `interactive_setup` plugin, any changes here should be applied there too.
+That copy and this comment can be removed once https://github.com/elastic/kibana/issues/119204 is implemented.*/
+// IMPORTANT: This code has been copied to the `kibana_utils` plugin, to avoid cyclical dependency, any changes here should be applied there too.
export const getColorMode = (theme: CoreTheme): EuiThemeColorModeStandard => {
return theme.darkMode ? COLOR_MODES_STANDARD.dark : COLOR_MODES_STANDARD.light;
diff --git a/src/plugins/kibana_utils/public/history/redirect_when_missing.tsx b/src/plugins/kibana_utils/public/history/redirect_when_missing.tsx
index c64ac35e6f83f..6913c94a6bb5f 100644
--- a/src/plugins/kibana_utils/public/history/redirect_when_missing.tsx
+++ b/src/plugins/kibana_utils/public/history/redirect_when_missing.tsx
@@ -13,7 +13,9 @@ import { EuiLoadingSpinner } from '@elastic/eui';
import ReactDOM from 'react-dom';
import { ApplicationStart, HttpStart, ToastsSetup } from 'kibana/public';
+import type { ThemeServiceStart } from '../../../../core/public';
import { SavedObjectNotFound } from '..';
+import { KibanaThemeProvider } from '../theme';
const ReactMarkdown = React.lazy(() => import('react-markdown'));
const ErrorRenderer = (props: { children: string }) => (
@@ -45,6 +47,7 @@ export function redirectWhenMissing({
mapping,
toastNotifications,
onBeforeRedirect,
+ theme,
}: {
history: History;
navigateToApp: ApplicationStart['navigateToApp'];
@@ -62,6 +65,7 @@ export function redirectWhenMissing({
* Optional callback invoked directly before a redirect is triggered
*/
onBeforeRedirect?: (error: SavedObjectNotFound) => void;
+ theme: ThemeServiceStart;
}) {
let localMappingObject: Mapping;
@@ -92,7 +96,12 @@ export function redirectWhenMissing({
defaultMessage: 'Saved object is missing',
}),
text: (element: HTMLElement) => {
- ReactDOM.render({error.message}, element);
+ ReactDOM.render(
+
+ {error.message}
+ ,
+ element
+ );
return () => ReactDOM.unmountComponentAtNode(element);
},
});
diff --git a/src/plugins/kibana_utils/public/theme/index.ts b/src/plugins/kibana_utils/public/theme/index.ts
new file mode 100644
index 0000000000000..165c5ef9195c2
--- /dev/null
+++ b/src/plugins/kibana_utils/public/theme/index.ts
@@ -0,0 +1,9 @@
+/*
+ * 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.
+ */
+
+export { KibanaThemeProvider } from './kibana_theme_provider';
diff --git a/src/plugins/kibana_utils/public/theme/kibana_theme_provider.test.tsx b/src/plugins/kibana_utils/public/theme/kibana_theme_provider.test.tsx
new file mode 100644
index 0000000000000..21059bd4a8236
--- /dev/null
+++ b/src/plugins/kibana_utils/public/theme/kibana_theme_provider.test.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 { useEuiTheme } from '@elastic/eui';
+import type { ReactWrapper } from 'enzyme';
+import type { FC } from 'react';
+import React, { useEffect } from 'react';
+import { act } from 'react-dom/test-utils';
+import { BehaviorSubject, of } from 'rxjs';
+
+import { mountWithIntl } from '@kbn/test/jest';
+import type { CoreTheme } from 'src/core/public';
+
+import { KibanaThemeProvider } from './kibana_theme_provider';
+
+describe('KibanaThemeProvider', () => {
+ let euiTheme: ReturnType | undefined;
+
+ beforeEach(() => {
+ euiTheme = undefined;
+ });
+
+ const flushPromises = async () => {
+ await new Promise(async (resolve, reject) => {
+ try {
+ setImmediate(() => resolve());
+ } catch (error) {
+ reject(error);
+ }
+ });
+ };
+
+ const InnerComponent: FC = () => {
+ const theme = useEuiTheme();
+ useEffect(() => {
+ euiTheme = theme;
+ }, [theme]);
+ return foo
;
+ };
+
+ const refresh = async (wrapper: ReactWrapper) => {
+ await act(async () => {
+ await flushPromises();
+ wrapper.update();
+ });
+ };
+
+ it('exposes the EUI theme provider', async () => {
+ const coreTheme: CoreTheme = { darkMode: true };
+
+ const wrapper = mountWithIntl(
+
+
+
+ );
+
+ await refresh(wrapper);
+
+ expect(euiTheme!.colorMode).toEqual('DARK');
+ });
+
+ it('propagates changes of the coreTheme observable', async () => {
+ const coreTheme$ = new BehaviorSubject({ darkMode: true });
+
+ const wrapper = mountWithIntl(
+
+
+
+ );
+
+ await refresh(wrapper);
+
+ expect(euiTheme!.colorMode).toEqual('DARK');
+
+ await act(async () => {
+ coreTheme$.next({ darkMode: false });
+ });
+
+ await refresh(wrapper);
+
+ expect(euiTheme!.colorMode).toEqual('LIGHT');
+ });
+});
diff --git a/src/plugins/kibana_utils/public/theme/kibana_theme_provider.tsx b/src/plugins/kibana_utils/public/theme/kibana_theme_provider.tsx
new file mode 100644
index 0000000000000..7c7963eff984b
--- /dev/null
+++ b/src/plugins/kibana_utils/public/theme/kibana_theme_provider.tsx
@@ -0,0 +1,33 @@
+/*
+ * 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 { EuiThemeProvider } from '@elastic/eui';
+import type { FC } from 'react';
+import React, { useMemo } from 'react';
+import useObservable from 'react-use/lib/useObservable';
+import type { Observable } from 'rxjs';
+
+import type { CoreTheme } from '../../../../core/public';
+import { getColorMode } from './utils';
+
+interface KibanaThemeProviderProps {
+ theme$: Observable;
+}
+
+const defaultTheme: CoreTheme = {
+ darkMode: false,
+};
+
+/**
+ * Copied from the `kibana_react` plugin, to avoid cyclical dependency
+ */
+export const KibanaThemeProvider: FC = ({ theme$, children }) => {
+ const theme = useObservable(theme$, defaultTheme);
+ const colorMode = useMemo(() => getColorMode(theme), [theme]);
+ return {children};
+};
diff --git a/src/plugins/kibana_utils/public/theme/utils.test.ts b/src/plugins/kibana_utils/public/theme/utils.test.ts
new file mode 100644
index 0000000000000..57b37f4fb2f62
--- /dev/null
+++ b/src/plugins/kibana_utils/public/theme/utils.test.ts
@@ -0,0 +1,19 @@
+/*
+ * 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 { getColorMode } from './utils';
+
+describe('getColorMode', () => {
+ it('returns the correct `colorMode` when `darkMode` is enabled', () => {
+ expect(getColorMode({ darkMode: true })).toEqual('DARK');
+ });
+
+ it('returns the correct `colorMode` when `darkMode` is disabled', () => {
+ expect(getColorMode({ darkMode: false })).toEqual('LIGHT');
+ });
+});
diff --git a/src/plugins/kibana_utils/public/theme/utils.ts b/src/plugins/kibana_utils/public/theme/utils.ts
new file mode 100644
index 0000000000000..887e4fe61fbe1
--- /dev/null
+++ b/src/plugins/kibana_utils/public/theme/utils.ts
@@ -0,0 +1,19 @@
+/*
+ * 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 { COLOR_MODES_STANDARD } from '@elastic/eui';
+import type { EuiThemeColorModeStandard } from '@elastic/eui';
+
+import type { CoreTheme } from '../../../../core/public';
+
+/**
+ * Copied from the `kibana_react` plugin, to avoid cyclical dependency
+ */
+export const getColorMode = (theme: CoreTheme): EuiThemeColorModeStandard => {
+ return theme.darkMode ? COLOR_MODES_STANDARD.dark : COLOR_MODES_STANDARD.light;
+};
diff --git a/src/plugins/kibana_utils/tsconfig.json b/src/plugins/kibana_utils/tsconfig.json
index 0538b145a5d62..0fba68be6aa57 100644
--- a/src/plugins/kibana_utils/tsconfig.json
+++ b/src/plugins/kibana_utils/tsconfig.json
@@ -14,7 +14,5 @@
"index.ts",
"../../../typings/**/*"
],
- "references": [
- { "path": "../../core/tsconfig.json" }
- ]
+ "references": [{ "path": "../../core/tsconfig.json" }]
}
diff --git a/src/plugins/share/kibana.json b/src/plugins/share/kibana.json
index 2e34da1da0287..08365d895f4b4 100644
--- a/src/plugins/share/kibana.json
+++ b/src/plugins/share/kibana.json
@@ -8,6 +8,6 @@
"githubTeam": "kibana-app-services"
},
"description": "Adds URL Service and sharing capabilities to Kibana",
- "requiredBundles": ["kibanaUtils"],
+ "requiredBundles": ["kibanaReact", "kibanaUtils"],
"optionalPlugins": []
}
diff --git a/src/plugins/share/public/services/share_menu_manager.tsx b/src/plugins/share/public/services/share_menu_manager.tsx
index 52f000512aa07..237e71009d205 100644
--- a/src/plugins/share/public/services/share_menu_manager.tsx
+++ b/src/plugins/share/public/services/share_menu_manager.tsx
@@ -11,7 +11,8 @@ import ReactDOM from 'react-dom';
import { I18nProvider } from '@kbn/i18n-react';
import { EuiWrappingPopover } from '@elastic/eui';
-import { CoreStart, HttpStart } from 'kibana/public';
+import { CoreStart, HttpStart, ThemeServiceStart } from 'kibana/public';
+import { KibanaThemeProvider } from '../../../kibana_react/public';
import { ShareContextMenu } from '../components/share_context_menu';
import { ShareMenuItem, ShowShareMenuOptions } from '../types';
import { ShareMenuRegistryStart } from './share_menu_registry';
@@ -42,6 +43,7 @@ export class ShareMenuManager {
post: core.http.post,
basePath: core.http.basePath.get(),
anonymousAccess,
+ theme: core.theme,
});
},
};
@@ -65,12 +67,14 @@ export class ShareMenuManager {
basePath,
embedUrlParamExtensions,
anonymousAccess,
+ theme,
showPublicUrlSwitch,
}: ShowShareMenuOptions & {
menuItems: ShareMenuItem[];
post: HttpStart['post'];
basePath: string;
anonymousAccess: AnonymousAccessServiceContract | undefined;
+ theme: ThemeServiceStart;
}) {
if (this.isOpen) {
this.onClose();
@@ -82,30 +86,32 @@ export class ShareMenuManager {
document.body.appendChild(this.container);
const element = (
-
-
-
+
+
+
+
+
);
ReactDOM.render(element, this.container);
diff --git a/src/plugins/share/public/url_service/redirect/components/page.tsx b/src/plugins/share/public/url_service/redirect/components/page.tsx
index 805213b73fdd0..f6aa4d62767c5 100644
--- a/src/plugins/share/public/url_service/redirect/components/page.tsx
+++ b/src/plugins/share/public/url_service/redirect/components/page.tsx
@@ -9,38 +9,45 @@
import * as React from 'react';
import useObservable from 'react-use/lib/useObservable';
import { EuiPageTemplate } from '@elastic/eui';
+import { ThemeServiceSetup } from 'kibana/public';
import { Error } from './error';
import { RedirectManager } from '../redirect_manager';
import { Spinner } from './spinner';
+import { KibanaThemeProvider } from '../../../../../kibana_react/public';
export interface PageProps {
manager: Pick;
+ theme: ThemeServiceSetup;
}
-export const Page: React.FC = ({ manager }) => {
+export const Page: React.FC = ({ manager, theme }) => {
const error = useObservable(manager.error$);
if (error) {
return (
+
+
+
+
+
+ );
+ }
+
+ return (
+
-
+
- );
- }
-
- return (
-
-
-
+
);
};
diff --git a/src/plugins/share/public/url_service/redirect/redirect_manager.ts b/src/plugins/share/public/url_service/redirect/redirect_manager.ts
index e6f524347e48c..9d7357eab310c 100644
--- a/src/plugins/share/public/url_service/redirect/redirect_manager.ts
+++ b/src/plugins/share/public/url_service/redirect/redirect_manager.ts
@@ -29,7 +29,7 @@ export class RedirectManager {
chromeless: true,
mount: async (params) => {
const { render } = await import('./render');
- const unmount = render(params.element, { manager: this });
+ const unmount = render(params.element, { manager: this, theme: core.theme });
this.onMount(params.history.location.search);
return () => {
unmount();
diff --git a/src/plugins/share/tsconfig.json b/src/plugins/share/tsconfig.json
index 1f9c438f03fc4..2633d840895d6 100644
--- a/src/plugins/share/tsconfig.json
+++ b/src/plugins/share/tsconfig.json
@@ -9,6 +9,7 @@
"include": ["common/**/*", "public/**/*", "server/**/*"],
"references": [
{ "path": "../../core/tsconfig.json" },
- { "path": "../kibana_utils/tsconfig.json" },
+ { "path": "../kibana_react/tsconfig.json" },
+ { "path": "../kibana_utils/tsconfig.json" }
]
}
diff --git a/src/plugins/ui_actions/public/context_menu/open_context_menu.tsx b/src/plugins/ui_actions/public/context_menu/open_context_menu.tsx
index 91cb8099e8b3c..04449d7b656bc 100644
--- a/src/plugins/ui_actions/public/context_menu/open_context_menu.tsx
+++ b/src/plugins/ui_actions/public/context_menu/open_context_menu.tsx
@@ -11,6 +11,8 @@ import React from 'react';
import { EuiContextMenu, EuiContextMenuPanelDescriptor, EuiPopover } from '@elastic/eui';
import { EventEmitter } from 'events';
import ReactDOM from 'react-dom';
+import { KibanaThemeProvider } from '../../../kibana_react/public';
+import { getTheme } from '../services';
let activeSession: ContextMenuSession | null = null;
@@ -168,20 +170,22 @@ export function openContextMenu(
};
ReactDOM.render(
-
-
- ,
+
+
+
+
+ ,
container
);
diff --git a/src/plugins/ui_actions/public/plugin.ts b/src/plugins/ui_actions/public/plugin.ts
index ea6a7e42815cb..2a2ad100a53d3 100644
--- a/src/plugins/ui_actions/public/plugin.ts
+++ b/src/plugins/ui_actions/public/plugin.ts
@@ -10,6 +10,7 @@ import { CoreStart, CoreSetup, Plugin, PluginInitializerContext } from 'src/core
import { PublicMethodsOf } from '@kbn/utility-types';
import { UiActionsService } from './service';
import { rowClickTrigger, visualizeFieldTrigger, visualizeGeoFieldTrigger } from './triggers';
+import { setTheme } from './services';
export type UiActionsSetup = Pick<
UiActionsService,
@@ -29,6 +30,7 @@ export class UiActionsPlugin implements Plugin {
constructor(initializerContext: PluginInitializerContext) {}
public setup(core: CoreSetup): UiActionsSetup {
+ setTheme(core.theme);
this.service.registerTrigger(rowClickTrigger);
this.service.registerTrigger(visualizeFieldTrigger);
this.service.registerTrigger(visualizeGeoFieldTrigger);
diff --git a/src/plugins/ui_actions/public/services.ts b/src/plugins/ui_actions/public/services.ts
new file mode 100644
index 0000000000000..96088e086a771
--- /dev/null
+++ b/src/plugins/ui_actions/public/services.ts
@@ -0,0 +1,12 @@
+/*
+ * 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 { ThemeServiceSetup } from 'src/core/public';
+import { createGetterSetter } from '../../kibana_utils/public';
+
+export const [getTheme, setTheme] = createGetterSetter('Theme');
diff --git a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx
index 24f0a871a12f7..cf219b1cda117 100644
--- a/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx
+++ b/src/plugins/visualizations/public/visualize_app/components/visualize_listing.tsx
@@ -42,6 +42,7 @@ export const VisualizeListing = () => {
visualizeCapabilities,
dashboardCapabilities,
kbnUrlStateStorage,
+ theme,
},
} = useKibana();
const { pathname } = useLocation();
@@ -201,6 +202,7 @@ export const VisualizeListing = () => {
})}
toastNotifications={toastNotifications}
searchFilters={searchFilters}
+ theme={theme}
>
{dashboardCapabilities.createNew && (
<>
diff --git a/src/plugins/visualizations/public/visualize_app/types.ts b/src/plugins/visualizations/public/visualize_app/types.ts
index cca4d9a48d104..a414dd2e61762 100644
--- a/src/plugins/visualizations/public/visualize_app/types.ts
+++ b/src/plugins/visualizations/public/visualize_app/types.ts
@@ -17,6 +17,7 @@ import type {
ToastsStart,
ScopedHistory,
AppMountParameters,
+ ThemeServiceStart,
} from 'kibana/public';
import type {
@@ -105,6 +106,7 @@ export interface VisualizeServices extends CoreStart {
usageCollection?: UsageCollectionStart;
getKibanaVersion: () => string;
spaces?: SpacesPluginStart;
+ theme: ThemeServiceStart;
visEditorsRegistry: VisEditorsRegistry;
}
diff --git a/src/plugins/visualizations/public/visualize_app/utils/utils.ts b/src/plugins/visualizations/public/visualize_app/utils/utils.ts
index a99b756fe8714..b3257f03354a6 100644
--- a/src/plugins/visualizations/public/visualize_app/utils/utils.ts
+++ b/src/plugins/visualizations/public/visualize_app/utils/utils.ts
@@ -92,5 +92,6 @@ export const redirectToSavedObjectPage = (
onBeforeRedirect() {
setActiveUrl(VisualizeConstants.LANDING_PAGE_PATH);
},
+ theme: services.theme,
})(error);
};
diff --git a/x-pack/examples/reporting_example/kibana.json b/x-pack/examples/reporting_example/kibana.json
index 94780f1df0b36..489b2bcd9f506 100644
--- a/x-pack/examples/reporting_example/kibana.json
+++ b/x-pack/examples/reporting_example/kibana.json
@@ -10,6 +10,13 @@
},
"description": "Example integration code for applications to feature reports.",
"optionalPlugins": [],
- "requiredPlugins": ["reporting", "developerExamples", "navigation", "screenshotMode", "share"],
+ "requiredPlugins": [
+ "reporting",
+ "developerExamples",
+ "kibanaReact",
+ "navigation",
+ "screenshotMode",
+ "share"
+ ],
"requiredBundles": ["screenshotting"]
}
diff --git a/x-pack/examples/reporting_example/public/application.tsx b/x-pack/examples/reporting_example/public/application.tsx
index 3e1afd7c517a2..9b044ac801773 100644
--- a/x-pack/examples/reporting_example/public/application.tsx
+++ b/x-pack/examples/reporting_example/public/application.tsx
@@ -9,6 +9,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch } from 'react-router-dom';
import { AppMountParameters, CoreStart } from '../../../../src/core/public';
+import { KibanaThemeProvider } from '../../../../../kibana/src/plugins/kibana_react/public';
import { CaptureTest } from './containers/capture_test';
import { Main } from './containers/main';
import { ApplicationContextProvider } from './application_context';
@@ -23,12 +24,14 @@ export const renderApp = (
) => {
ReactDOM.render(
-
-
- } />
- } />
-
-
+
+
+
+ } />
+ } />
+
+
+
,
element
);
diff --git a/x-pack/examples/reporting_example/tsconfig.json b/x-pack/examples/reporting_example/tsconfig.json
index 4c4016911e0c5..1b097d8e52868 100644
--- a/x-pack/examples/reporting_example/tsconfig.json
+++ b/x-pack/examples/reporting_example/tsconfig.json
@@ -9,15 +9,15 @@
"public/**/*.tsx",
"server/**/*.ts",
"common/**/*.ts",
- "../../../typings/**/*",
+ "../../../typings/**/*"
],
"exclude": [],
"references": [
{ "path": "../../../src/core/tsconfig.json" },
+ { "path": "../../../src/plugins/kibana_react/tsconfig.json" },
{ "path": "../../../src/plugins/navigation/tsconfig.json" },
{ "path": "../../../src/plugins/screenshot_mode/tsconfig.json" },
{ "path": "../../../examples/developer_examples/tsconfig.json" },
- { "path": "../../plugins/reporting/tsconfig.json" },
+ { "path": "../../plugins/reporting/tsconfig.json" }
]
}
-
diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts
index 6ec645c932e05..ee76cce9b9d2b 100644
--- a/x-pack/plugins/data_enhanced/public/plugin.ts
+++ b/x-pack/plugins/data_enhanced/public/plugin.ts
@@ -81,7 +81,8 @@ export class DataEnhancedPlugin
usageCollector: this.usageCollector,
tourDisabled: plugins.screenshotMode.isScreenshotMode(),
})
- )
+ ),
+ { theme$: core.theme.theme$ }
),
});
}
diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/delete_button.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/delete_button.tsx
index 3d1a3052e720b..127a63b647a24 100644
--- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/delete_button.tsx
+++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/delete_button.tsx
@@ -74,7 +74,8 @@ export const createDeleteActionDescriptor = (
onClick: async () => {
const ref = core.overlays.openModal(
toMountPoint(
- ref?.close()} searchSession={uiSession} api={api} />
+ ref?.close()} searchSession={uiSession} api={api} />,
+ { theme$: core.theme.theme$ }
)
);
await ref.onClose;
diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/extend_button.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/extend_button.tsx
index 6989caeca359e..d8b5e9de16688 100644
--- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/extend_button.tsx
+++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/extend_button.tsx
@@ -81,7 +81,8 @@ export const createExtendActionDescriptor = (
onClick: async () => {
const ref = core.overlays.openModal(
toMountPoint(
- ref?.close()} searchSession={uiSession} api={api} />
+ ref?.close()} searchSession={uiSession} api={api} />,
+ { theme$: core.theme.theme$ }
)
);
await ref.onClose;
diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/inspect_button.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/inspect_button.tsx
index 23c010e0fbc67..2b917c28c4b3b 100644
--- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/inspect_button.tsx
+++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/inspect_button.tsx
@@ -97,7 +97,7 @@ export const createInspectActionDescriptor = (
),
onClick: async () => {
const flyout = ;
- const overlay = core.overlays.openFlyout(toMountPoint(flyout));
+ const overlay = core.overlays.openFlyout(toMountPoint(flyout, { theme$: core.theme.theme$ }));
await overlay.onClose;
},
});
diff --git a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/rename_button.tsx b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/rename_button.tsx
index beb773e057cb9..d663d0da5cad7 100644
--- a/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/rename_button.tsx
+++ b/x-pack/plugins/data_enhanced/public/search/sessions_mgmt/components/actions/rename_button.tsx
@@ -113,7 +113,8 @@ export const createRenameActionDescriptor = (
onClick: async () => {
const ref = core.overlays.openModal(
toMountPoint(
- ref?.close()} api={api} searchSession={uiSession} />
+ ref?.close()} api={api} searchSession={uiSession} />,
+ { theme$: core.theme.theme$ }
)
);
await ref.onClose;
diff --git a/x-pack/plugins/graph/public/apps/listing_route.tsx b/x-pack/plugins/graph/public/apps/listing_route.tsx
index 4ed0789f33fdf..dc70d84155bf9 100644
--- a/x-pack/plugins/graph/public/apps/listing_route.tsx
+++ b/x-pack/plugins/graph/public/apps/listing_route.tsx
@@ -102,6 +102,7 @@ export function ListingRoute({
tableListTitle={i18n.translate('xpack.graph.listing.graphsTitle', {
defaultMessage: 'Graphs',
})}
+ theme={coreStart.theme}
/>
);
diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx
index 7f65e50bf4429..e501138648b14 100644
--- a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx
+++ b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx
@@ -6,7 +6,7 @@
*/
import React, { FC, useEffect } from 'react';
-import type { CoreStart } from 'kibana/public';
+import type { CoreStart, ThemeServiceStart } from 'kibana/public';
import type { UiActionsStart } from 'src/plugins/ui_actions/public';
import type { Start as InspectorStartContract } from 'src/plugins/inspector/public';
import { EuiLoadingChart } from '@elastic/eui';
@@ -68,6 +68,7 @@ export function getEmbeddableComponent(core: CoreStart, plugins: PluginsStartDep
const input = { ...props };
const [embeddable, loading, error] = useEmbeddableFactory({ factory, input });
const hasActions = props.withActions === true;
+ const theme = core.theme;
if (loading) {
return ;
@@ -81,6 +82,7 @@ export function getEmbeddableComponent(core: CoreStart, plugins: PluginsStartDep
inspector={inspector}
actionPredicate={() => hasActions}
input={input}
+ theme={theme}
/>
);
}
@@ -95,6 +97,7 @@ interface EmbeddablePanelWrapperProps {
inspector: PluginsStartDependencies['inspector'];
actionPredicate: (id: string) => boolean;
input: EmbeddableComponentProps;
+ theme: ThemeServiceStart;
}
const EmbeddablePanelWrapper: FC = ({
@@ -103,6 +106,7 @@ const EmbeddablePanelWrapper: FC = ({
actionPredicate,
inspector,
input,
+ theme,
}) => {
useEffect(() => {
embeddable.updateInput(input);
@@ -118,6 +122,7 @@ const EmbeddablePanelWrapper: FC = ({
showShadow={false}
showBadges={false}
showNotifications={false}
+ theme={theme}
/>
);
};
diff --git a/x-pack/plugins/maps/public/kibana_services.ts b/x-pack/plugins/maps/public/kibana_services.ts
index ddc2851f595b0..027981de32295 100644
--- a/x-pack/plugins/maps/public/kibana_services.ts
+++ b/x-pack/plugins/maps/public/kibana_services.ts
@@ -54,6 +54,7 @@ export const getSavedObjectsTagging = () => pluginsStart.savedObjectsTagging;
export const getPresentationUtilContext = () => pluginsStart.presentationUtil.ContextProvider;
export const getSecurityService = () => pluginsStart.security;
export const getSpacesApi = () => pluginsStart.spaces;
+export const getTheme = () => coreStart.theme;
// xpack.maps.* kibana.yml settings from this plugin
let mapAppConfig: MapsConfigType;
diff --git a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx
index 7dc8c9c88d4ca..571cba64a06c4 100644
--- a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx
+++ b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx
@@ -21,6 +21,7 @@ import {
getSavedObjectsClient,
getSavedObjectsTagging,
getSavedObjects,
+ getTheme,
} from '../../kibana_services';
import { getAppTitle } from '../../../common/i18n_getters';
import { MapSavedObjectAttributes } from '../../../common/map_saved_object_type';
@@ -148,6 +149,7 @@ export function MapsListView() {
tableListTitle={getAppTitle()}
toastNotifications={getToasts()}
searchFilters={searchFilters}
+ theme={getTheme()}
/>
);
}
diff --git a/x-pack/plugins/reporting/public/lib/stream_handler.test.ts b/x-pack/plugins/reporting/public/lib/stream_handler.test.ts
index 1bb8c3229407d..78742af7fe879 100644
--- a/x-pack/plugins/reporting/public/lib/stream_handler.test.ts
+++ b/x-pack/plugins/reporting/public/lib/stream_handler.test.ts
@@ -7,7 +7,7 @@
import sinon, { stub } from 'sinon';
import { NotificationsStart } from 'src/core/public';
-import { coreMock } from '../../../../../src/core/public/mocks';
+import { coreMock, themeServiceMock } from '../../../../../src/core/public/mocks';
import { JobSummary, ReportApiJSON } from '../../common/types';
import { Job } from './job';
import { ReportingAPIClient } from './reporting_api_client';
@@ -46,19 +46,21 @@ const notificationsMock = {
},
} as unknown as NotificationsStart;
+const theme = themeServiceMock.createStartContract();
+
describe('stream handler', () => {
afterEach(() => {
sinon.reset();
});
it('constructs', () => {
- const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock);
+ const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock, theme);
expect(sh).not.toBe(null);
});
describe('findChangedStatusJobs', () => {
it('finds no changed status jobs from empty', (done) => {
- const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock);
+ const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock, theme);
const findJobs = sh.findChangedStatusJobs([]);
findJobs.subscribe((data) => {
expect(data).toEqual({ completed: [], failed: [] });
@@ -67,7 +69,7 @@ describe('stream handler', () => {
});
it('finds changed status jobs', (done) => {
- const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock);
+ const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock, theme);
const findJobs = sh.findChangedStatusJobs([
'job-source-mock1',
'job-source-mock2',
@@ -83,7 +85,7 @@ describe('stream handler', () => {
describe('showNotifications', () => {
it('show success', (done) => {
- const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock);
+ const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock, theme);
sh.showNotifications({
completed: [
{
@@ -104,7 +106,7 @@ describe('stream handler', () => {
});
it('show max length warning', (done) => {
- const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock);
+ const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock, theme);
sh.showNotifications({
completed: [
{
@@ -126,7 +128,7 @@ describe('stream handler', () => {
});
it('show csv formulas warning', (done) => {
- const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock);
+ const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock, theme);
sh.showNotifications({
completed: [
{
@@ -148,7 +150,7 @@ describe('stream handler', () => {
});
it('show failed job toast', (done) => {
- const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock);
+ const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock, theme);
sh.showNotifications({
completed: [],
failed: [
@@ -169,7 +171,7 @@ describe('stream handler', () => {
});
it('show multiple toast', (done) => {
- const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock);
+ const sh = new ReportingNotifierStreamHandler(notificationsMock, jobQueueClientMock, theme);
sh.showNotifications({
completed: [
{
diff --git a/x-pack/plugins/reporting/public/lib/stream_handler.ts b/x-pack/plugins/reporting/public/lib/stream_handler.ts
index 304b4fb73374d..27e220221156e 100644
--- a/x-pack/plugins/reporting/public/lib/stream_handler.ts
+++ b/x-pack/plugins/reporting/public/lib/stream_handler.ts
@@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
import * as Rx from 'rxjs';
import { catchError, map } from 'rxjs/operators';
-import { NotificationsSetup } from 'src/core/public';
+import { NotificationsSetup, ThemeServiceStart } from 'src/core/public';
import { JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY, JOB_STATUSES } from '../../common/constants';
import { JobId, JobSummary, JobSummarySet } from '../../common/types';
import {
@@ -37,7 +37,11 @@ function getReportStatus(src: Job): JobSummary {
}
export class ReportingNotifierStreamHandler {
- constructor(private notifications: NotificationsSetup, private apiClient: ReportingAPIClient) {}
+ constructor(
+ private notifications: NotificationsSetup,
+ private apiClient: ReportingAPIClient,
+ private theme: ThemeServiceStart
+ ) {}
/*
* Use Kibana Toast API to show our messages
@@ -54,7 +58,8 @@ export class ReportingNotifierStreamHandler {
getWarningFormulasToast(
job,
this.apiClient.getManagementLink,
- this.apiClient.getDownloadLink
+ this.apiClient.getDownloadLink,
+ this.theme
)
);
} else if (job.maxSizeReached) {
@@ -62,12 +67,18 @@ export class ReportingNotifierStreamHandler {
getWarningMaxSizeToast(
job,
this.apiClient.getManagementLink,
- this.apiClient.getDownloadLink
+ this.apiClient.getDownloadLink,
+ this.theme
)
);
} else {
this.notifications.toasts.addSuccess(
- getSuccessToast(job, this.apiClient.getManagementLink, this.apiClient.getDownloadLink)
+ getSuccessToast(
+ job,
+ this.apiClient.getManagementLink,
+ this.apiClient.getDownloadLink,
+ this.theme
+ )
);
}
}
@@ -76,7 +87,7 @@ export class ReportingNotifierStreamHandler {
for (const job of failedJobs) {
const errorText = await this.apiClient.getError(job.id);
this.notifications.toasts.addDanger(
- getFailureToast(errorText, job, this.apiClient.getManagementLink)
+ getFailureToast(errorText, job, this.apiClient.getManagementLink, this.theme)
);
}
return { completed: completedJobs, failed: failedJobs };
@@ -120,7 +131,8 @@ export class ReportingNotifierStreamHandler {
i18n.translate('xpack.reporting.publicNotifier.httpErrorMessage', {
defaultMessage: 'Could not check Reporting job status!',
}),
- err
+ err,
+ this.theme
)
); // prettier-ignore
window.console.error(err);
diff --git a/x-pack/plugins/reporting/public/notifier/general_error.tsx b/x-pack/plugins/reporting/public/notifier/general_error.tsx
index 141b7b49444b0..66fff4d00ceeb 100644
--- a/x-pack/plugins/reporting/public/notifier/general_error.tsx
+++ b/x-pack/plugins/reporting/public/notifier/general_error.tsx
@@ -8,10 +8,14 @@
import React, { Fragment } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiCallOut, EuiSpacer } from '@elastic/eui';
-import { ToastInput } from 'src/core/public';
+import { ThemeServiceStart, ToastInput } from 'src/core/public';
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
-export const getGeneralErrorToast = (errorText: string, err: Error): ToastInput => ({
+export const getGeneralErrorToast = (
+ errorText: string,
+ err: Error,
+ theme: ThemeServiceStart
+): ToastInput => ({
text: toMountPoint(
@@ -24,7 +28,8 @@ export const getGeneralErrorToast = (errorText: string, err: Error): ToastInput
id="xpack.reporting.publicNotifier.error.tryRefresh"
defaultMessage="Try refreshing the page."
/>
-
+ ,
+ { theme$: theme.theme$ }
),
iconType: undefined,
});
diff --git a/x-pack/plugins/reporting/public/notifier/job_failure.tsx b/x-pack/plugins/reporting/public/notifier/job_failure.tsx
index a9e7b78c7e12f..87fbc72d29ab8 100644
--- a/x-pack/plugins/reporting/public/notifier/job_failure.tsx
+++ b/x-pack/plugins/reporting/public/notifier/job_failure.tsx
@@ -9,14 +9,15 @@ import { EuiCallOut, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import React, { Fragment } from 'react';
-import { ToastInput } from 'src/core/public';
+import { ThemeServiceStart, ToastInput } from 'src/core/public';
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
import { JobSummary, ManagementLinkFn } from '../../common/types';
export const getFailureToast = (
errorText: string,
job: JobSummary,
- getManagmenetLink: ManagementLinkFn
+ getManagmenetLink: ManagementLinkFn,
+ theme: ThemeServiceStart
): ToastInput => {
return {
title: toMountPoint(
@@ -24,7 +25,8 @@ export const getFailureToast = (
id="xpack.reporting.publicNotifier.error.couldNotCreateReportTitle"
defaultMessage="Could not create report for {reportObjectType} '{reportObjectTitle}'."
values={{ reportObjectType: job.jobtype, reportObjectTitle: job.title }}
- />
+ />,
+ { theme$: theme.theme$ }
),
text: toMountPoint(
@@ -58,7 +60,8 @@ export const getFailureToast = (
}}
/>
-
+ ,
+ { theme$: theme.theme$ }
),
iconType: undefined,
'data-test-subj': 'completeReportFailure',
diff --git a/x-pack/plugins/reporting/public/notifier/job_success.tsx b/x-pack/plugins/reporting/public/notifier/job_success.tsx
index c1de9a7625858..f949c27f6fedb 100644
--- a/x-pack/plugins/reporting/public/notifier/job_success.tsx
+++ b/x-pack/plugins/reporting/public/notifier/job_success.tsx
@@ -7,7 +7,7 @@
import { FormattedMessage } from '@kbn/i18n-react';
import React, { Fragment } from 'react';
-import { ToastInput } from 'src/core/public';
+import { ThemeServiceStart, ToastInput } from 'src/core/public';
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
import { JobId, JobSummary } from '../../common/types';
import { DownloadButton } from './job_download_button';
@@ -16,14 +16,16 @@ import { ReportLink } from './report_link';
export const getSuccessToast = (
job: JobSummary,
getReportLink: () => string,
- getDownloadLink: (jobId: JobId) => string
+ getDownloadLink: (jobId: JobId) => string,
+ theme: ThemeServiceStart
): ToastInput => ({
title: toMountPoint(
+ />,
+ { theme$: theme.theme$ }
),
color: 'success',
text: toMountPoint(
@@ -32,7 +34,8 @@ export const getSuccessToast = (
-
+ ,
+ { theme$: theme.theme$ }
),
'data-test-subj': 'completeReportSuccess',
});
diff --git a/x-pack/plugins/reporting/public/notifier/job_warning_formulas.tsx b/x-pack/plugins/reporting/public/notifier/job_warning_formulas.tsx
index c835203813b86..08c87a40a829a 100644
--- a/x-pack/plugins/reporting/public/notifier/job_warning_formulas.tsx
+++ b/x-pack/plugins/reporting/public/notifier/job_warning_formulas.tsx
@@ -7,7 +7,7 @@
import { FormattedMessage } from '@kbn/i18n-react';
import React, { Fragment } from 'react';
-import { ToastInput } from 'src/core/public';
+import { ThemeServiceStart, ToastInput } from 'src/core/public';
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
import { JobId, JobSummary } from '../../common/types';
import { DownloadButton } from './job_download_button';
@@ -16,14 +16,16 @@ import { ReportLink } from './report_link';
export const getWarningFormulasToast = (
job: JobSummary,
getReportLink: () => string,
- getDownloadLink: (jobId: JobId) => string
+ getDownloadLink: (jobId: JobId) => string,
+ theme: ThemeServiceStart
): ToastInput => ({
title: toMountPoint(
+ />,
+ { theme$: theme.theme$ }
),
text: toMountPoint(
@@ -37,7 +39,8 @@ export const getWarningFormulasToast = (
-
+ ,
+ { theme$: theme.theme$ }
),
'data-test-subj': 'completeReportCsvFormulasWarning',
});
diff --git a/x-pack/plugins/reporting/public/notifier/job_warning_max_size.tsx b/x-pack/plugins/reporting/public/notifier/job_warning_max_size.tsx
index f7cc8e2219df9..629ac44adeae8 100644
--- a/x-pack/plugins/reporting/public/notifier/job_warning_max_size.tsx
+++ b/x-pack/plugins/reporting/public/notifier/job_warning_max_size.tsx
@@ -7,7 +7,7 @@
import { FormattedMessage } from '@kbn/i18n-react';
import React, { Fragment } from 'react';
-import { ToastInput } from 'src/core/public';
+import { ThemeServiceStart, ToastInput } from 'src/core/public';
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
import { JobId, JobSummary } from '../../common/types';
import { DownloadButton } from './job_download_button';
@@ -16,14 +16,16 @@ import { ReportLink } from './report_link';
export const getWarningMaxSizeToast = (
job: JobSummary,
getReportLink: () => string,
- getDownloadLink: (jobId: JobId) => string
+ getDownloadLink: (jobId: JobId) => string,
+ theme: ThemeServiceStart
): ToastInput => ({
title: toMountPoint(
+ />,
+ { theme$: theme.theme$ }
),
text: toMountPoint(
@@ -37,7 +39,8 @@ export const getWarningMaxSizeToast = (
-
+ ,
+ { theme$: theme.theme$ }
),
'data-test-subj': 'completeReportMaxSizeWarning',
});
diff --git a/x-pack/plugins/reporting/public/plugin.ts b/x-pack/plugins/reporting/public/plugin.ts
index b1f9b63e66cbe..77c8489bb8992 100644
--- a/x-pack/plugins/reporting/public/plugin.ts
+++ b/x-pack/plugins/reporting/public/plugin.ts
@@ -17,6 +17,7 @@ import {
NotificationsSetup,
Plugin,
PluginInitializerContext,
+ ThemeServiceStart,
} from 'src/core/public';
import type { ScreenshottingSetup } from '../../screenshotting/public';
import { CONTEXT_MENU_TRIGGER } from '../../../../src/plugins/embeddable/public';
@@ -56,13 +57,18 @@ function getStored(): JobId[] {
return sessionValue ? JSON.parse(sessionValue) : [];
}
-function handleError(notifications: NotificationsSetup, err: Error): Rx.Observable {
+function handleError(
+ notifications: NotificationsSetup,
+ err: Error,
+ theme: ThemeServiceStart
+): Rx.Observable {
notifications.toasts.addDanger(
getGeneralErrorToast(
i18n.translate('xpack.reporting.publicNotifier.pollingErrorMessage', {
defaultMessage: 'Reporting notifier error!',
}),
- err
+ err,
+ theme
)
);
window.console.error(err);
@@ -235,6 +241,7 @@ export class ReportingPublicPlugin
startServices$,
uiSettings,
usesUiCapabilities,
+ theme: core.theme,
})
);
@@ -246,6 +253,7 @@ export class ReportingPublicPlugin
startServices$,
uiSettings,
usesUiCapabilities,
+ theme: core.theme,
})
);
@@ -255,7 +263,7 @@ export class ReportingPublicPlugin
public start(core: CoreStart) {
const { notifications } = core;
const apiClient = this.getApiClient(core.http, core.uiSettings);
- const streamHandler = new StreamHandler(notifications, apiClient);
+ const streamHandler = new StreamHandler(notifications, apiClient, core.theme);
const interval = durationToNumber(this.config.poll.jobsRefresh.interval);
Rx.timer(0, interval)
.pipe(
@@ -264,7 +272,7 @@ export class ReportingPublicPlugin
filter((storedJobs) => storedJobs.length > 0), // stop the pipeline here if there are none pending
mergeMap((storedJobs) => streamHandler.findChangedStatusJobs(storedJobs)), // look up the latest status of all pending jobs on the server
mergeMap(({ completed, failed }) => streamHandler.showNotifications({ completed, failed })),
- catchError((err) => handleError(notifications, err))
+ catchError((err) => handleError(notifications, err, core.theme))
)
.subscribe();
diff --git a/x-pack/plugins/reporting/public/share_context_menu/index.ts b/x-pack/plugins/reporting/public/share_context_menu/index.ts
index 321a5a29281af..6a5dbf970e0b4 100644
--- a/x-pack/plugins/reporting/public/share_context_menu/index.ts
+++ b/x-pack/plugins/reporting/public/share_context_menu/index.ts
@@ -6,7 +6,7 @@
*/
import * as Rx from 'rxjs';
-import type { IUiSettingsClient, ToastsSetup } from 'src/core/public';
+import type { IUiSettingsClient, ThemeServiceSetup, ToastsSetup } from 'src/core/public';
import { CoreStart } from 'src/core/public';
import type { LayoutParams } from '../../../screenshotting/common';
import type { LicensingPluginSetup } from '../../../licensing/public';
@@ -19,6 +19,7 @@ export interface ExportPanelShareOpts {
license$: LicensingPluginSetup['license$']; // FIXME: 'license$' is deprecated
startServices$: Rx.Observable<[CoreStart, object, unknown]>;
usesUiCapabilities: boolean;
+ theme: ThemeServiceSetup;
}
export interface ReportingSharingData {
diff --git a/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx b/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx
index 8859d01e4fe9a..b264c96361122 100644
--- a/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx
+++ b/x-pack/plugins/reporting/public/share_context_menu/register_csv_reporting.tsx
@@ -21,6 +21,7 @@ export const ReportingCsvShareProvider = ({
license$,
startServices$,
usesUiCapabilities,
+ theme,
}: ExportPanelShareOpts) => {
let licenseToolTipContent = '';
let licenseHasCsvReporting = false;
@@ -96,6 +97,7 @@ export const ReportingCsvShareProvider = ({
objectId={objectId}
getJobParams={getJobParams}
onClose={onClose}
+ theme={theme}
/>
),
},
diff --git a/x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx b/x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx
index 610781f3b6ea0..3cc8cbacc7921 100644
--- a/x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx
+++ b/x-pack/plugins/reporting/public/share_context_menu/register_pdf_png_reporting.tsx
@@ -63,6 +63,7 @@ export const reportingScreenshotShareProvider = ({
license$,
startServices$,
usesUiCapabilities,
+ theme,
}: ExportPanelShareOpts) => {
let licenseToolTipContent = '';
let licenseDisabled = true;
@@ -156,6 +157,7 @@ export const reportingScreenshotShareProvider = ({
getJobParams={getJobParams(apiClient, jobProviderOptions, pngReportType)}
isDirty={isDirty}
onClose={onClose}
+ theme={theme}
/>
),
},
@@ -191,6 +193,7 @@ export const reportingScreenshotShareProvider = ({
getJobParams={getJobParams(apiClient, jobProviderOptions, pdfReportType)}
isDirty={isDirty}
onClose={onClose}
+ theme={theme}
/>
),
},
diff --git a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.test.tsx b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.test.tsx
index e9dd584e51f82..ef3e9940238c1 100644
--- a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.test.tsx
+++ b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.test.tsx
@@ -10,6 +10,7 @@ import { mountWithIntl } from '@kbn/test/jest';
import {
httpServiceMock,
notificationServiceMock,
+ themeServiceMock,
uiSettingsServiceMock,
} from 'src/core/public/mocks';
import { ReportingAPIClient } from '../../lib/reporting_api_client';
@@ -21,6 +22,8 @@ jest.mock('./constants', () => ({
}));
import * as constants from './constants';
+const theme = themeServiceMock.createSetupContract();
+
describe('ReportingPanelContent', () => {
const props: Partial = {
layoutId: 'super_cool_layout_id_X',
@@ -58,6 +61,7 @@ describe('ReportingPanelContent', () => {
apiClient={apiClient}
toasts={toasts}
uiSettings={uiSettings}
+ theme={theme}
{...props}
{...newProps}
/>
diff --git a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx
index 73ccbc2b13d75..e1fa1198cf1f8 100644
--- a/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx
+++ b/x-pack/plugins/reporting/public/share_context_menu/reporting_panel_content/reporting_panel_content.tsx
@@ -18,7 +18,7 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n-react';
import React, { Component, ReactElement } from 'react';
-import { IUiSettingsClient, ToastsSetup } from 'src/core/public';
+import { IUiSettingsClient, ThemeServiceSetup, ToastsSetup } from 'src/core/public';
import url from 'url';
import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public';
import {
@@ -46,6 +46,7 @@ export interface ReportingPanelProps {
options?: ReactElement | null;
isDirty?: boolean;
onClose?: () => void;
+ theme: ThemeServiceSetup;
}
export type Props = ReportingPanelProps & { intl: InjectedIntl };
@@ -291,7 +292,8 @@ class ReportingPanelContentUi extends Component {
),
}}
- />
+ />,
+ { theme$: this.props.theme.theme$ }
),
'data-test-subj': 'queueReportSuccess',
});
diff --git a/x-pack/plugins/reporting/public/share_context_menu/screen_capture_panel_content.test.tsx b/x-pack/plugins/reporting/public/share_context_menu/screen_capture_panel_content.test.tsx
index 7a2fa52d010e3..ebf741c79bd86 100644
--- a/x-pack/plugins/reporting/public/share_context_menu/screen_capture_panel_content.test.tsx
+++ b/x-pack/plugins/reporting/public/share_context_menu/screen_capture_panel_content.test.tsx
@@ -8,7 +8,7 @@
import { mount } from 'enzyme';
import React from 'react';
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
-import { coreMock } from 'src/core/public/mocks';
+import { coreMock, themeServiceMock } from 'src/core/public/mocks';
import { ReportingAPIClient } from '../lib/reporting_api_client';
import { ScreenCapturePanelContent } from './screen_capture_panel_content';
@@ -27,6 +27,8 @@ const getJobParamsDefault = () => ({
browserTimezone: 'America/New_York',
});
+const theme = themeServiceMock.createSetupContract();
+
test('ScreenCapturePanelContent renders the default view properly', () => {
const component = mount(
@@ -37,6 +39,7 @@ test('ScreenCapturePanelContent renders the default view properly', () => {
uiSettings={uiSettings}
toasts={coreSetup.notifications.toasts}
getJobParams={getJobParamsDefault}
+ theme={theme}
/>
);
@@ -56,6 +59,7 @@ test('ScreenCapturePanelContent properly renders a view with "canvas" layout opt
uiSettings={uiSettings}
toasts={coreSetup.notifications.toasts}
getJobParams={getJobParamsDefault}
+ theme={theme}
/>
);
@@ -75,6 +79,7 @@ test('ScreenCapturePanelContent allows POST URL to be copied when objectId is pr
toasts={coreSetup.notifications.toasts}
getJobParams={getJobParamsDefault}
objectId={'1234-5'}
+ theme={theme}
/>
);
@@ -93,6 +98,7 @@ test('ScreenCapturePanelContent does not allow POST URL to be copied when object
uiSettings={uiSettings}
toasts={coreSetup.notifications.toasts}
getJobParams={getJobParamsDefault}
+ theme={theme}
/>
);
@@ -111,6 +117,7 @@ test('ScreenCapturePanelContent properly renders a view with "print" layout opti
uiSettings={uiSettings}
toasts={coreSetup.notifications.toasts}
getJobParams={getJobParamsDefault}
+ theme={theme}
/>
);
@@ -130,6 +137,7 @@ test('ScreenCapturePanelContent decorated job params are visible in the POST URL
uiSettings={uiSettings}
toasts={coreSetup.notifications.toasts}
getJobParams={getJobParamsDefault}
+ theme={theme}
/>
);
diff --git a/x-pack/plugins/reporting/public/shared/get_shared_components.tsx b/x-pack/plugins/reporting/public/shared/get_shared_components.tsx
index b08036e8b1c80..0906bf85c9538 100644
--- a/x-pack/plugins/reporting/public/shared/get_shared_components.tsx
+++ b/x-pack/plugins/reporting/public/shared/get_shared_components.tsx
@@ -35,6 +35,7 @@ export function getSharedComponents(core: CoreSetup, apiClient: ReportingAPIClie
apiClient={apiClient}
toasts={core.notifications.toasts}
uiSettings={core.uiSettings}
+ theme={core.theme}
{...props}
/>
);
@@ -48,6 +49,7 @@ export function getSharedComponents(core: CoreSetup, apiClient: ReportingAPIClie
apiClient={apiClient}
toasts={core.notifications.toasts}
uiSettings={core.uiSettings}
+ theme={core.theme}
{...props}
/>
);
@@ -61,6 +63,7 @@ export function getSharedComponents(core: CoreSetup, apiClient: ReportingAPIClie
apiClient={apiClient}
toasts={core.notifications.toasts}
uiSettings={core.uiSettings}
+ theme={core.theme}
{...props}
/>
);
diff --git a/x-pack/plugins/reporting/tsconfig.json b/x-pack/plugins/reporting/tsconfig.json
index 66d528cd83a22..24db825856627 100644
--- a/x-pack/plugins/reporting/tsconfig.json
+++ b/x-pack/plugins/reporting/tsconfig.json
@@ -6,18 +6,14 @@
"declaration": true,
"declarationMap": true
},
- "include": [
- "common/**/*",
- "public/**/*",
- "server/**/*",
- "../../../typings/**/*"
- ],
+ "include": ["common/**/*", "public/**/*", "server/**/*", "../../../typings/**/*"],
"references": [
{ "path": "../../../src/core/tsconfig.json" },
- { "path": "../../../src/plugins/data/tsconfig.json"},
+ { "path": "../../../src/plugins/data/tsconfig.json" },
{ "path": "../../../src/plugins/discover/tsconfig.json" },
{ "path": "../../../src/plugins/embeddable/tsconfig.json" },
{ "path": "../../../src/plugins/kibana_react/tsconfig.json" },
+ { "path": "../../../src/plugins/kibana_utils/tsconfig.json" },
{ "path": "../../../src/plugins/management/tsconfig.json" },
{ "path": "../../../src/plugins/screenshot_mode/tsconfig.json" },
{ "path": "../../../src/plugins/share/tsconfig.json" },
@@ -29,6 +25,6 @@
{ "path": "../licensing/tsconfig.json" },
{ "path": "../screenshotting/tsconfig.json" },
{ "path": "../security/tsconfig.json" },
- { "path": "../spaces/tsconfig.json" },
+ { "path": "../spaces/tsconfig.json" }
]
}
diff --git a/x-pack/plugins/runtime_fields/README.md b/x-pack/plugins/runtime_fields/README.md
index eb7b31e6e1154..9c0e0e03f2fe5 100644
--- a/x-pack/plugins/runtime_fields/README.md
+++ b/x-pack/plugins/runtime_fields/README.md
@@ -72,7 +72,7 @@ interface RuntimeField {
type: RuntimeType; // 'long' | 'boolean' ...
script: {
source: string;
- }
+ };
}
```
@@ -103,8 +103,8 @@ interface Context {
The runtime field editor is also exported as static React component that you can import into your components. The editor is exported in 2 flavours:
-* As the content of a `` (it contains a flyout header and footer)
-* As a standalone component that you can inline anywhere
+- As the content of a `` (it contains a flyout header and footer)
+- As a standalone component that you can inline anywhere
**Note:** The runtime field editor uses the `` that has a dependency on the `Provider` from the `"kibana_react"` plugin. If your app is not already wrapped by this provider you will need to add it at least around the runtime field editor. You can see an example in the ["Using the core.overlays.openFlyout()"](#using-the-coreoverlaysopenflyout) example below.
@@ -118,7 +118,7 @@ import { RuntimeFieldEditorFlyoutContent, RuntimeField } from '../runtime_fields
const MyComponent = () => {
const { docLinksStart } = useCoreContext(); // access the core start service
const [isFlyoutVisilbe, setIsFlyoutVisible] = useState(false);
-
+
const saveRuntimeField = useCallback((field: RuntimeField) => {
// Do something with the field
}, []);
@@ -139,7 +139,7 @@ const MyComponent = () => {
)}
>
- )
+ )
}
```
@@ -157,11 +157,11 @@ import { RuntimeFieldEditorFlyoutContent, RuntimeField } from '../runtime_fields
const MyComponent = () => {
// Access the core start service
- const { docLinksStart, overlays, uiSettings } = useCoreContext();
+ const { docLinksStart, theme, overlays, uiSettings } = useCoreContext();
const flyoutEditor = useRef(null);
const { openFlyout } = overlays;
-
+
const saveRuntimeField = useCallback((field: RuntimeField) => {
// Do something with the field
}, []);
@@ -179,7 +179,8 @@ const MyComponent = () => {
defaultValue={defaultRuntimeField}
ctx={/*optional context object -- see section above*/}
/>
-
+ ,
+ { theme$: theme.theme$ }
)
);
}, [openFlyout, saveRuntimeField, uiSettings]);
@@ -188,7 +189,7 @@ const MyComponent = () => {
<>
Create field
>
- )
+ )
}
```
@@ -208,7 +209,7 @@ const MyComponent = () => {
});
const { submit, isValid: isFormValid, isSubmitted } = runtimeFieldFormState;
-
+
const saveRuntimeField = useCallback(async () => {
const { isValid, data } = await submit();
if (isValid) {
@@ -233,6 +234,6 @@ const MyComponent = () => {
Save field
>
- )
+ )
}
-```
\ No newline at end of file
+```
diff --git a/x-pack/plugins/runtime_fields/public/load_editor.tsx b/x-pack/plugins/runtime_fields/public/load_editor.tsx
index 0cea90f33a54d..6aec33b90466f 100644
--- a/x-pack/plugins/runtime_fields/public/load_editor.tsx
+++ b/x-pack/plugins/runtime_fields/public/load_editor.tsx
@@ -22,7 +22,7 @@ export const getRuntimeFieldEditorLoader =
(coreSetup: CoreSetup) => async (): Promise => {
const { RuntimeFieldEditorFlyoutContent } = await import('./components');
const [core] = await coreSetup.getStartServices();
- const { uiSettings, overlays, docLinks } = core;
+ const { uiSettings, theme, overlays, docLinks } = core;
const { Provider: KibanaReactContextProvider } = createKibanaReactContext({ uiSettings });
let overlayRef: OverlayRef | null = null;
@@ -50,7 +50,8 @@ export const getRuntimeFieldEditorLoader =
defaultValue={defaultValue}
ctx={ctx}
/>
-
+ ,
+ { theme$: theme.theme$ }
)
);
diff --git a/x-pack/plugins/runtime_fields/public/plugin.test.ts b/x-pack/plugins/runtime_fields/public/plugin.test.ts
index 0f72d99ec5d4f..fc36eecc12f0a 100644
--- a/x-pack/plugins/runtime_fields/public/plugin.test.ts
+++ b/x-pack/plugins/runtime_fields/public/plugin.test.ts
@@ -6,7 +6,7 @@
*/
import { CoreSetup } from 'src/core/public';
-import { coreMock } from 'src/core/public/mocks';
+import { coreMock, themeServiceMock } from 'src/core/public/mocks';
jest.mock('../../../../src/plugins/kibana_react/public', () => {
const original = jest.requireActual('../../../../src/plugins/kibana_react/public');
@@ -52,6 +52,7 @@ describe('RuntimeFieldsPlugin', () => {
openFlyout,
},
uiSettings: {},
+ theme: themeServiceMock.createStartContract(),
};
coreSetup.getStartServices = async () => [mockCore] as any;
const setupApi = await plugin.setup(coreSetup, {});