mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
add KibanaThemeProvider support for kibana-app-services (#122370)
add KibanaThemeProvider support for kibana-app-services
This commit is contained in:
parent
f1f35660f0
commit
6dc31d768d
92 changed files with 718 additions and 233 deletions
|
@ -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}
|
||||
/>
|
||||
</presentationUtil.ContextProvider>
|
||||
</KibanaContextProvider>
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -297,6 +297,7 @@ export const DashboardListing = ({
|
|||
listingLimit,
|
||||
tableColumns,
|
||||
}}
|
||||
theme={core.theme}
|
||||
>
|
||||
<DashboardUnsavedListing
|
||||
redirectTo={redirectTo}
|
||||
|
|
|
@ -161,6 +161,7 @@ export function DashboardTopNav({
|
|||
overlays: core.overlays,
|
||||
SavedObjectFinder: getSavedObjectFinder(core.savedObjects, uiSettings),
|
||||
reportUiCounter: usageCollection?.reportUiCounter,
|
||||
theme: core.theme,
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
@ -171,6 +172,7 @@ export function DashboardTopNav({
|
|||
core.notifications,
|
||||
core.savedObjects,
|
||||
core.overlays,
|
||||
core.theme,
|
||||
uiSettings,
|
||||
usageCollection,
|
||||
]);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ThemeServiceSetup } from 'kibana/public';
|
||||
import { toMountPoint } from '../../../kibana_react/public';
|
||||
import { Action, createAction, IncompatibleActionError } from '../../../ui_actions/public';
|
||||
import { getOverlays, getIndexPatterns } from '../services';
|
||||
|
@ -32,7 +33,8 @@ async function isCompatible(context: ApplyGlobalFilterActionContext) {
|
|||
|
||||
export function createFilterAction(
|
||||
filterManager: FilterManager,
|
||||
timeFilter: TimefilterContract
|
||||
timeFilter: TimefilterContract,
|
||||
theme: ThemeServiceSetup
|
||||
): Action {
|
||||
return createAction({
|
||||
type: ACTION_GLOBAL_APPLY_FILTER,
|
||||
|
@ -77,7 +79,8 @@ export function createFilterAction(
|
|||
overlay.close();
|
||||
resolve(filterSelection);
|
||||
}
|
||||
)
|
||||
),
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
{
|
||||
'data-test-subj': 'test',
|
||||
|
|
|
@ -27,6 +27,7 @@ import {
|
|||
setOverlays,
|
||||
setSearchService,
|
||||
setUiSettings,
|
||||
setTheme,
|
||||
} from './services';
|
||||
import { createSearchBar } from './ui/search_bar/create_search_bar';
|
||||
import {
|
||||
|
@ -82,6 +83,7 @@ export class DataPublicPlugin
|
|||
const startServices = createStartServicesGetter(core.getStartServices);
|
||||
|
||||
this.usageCollection = usageCollection;
|
||||
setTheme(core.theme);
|
||||
|
||||
const searchService = this.searchService.setup(core, {
|
||||
bfetch,
|
||||
|
@ -98,7 +100,7 @@ export class DataPublicPlugin
|
|||
|
||||
uiActions.registerTrigger(applyFilterTrigger);
|
||||
uiActions.registerAction(
|
||||
createFilterAction(queryService.filterManager, queryService.timefilter.timefilter)
|
||||
createFilterAction(queryService.filterManager, queryService.timefilter.timefilter, core.theme)
|
||||
);
|
||||
|
||||
inspector.registerView(
|
||||
|
|
|
@ -13,6 +13,7 @@ import { handleResponse } from './handle_response';
|
|||
import { notificationServiceMock } from '../../../../../core/public/notifications/notifications_service.mock';
|
||||
import { setNotifications } from '../../services';
|
||||
import { IKibanaSearchResponse } from 'src/plugins/data/common';
|
||||
import { themeServiceMock } from 'src/core/public/mocks';
|
||||
|
||||
jest.mock('@kbn/i18n', () => {
|
||||
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<any>;
|
||||
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<any>;
|
||||
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<any>;
|
||||
const result = handleResponse(request, response);
|
||||
const result = handleResponse(request, response, theme);
|
||||
expect(result).toBe(response);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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}
|
||||
<EuiSpacer size="s" />
|
||||
<ShardFailureOpenModalButton request={request.body} response={rawResponse} title={title} />
|
||||
</>
|
||||
<ShardFailureOpenModalButton
|
||||
request={request.body}
|
||||
response={rawResponse}
|
||||
theme={theme}
|
||||
title={title}
|
||||
/>
|
||||
</>,
|
||||
{ theme$: theme.theme$ }
|
||||
);
|
||||
|
||||
getNotifications().toasts.addWarning({ title, text });
|
||||
|
|
|
@ -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(),
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -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<ISearchSetup, ISearchStart> {
|
|||
constructor(private initializerContext: PluginInitializerContext<ConfigSchema>) {}
|
||||
|
||||
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<ISearchSetup, ISearchStart> {
|
|||
startServices: getStartServices(),
|
||||
usageCollector: this.usageCollector!,
|
||||
session: this.sessionService,
|
||||
theme,
|
||||
});
|
||||
|
||||
expressions.registerFunction(
|
||||
|
@ -173,7 +174,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
}
|
||||
|
||||
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<ISearchSetup, ISearchStart> {
|
|||
const searchSourceDependencies: SearchSourceDependencies = {
|
||||
getConfig: uiSettings.get.bind(uiSettings),
|
||||
search,
|
||||
onResponse: handleResponse,
|
||||
onResponse: (request: SearchRequest, response: IKibanaSearchResponse) =>
|
||||
handleResponse(request, response, theme),
|
||||
};
|
||||
|
||||
return {
|
||||
|
|
|
@ -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<DataPublicPluginStart['search']>('Search');
|
||||
|
||||
export const [getTheme, setTheme] = createGetterSetter<ThemeServiceStart>('Theme');
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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<IIndexPattern | string>;
|
||||
|
@ -487,7 +488,8 @@ export default class QueryStringInputUI extends PureComponent<Props, State> {
|
|||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
</div>,
|
||||
{ theme$: getTheme().theme$ }
|
||||
),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
<ShardFailureOpenModalButton
|
||||
request={shardFailureRequest}
|
||||
response={shardFailureResponse}
|
||||
theme={theme}
|
||||
title="test"
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -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<any>;
|
||||
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',
|
||||
|
|
|
@ -79,7 +79,8 @@ export const getEditorOpener =
|
|||
requireTimestampField={requireTimestampField}
|
||||
/>
|
||||
</I18nProvider>
|
||||
</KibanaReactContextProvider>
|
||||
</KibanaReactContextProvider>,
|
||||
{ theme$: core.theme.theme$ }
|
||||
),
|
||||
{
|
||||
hideCloseButton: true,
|
||||
|
|
|
@ -75,7 +75,8 @@ export const getFieldDeleteModalOpener =
|
|||
fieldsToDelete={fieldsToDelete}
|
||||
closeModal={closeModal}
|
||||
confirmDelete={onConfirmDelete}
|
||||
/>
|
||||
/>,
|
||||
{ theme$: core.theme.theme$ }
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -128,7 +128,8 @@ export const getFieldEditorOpener =
|
|||
fieldFormats={fieldFormats}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
</KibanaReactContextProvider>
|
||||
</KibanaReactContextProvider>,
|
||||
{ theme$: core.theme.theme$ }
|
||||
),
|
||||
{
|
||||
className: euiFlyoutClassname,
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
@ -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<IndexedFieldProps> {
|
|||
<span>
|
||||
{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
|
||||
)
|
||||
: ''}
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -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<IndexedFieldsTableProps, IndexedFieldsTabl
|
|||
editField={(field) => this.props.helpers.editField(field.name)}
|
||||
deleteField={(fieldName) => this.props.helpers.deleteField(fieldName)}
|
||||
openModal={this.props.openModal}
|
||||
theme={this.props.theme}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -80,7 +80,7 @@ export function Tabs({
|
|||
location,
|
||||
refreshFields,
|
||||
}: TabsProps) {
|
||||
const { application, uiSettings, docLinks, dataViewFieldEditor, overlays } =
|
||||
const { application, uiSettings, docLinks, dataViewFieldEditor, overlays, theme } =
|
||||
useKibana<IndexPatternManagmentContext>().services;
|
||||
const [fieldFilter, setFieldFilter] = useState<string>('');
|
||||
const [indexedFieldTypeFilter, setIndexedFieldTypeFilter] = useState<string>('');
|
||||
|
@ -236,6 +236,7 @@ export function Tabs({
|
|||
getFieldInfo,
|
||||
}}
|
||||
openModal={overlays.openModal}
|
||||
theme={theme}
|
||||
/>
|
||||
)}
|
||||
</DeleteRuntimeFieldProvider>
|
||||
|
@ -295,6 +296,7 @@ export function Tabs({
|
|||
DeleteRuntimeFieldProvider,
|
||||
refreshFields,
|
||||
overlays,
|
||||
theme,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -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(
|
||||
<KibanaContextProvider services={deps}>
|
||||
<I18nProvider>
|
||||
<Router history={params.history}>
|
||||
<Switch>
|
||||
<Route path={['/create']}>
|
||||
<IndexPatternTableWithRouter canSave={canSave} showCreateDialog={true} />
|
||||
</Route>
|
||||
<Route path={['/dataView/:id/field/:fieldName', '/dataView/:id/create-field/']}>
|
||||
<CreateEditFieldContainer />
|
||||
</Route>
|
||||
<Route path={['/dataView/:id']}>
|
||||
<EditIndexPatternContainer />
|
||||
</Route>
|
||||
<Redirect path={'/patterns*'} to={'dataView*'} />
|
||||
<Route path={['/']}>
|
||||
<IndexPatternTableWithRouter canSave={canSave} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</I18nProvider>
|
||||
<KibanaThemeProvider theme$={theme.theme$}>
|
||||
<I18nProvider>
|
||||
<Router history={params.history}>
|
||||
<Switch>
|
||||
<Route path={['/create']}>
|
||||
<IndexPatternTableWithRouter canSave={canSave} showCreateDialog={true} />
|
||||
</Route>
|
||||
<Route path={['/dataView/:id/field/:fieldName', '/dataView/:id/create-field/']}>
|
||||
<CreateEditFieldContainer />
|
||||
</Route>
|
||||
<Route path={['/dataView/:id']}>
|
||||
<EditIndexPatternContainer />
|
||||
</Route>
|
||||
<Redirect path={'/patterns*'} to={'dataView*'} />
|
||||
<Route path={['/']}>
|
||||
<IndexPatternTableWithRouter canSave={canSave} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</I18nProvider>
|
||||
</KibanaThemeProvider>
|
||||
</KibanaContextProvider>,
|
||||
params.element
|
||||
);
|
||||
|
|
|
@ -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(<EuiCallOut color="warning" iconType="iInCircle" title={bannerMessage} />)
|
||||
toMountPoint(<EuiCallOut color="warning" iconType="iInCircle" title={bannerMessage} />, {
|
||||
theme$: theme.theme$,
|
||||
})
|
||||
);
|
||||
|
||||
// hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around
|
||||
|
|
|
@ -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),
|
||||
});
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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<EmbeddableInput, EmbeddableOutpu
|
|||
public render(dom: HTMLElement) {
|
||||
const title = typeof this.error === 'string' ? this.error : this.error.message;
|
||||
this.dom = dom;
|
||||
ReactDOM.render(
|
||||
// @ts-ignore
|
||||
let theme;
|
||||
try {
|
||||
theme = getTheme();
|
||||
} catch (err) {
|
||||
theme = {};
|
||||
}
|
||||
const node = (
|
||||
<div className="embPanel__error embPanel__content" data-test-subj="embeddableStackError">
|
||||
<EuiText color="subdued" size="xs">
|
||||
<EuiIcon type="alert" color="danger" />
|
||||
|
@ -49,9 +55,16 @@ export class ErrorEmbeddable extends Embeddable<EmbeddableInput, EmbeddableOutpu
|
|||
data-test-subj="errorMessageMarkdown"
|
||||
/>
|
||||
</EuiText>
|
||||
</div>,
|
||||
dom
|
||||
</div>
|
||||
);
|
||||
const content =
|
||||
theme && theme.theme$ ? (
|
||||
<KibanaThemeProvider theme$={theme.theme$}>{node}</KibanaThemeProvider>
|
||||
) : (
|
||||
node
|
||||
);
|
||||
|
||||
ReactDOM.render(content, dom);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
|
|
|
@ -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<string, Action>();
|
||||
const triggerRegistry = new Map<string, Trigger>();
|
||||
|
@ -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}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
@ -191,6 +193,7 @@ const renderInEditModeAndOpenContextMenu = async (
|
|||
application={applicationMock}
|
||||
inspector={inspector}
|
||||
SavedObjectFinder={() => null}
|
||||
theme={theme}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
@ -298,6 +301,7 @@ test('HelloWorldContainer in edit mode shows edit mode actions', async () => {
|
|||
application={applicationMock}
|
||||
inspector={inspector}
|
||||
SavedObjectFinder={() => null}
|
||||
theme={theme}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
@ -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}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
@ -497,6 +504,7 @@ test('Check when hide header option is false', async () => {
|
|||
inspector={inspector}
|
||||
SavedObjectFinder={() => null}
|
||||
hideHeader={false}
|
||||
theme={theme}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
@ -535,6 +543,7 @@ test('Check when hide header option is true', async () => {
|
|||
inspector={inspector}
|
||||
SavedObjectFinder={() => null}
|
||||
hideHeader={true}
|
||||
theme={theme}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
@ -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}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
|
|
@ -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<Props, State> {
|
|||
) {
|
||||
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<Props, State> {
|
|||
resolve({ title, hideTitle });
|
||||
}}
|
||||
cancel={() => session.close()}
|
||||
/>
|
||||
/>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
{
|
||||
'data-test-subj': 'customizePanel',
|
||||
|
@ -373,13 +374,16 @@ export class EmbeddablePanel extends React.Component<Props, State> {
|
|||
// 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(),
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<ActionContext> {
|
|||
private readonly overlays: OverlayStart,
|
||||
private readonly notifications: NotificationsStart,
|
||||
private readonly SavedObjectFinder: React.ComponentType<any>,
|
||||
private readonly theme: ThemeServiceStart,
|
||||
private readonly reportUiCounter?: UsageCollectionStart['reportUiCounter']
|
||||
) {}
|
||||
|
||||
|
@ -63,6 +64,7 @@ export class AddPanelAction implements Action<ActionContext> {
|
|||
notifications: this.notifications,
|
||||
SavedObjectFinder: this.SavedObjectFinder,
|
||||
reportUiCounter: this.reportUiCounter,
|
||||
theme: this.theme,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<any>;
|
||||
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',
|
||||
|
|
|
@ -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<any>;
|
||||
}
|
||||
|
||||
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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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<EmbeddableSetup, Embeddabl
|
|||
constructor(initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public setup(core: CoreSetup, { uiActions }: EmbeddableSetupDependencies) {
|
||||
setTheme(core.theme);
|
||||
bootstrap(uiActions);
|
||||
|
||||
return {
|
||||
|
@ -184,6 +186,7 @@ export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, Embeddabl
|
|||
inspector={inspector}
|
||||
SavedObjectFinder={getSavedObjectFinder(core.savedObjects, core.uiSettings)}
|
||||
containerContext={containerContext}
|
||||
theme={core.theme}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
12
src/plugins/embeddable/public/services.ts
Normal file
12
src/plugins/embeddable/public/services.ts
Normal file
|
@ -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<ThemeServiceSetup>('Theme');
|
|
@ -106,7 +106,8 @@ export class InspectorPublicPlugin implements Plugin<Setup, Start> {
|
|||
uiSettings: core.uiSettings,
|
||||
share: startDeps.share,
|
||||
}}
|
||||
/>
|
||||
/>,
|
||||
{ theme$: core.theme.theme$ }
|
||||
),
|
||||
{
|
||||
'data-test-subj': 'inspectorPanel',
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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<V> {
|
|||
*/
|
||||
tableCaption: string;
|
||||
searchFilters?: SearchFilterConfig[];
|
||||
theme: ThemeServiceStart;
|
||||
}
|
||||
|
||||
export interface TableListViewState<V> {
|
||||
|
@ -177,7 +178,8 @@ class TableListView<V extends {}> 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}`,
|
||||
});
|
||||
|
|
|
@ -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<KibanaThemeProviderProps> = ({ theme$, children }) => {
|
||||
const theme = useObservable(theme$, defaultTheme);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(<ErrorRenderer>{error.message}</ErrorRenderer>, element);
|
||||
ReactDOM.render(
|
||||
<KibanaThemeProvider theme$={theme.theme$}>
|
||||
<ErrorRenderer>{error.message}</ErrorRenderer>
|
||||
</KibanaThemeProvider>,
|
||||
element
|
||||
);
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
},
|
||||
});
|
||||
|
|
9
src/plugins/kibana_utils/public/theme/index.ts
Normal file
9
src/plugins/kibana_utils/public/theme/index.ts
Normal file
|
@ -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';
|
|
@ -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<typeof useEuiTheme> | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
euiTheme = undefined;
|
||||
});
|
||||
|
||||
const flushPromises = async () => {
|
||||
await new Promise<void>(async (resolve, reject) => {
|
||||
try {
|
||||
setImmediate(() => resolve());
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const InnerComponent: FC = () => {
|
||||
const theme = useEuiTheme();
|
||||
useEffect(() => {
|
||||
euiTheme = theme;
|
||||
}, [theme]);
|
||||
return <div>foo</div>;
|
||||
};
|
||||
|
||||
const refresh = async (wrapper: ReactWrapper<unknown>) => {
|
||||
await act(async () => {
|
||||
await flushPromises();
|
||||
wrapper.update();
|
||||
});
|
||||
};
|
||||
|
||||
it('exposes the EUI theme provider', async () => {
|
||||
const coreTheme: CoreTheme = { darkMode: true };
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<KibanaThemeProvider theme$={of(coreTheme)}>
|
||||
<InnerComponent />
|
||||
</KibanaThemeProvider>
|
||||
);
|
||||
|
||||
await refresh(wrapper);
|
||||
|
||||
expect(euiTheme!.colorMode).toEqual('DARK');
|
||||
});
|
||||
|
||||
it('propagates changes of the coreTheme observable', async () => {
|
||||
const coreTheme$ = new BehaviorSubject<CoreTheme>({ darkMode: true });
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<KibanaThemeProvider theme$={coreTheme$}>
|
||||
<InnerComponent />
|
||||
</KibanaThemeProvider>
|
||||
);
|
||||
|
||||
await refresh(wrapper);
|
||||
|
||||
expect(euiTheme!.colorMode).toEqual('DARK');
|
||||
|
||||
await act(async () => {
|
||||
coreTheme$.next({ darkMode: false });
|
||||
});
|
||||
|
||||
await refresh(wrapper);
|
||||
|
||||
expect(euiTheme!.colorMode).toEqual('LIGHT');
|
||||
});
|
||||
});
|
|
@ -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<CoreTheme>;
|
||||
}
|
||||
|
||||
const defaultTheme: CoreTheme = {
|
||||
darkMode: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Copied from the `kibana_react` plugin, to avoid cyclical dependency
|
||||
*/
|
||||
export const KibanaThemeProvider: FC<KibanaThemeProviderProps> = ({ theme$, children }) => {
|
||||
const theme = useObservable(theme$, defaultTheme);
|
||||
const colorMode = useMemo(() => getColorMode(theme), [theme]);
|
||||
return <EuiThemeProvider colorMode={colorMode}>{children}</EuiThemeProvider>;
|
||||
};
|
19
src/plugins/kibana_utils/public/theme/utils.test.ts
Normal file
19
src/plugins/kibana_utils/public/theme/utils.test.ts
Normal file
|
@ -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');
|
||||
});
|
||||
});
|
19
src/plugins/kibana_utils/public/theme/utils.ts
Normal file
19
src/plugins/kibana_utils/public/theme/utils.ts
Normal file
|
@ -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;
|
||||
};
|
|
@ -14,7 +14,5 @@
|
|||
"index.ts",
|
||||
"../../../typings/**/*"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "../../core/tsconfig.json" }
|
||||
]
|
||||
"references": [{ "path": "../../core/tsconfig.json" }]
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
"githubTeam": "kibana-app-services"
|
||||
},
|
||||
"description": "Adds URL Service and sharing capabilities to Kibana",
|
||||
"requiredBundles": ["kibanaUtils"],
|
||||
"requiredBundles": ["kibanaReact", "kibanaUtils"],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
|
@ -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 = (
|
||||
<I18nProvider>
|
||||
<EuiWrappingPopover
|
||||
id="sharePopover"
|
||||
button={anchorElement}
|
||||
isOpen={true}
|
||||
closePopover={this.onClose}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downLeft"
|
||||
>
|
||||
<ShareContextMenu
|
||||
allowEmbed={allowEmbed}
|
||||
allowShortUrl={allowShortUrl}
|
||||
objectId={objectId}
|
||||
objectType={objectType}
|
||||
shareMenuItems={menuItems}
|
||||
sharingData={sharingData}
|
||||
shareableUrl={shareableUrl}
|
||||
onClose={this.onClose}
|
||||
post={post}
|
||||
basePath={basePath}
|
||||
embedUrlParamExtensions={embedUrlParamExtensions}
|
||||
anonymousAccess={anonymousAccess}
|
||||
showPublicUrlSwitch={showPublicUrlSwitch}
|
||||
/>
|
||||
</EuiWrappingPopover>
|
||||
<KibanaThemeProvider theme$={theme.theme$}>
|
||||
<EuiWrappingPopover
|
||||
id="sharePopover"
|
||||
button={anchorElement}
|
||||
isOpen={true}
|
||||
closePopover={this.onClose}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downLeft"
|
||||
>
|
||||
<ShareContextMenu
|
||||
allowEmbed={allowEmbed}
|
||||
allowShortUrl={allowShortUrl}
|
||||
objectId={objectId}
|
||||
objectType={objectType}
|
||||
shareMenuItems={menuItems}
|
||||
sharingData={sharingData}
|
||||
shareableUrl={shareableUrl}
|
||||
onClose={this.onClose}
|
||||
post={post}
|
||||
basePath={basePath}
|
||||
embedUrlParamExtensions={embedUrlParamExtensions}
|
||||
anonymousAccess={anonymousAccess}
|
||||
showPublicUrlSwitch={showPublicUrlSwitch}
|
||||
/>
|
||||
</EuiWrappingPopover>
|
||||
</KibanaThemeProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
ReactDOM.render(element, this.container);
|
||||
|
|
|
@ -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<RedirectManager, 'error$'>;
|
||||
theme: ThemeServiceSetup;
|
||||
}
|
||||
|
||||
export const Page: React.FC<PageProps> = ({ manager }) => {
|
||||
export const Page: React.FC<PageProps> = ({ manager, theme }) => {
|
||||
const error = useObservable(manager.error$);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<EuiPageTemplate
|
||||
template="centeredContent"
|
||||
pageContentProps={{
|
||||
color: 'danger',
|
||||
}}
|
||||
>
|
||||
<Error error={error} />
|
||||
</EuiPageTemplate>
|
||||
<KibanaThemeProvider theme$={theme.theme$}>
|
||||
<EuiPageTemplate
|
||||
template="centeredContent"
|
||||
pageContentProps={{
|
||||
color: 'danger',
|
||||
}}
|
||||
>
|
||||
<Error error={error} />
|
||||
</EuiPageTemplate>
|
||||
</KibanaThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiPageTemplate
|
||||
template="centeredContent"
|
||||
pageContentProps={{
|
||||
color: 'primary',
|
||||
}}
|
||||
>
|
||||
<Spinner />
|
||||
</EuiPageTemplate>
|
||||
<KibanaThemeProvider theme$={theme.theme$}>
|
||||
<EuiPageTemplate
|
||||
template="centeredContent"
|
||||
pageContentProps={{
|
||||
color: 'primary',
|
||||
}}
|
||||
>
|
||||
<Spinner />
|
||||
</EuiPageTemplate>
|
||||
</KibanaThemeProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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" }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
<EuiPopover
|
||||
className="embPanel__optionsMenuPopover"
|
||||
button={container}
|
||||
isOpen={true}
|
||||
closePopover={onClose}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downRight"
|
||||
>
|
||||
<EuiContextMenu
|
||||
initialPanelId="mainMenu"
|
||||
panels={panels}
|
||||
data-test-subj={props['data-test-subj']}
|
||||
/>
|
||||
</EuiPopover>,
|
||||
<KibanaThemeProvider theme$={getTheme().theme$}>
|
||||
<EuiPopover
|
||||
className="embPanel__optionsMenuPopover"
|
||||
button={container}
|
||||
isOpen={true}
|
||||
closePopover={onClose}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downRight"
|
||||
>
|
||||
<EuiContextMenu
|
||||
initialPanelId="mainMenu"
|
||||
panels={panels}
|
||||
data-test-subj={props['data-test-subj']}
|
||||
/>
|
||||
</EuiPopover>
|
||||
</KibanaThemeProvider>,
|
||||
container
|
||||
);
|
||||
|
||||
|
|
|
@ -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<UiActionsSetup, UiActionsStart> {
|
|||
constructor(initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public setup(core: CoreSetup): UiActionsSetup {
|
||||
setTheme(core.theme);
|
||||
this.service.registerTrigger(rowClickTrigger);
|
||||
this.service.registerTrigger(visualizeFieldTrigger);
|
||||
this.service.registerTrigger(visualizeGeoFieldTrigger);
|
||||
|
|
12
src/plugins/ui_actions/public/services.ts
Normal file
12
src/plugins/ui_actions/public/services.ts
Normal file
|
@ -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<ThemeServiceSetup>('Theme');
|
|
@ -42,6 +42,7 @@ export const VisualizeListing = () => {
|
|||
visualizeCapabilities,
|
||||
dashboardCapabilities,
|
||||
kbnUrlStateStorage,
|
||||
theme,
|
||||
},
|
||||
} = useKibana<VisualizeServices>();
|
||||
const { pathname } = useLocation();
|
||||
|
@ -201,6 +202,7 @@ export const VisualizeListing = () => {
|
|||
})}
|
||||
toastNotifications={toastNotifications}
|
||||
searchFilters={searchFilters}
|
||||
theme={theme}
|
||||
>
|
||||
{dashboardCapabilities.createNew && (
|
||||
<>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,5 +92,6 @@ export const redirectToSavedObjectPage = (
|
|||
onBeforeRedirect() {
|
||||
setActiveUrl(VisualizeConstants.LANDING_PAGE_PATH);
|
||||
},
|
||||
theme: services.theme,
|
||||
})(error);
|
||||
};
|
||||
|
|
|
@ -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"]
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
<ApplicationContextProvider forwardedState={forwardedParams}>
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route path={ROUTES.captureTest} exact render={() => <CaptureTest />} />
|
||||
<Route render={() => <Main basename={appBasePath} {...coreStart} {...deps} />} />
|
||||
</Switch>
|
||||
</Router>
|
||||
<KibanaThemeProvider theme$={coreStart.theme.theme$}>
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route path={ROUTES.captureTest} exact render={() => <CaptureTest />} />
|
||||
<Route render={() => <Main basename={appBasePath} {...coreStart} {...deps} />} />
|
||||
</Switch>
|
||||
</Router>
|
||||
</KibanaThemeProvider>
|
||||
</ApplicationContextProvider>,
|
||||
element
|
||||
);
|
||||
|
|
|
@ -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" }
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,8 @@ export class DataEnhancedPlugin
|
|||
usageCollector: this.usageCollector,
|
||||
tourDisabled: plugins.screenshotMode.isScreenshotMode(),
|
||||
})
|
||||
)
|
||||
),
|
||||
{ theme$: core.theme.theme$ }
|
||||
),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -74,7 +74,8 @@ export const createDeleteActionDescriptor = (
|
|||
onClick: async () => {
|
||||
const ref = core.overlays.openModal(
|
||||
toMountPoint(
|
||||
<DeleteConfirm onActionDismiss={() => ref?.close()} searchSession={uiSession} api={api} />
|
||||
<DeleteConfirm onActionDismiss={() => ref?.close()} searchSession={uiSession} api={api} />,
|
||||
{ theme$: core.theme.theme$ }
|
||||
)
|
||||
);
|
||||
await ref.onClose;
|
||||
|
|
|
@ -81,7 +81,8 @@ export const createExtendActionDescriptor = (
|
|||
onClick: async () => {
|
||||
const ref = core.overlays.openModal(
|
||||
toMountPoint(
|
||||
<ExtendConfirm onActionDismiss={() => ref?.close()} searchSession={uiSession} api={api} />
|
||||
<ExtendConfirm onActionDismiss={() => ref?.close()} searchSession={uiSession} api={api} />,
|
||||
{ theme$: core.theme.theme$ }
|
||||
)
|
||||
);
|
||||
await ref.onClose;
|
||||
|
|
|
@ -97,7 +97,7 @@ export const createInspectActionDescriptor = (
|
|||
),
|
||||
onClick: async () => {
|
||||
const flyout = <InspectFlyout uiSettings={core.uiSettings} searchSession={uiSession} />;
|
||||
const overlay = core.overlays.openFlyout(toMountPoint(flyout));
|
||||
const overlay = core.overlays.openFlyout(toMountPoint(flyout, { theme$: core.theme.theme$ }));
|
||||
await overlay.onClose;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -113,7 +113,8 @@ export const createRenameActionDescriptor = (
|
|||
onClick: async () => {
|
||||
const ref = core.overlays.openModal(
|
||||
toMountPoint(
|
||||
<RenameDialog onActionDismiss={() => ref?.close()} api={api} searchSession={uiSession} />
|
||||
<RenameDialog onActionDismiss={() => ref?.close()} api={api} searchSession={uiSession} />,
|
||||
{ theme$: core.theme.theme$ }
|
||||
)
|
||||
);
|
||||
await ref.onClose;
|
||||
|
|
|
@ -102,6 +102,7 @@ export function ListingRoute({
|
|||
tableListTitle={i18n.translate('xpack.graph.listing.graphsTitle', {
|
||||
defaultMessage: 'Graphs',
|
||||
})}
|
||||
theme={coreStart.theme}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
|
|
@ -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 <EuiLoadingChart />;
|
||||
|
@ -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<EmbeddablePanelWrapperProps> = ({
|
||||
|
@ -103,6 +106,7 @@ const EmbeddablePanelWrapper: FC<EmbeddablePanelWrapperProps> = ({
|
|||
actionPredicate,
|
||||
inspector,
|
||||
input,
|
||||
theme,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
embeddable.updateInput(input);
|
||||
|
@ -118,6 +122,7 @@ const EmbeddablePanelWrapper: FC<EmbeddablePanelWrapperProps> = ({
|
|||
showShadow={false}
|
||||
showBadges={false}
|
||||
showNotifications={false}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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: [
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
<Fragment>
|
||||
<EuiCallOut title={errorText} color="danger" iconType="alert">
|
||||
|
@ -24,7 +28,8 @@ export const getGeneralErrorToast = (errorText: string, err: Error): ToastInput
|
|||
id="xpack.reporting.publicNotifier.error.tryRefresh"
|
||||
defaultMessage="Try refreshing the page."
|
||||
/>
|
||||
</Fragment>
|
||||
</Fragment>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
iconType: undefined,
|
||||
});
|
||||
|
|
|
@ -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(
|
||||
<Fragment>
|
||||
|
@ -58,7 +60,8 @@ export const getFailureToast = (
|
|||
}}
|
||||
/>
|
||||
</p>
|
||||
</Fragment>
|
||||
</Fragment>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
iconType: undefined,
|
||||
'data-test-subj': 'completeReportFailure',
|
||||
|
|
|
@ -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(
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.publicNotifier.successfullyCreatedReportNotificationTitle"
|
||||
defaultMessage="Created report for {reportObjectType} '{reportObjectTitle}'"
|
||||
values={{ reportObjectType: job.jobtype, reportObjectTitle: job.title }}
|
||||
/>
|
||||
/>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
color: 'success',
|
||||
text: toMountPoint(
|
||||
|
@ -32,7 +34,8 @@ export const getSuccessToast = (
|
|||
<ReportLink getUrl={getReportLink} />
|
||||
</p>
|
||||
<DownloadButton getUrl={getDownloadLink} job={job} />
|
||||
</Fragment>
|
||||
</Fragment>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
'data-test-subj': 'completeReportSuccess',
|
||||
});
|
||||
|
|
|
@ -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(
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.publicNotifier.csvContainsFormulas.formulaReportTitle"
|
||||
defaultMessage="Report may contain formulas {reportObjectType} '{reportObjectTitle}'"
|
||||
values={{ reportObjectType: job.jobtype, reportObjectTitle: job.title }}
|
||||
/>
|
||||
/>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
text: toMountPoint(
|
||||
<Fragment>
|
||||
|
@ -37,7 +39,8 @@ export const getWarningFormulasToast = (
|
|||
<ReportLink getUrl={getReportLink} />
|
||||
</p>
|
||||
<DownloadButton getUrl={getDownloadLink} job={job} />
|
||||
</Fragment>
|
||||
</Fragment>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
'data-test-subj': 'completeReportCsvFormulasWarning',
|
||||
});
|
||||
|
|
|
@ -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(
|
||||
<FormattedMessage
|
||||
id="xpack.reporting.publicNotifier.maxSizeReached.partialReportTitle"
|
||||
defaultMessage="Created partial report for {reportObjectType} '{reportObjectTitle}'"
|
||||
values={{ reportObjectType: job.jobtype, reportObjectTitle: job.title }}
|
||||
/>
|
||||
/>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
text: toMountPoint(
|
||||
<Fragment>
|
||||
|
@ -37,7 +39,8 @@ export const getWarningMaxSizeToast = (
|
|||
<ReportLink getUrl={getReportLink} />
|
||||
</p>
|
||||
<DownloadButton getUrl={getDownloadLink} job={job} />
|
||||
</Fragment>
|
||||
</Fragment>,
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
'data-test-subj': 'completeReportMaxSizeWarning',
|
||||
});
|
||||
|
|
|
@ -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<JobSummarySet> {
|
||||
function handleError(
|
||||
notifications: NotificationsSetup,
|
||||
err: Error,
|
||||
theme: ThemeServiceStart
|
||||
): Rx.Observable<JobSummarySet> {
|
||||
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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
|
|
@ -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<Props> = {
|
||||
layoutId: 'super_cool_layout_id_X',
|
||||
|
@ -58,6 +61,7 @@ describe('ReportingPanelContent', () => {
|
|||
apiClient={apiClient}
|
||||
toasts={toasts}
|
||||
uiSettings={uiSettings}
|
||||
theme={theme}
|
||||
{...props}
|
||||
{...newProps}
|
||||
/>
|
||||
|
|
|
@ -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<Props, State> {
|
|||
</a>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
/>,
|
||||
{ theme$: this.props.theme.theme$ }
|
||||
),
|
||||
'data-test-subj': 'queueReportSuccess',
|
||||
});
|
||||
|
|
|
@ -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(
|
||||
<IntlProvider locale="en">
|
||||
|
@ -37,6 +39,7 @@ test('ScreenCapturePanelContent renders the default view properly', () => {
|
|||
uiSettings={uiSettings}
|
||||
toasts={coreSetup.notifications.toasts}
|
||||
getJobParams={getJobParamsDefault}
|
||||
theme={theme}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
@ -56,6 +59,7 @@ test('ScreenCapturePanelContent properly renders a view with "canvas" layout opt
|
|||
uiSettings={uiSettings}
|
||||
toasts={coreSetup.notifications.toasts}
|
||||
getJobParams={getJobParamsDefault}
|
||||
theme={theme}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
@ -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}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
@ -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}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
@ -111,6 +117,7 @@ test('ScreenCapturePanelContent properly renders a view with "print" layout opti
|
|||
uiSettings={uiSettings}
|
||||
toasts={coreSetup.notifications.toasts}
|
||||
getJobParams={getJobParamsDefault}
|
||||
theme={theme}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
@ -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}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -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" }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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 `<EuiFlyout />` (it contains a flyout header and footer)
|
||||
* As a standalone component that you can inline anywhere
|
||||
- As the content of a `<EuiFlyout />` (it contains a flyout header and footer)
|
||||
- As a standalone component that you can inline anywhere
|
||||
|
||||
**Note:** The runtime field editor uses the `<CodeEditor />` 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 = () => {
|
|||
</EuiFlyout>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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<OverlayRef | null>(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*/}
|
||||
/>
|
||||
</KibanaReactContextProvider>
|
||||
</KibanaReactContextProvider>,
|
||||
{ theme$: theme.theme$ }
|
||||
)
|
||||
);
|
||||
}, [openFlyout, saveRuntimeField, uiSettings]);
|
||||
|
@ -188,7 +189,7 @@ const MyComponent = () => {
|
|||
<>
|
||||
<EuiButton onClick={openRuntimeFieldEditor}>Create field</EuiButton>
|
||||
</>
|
||||
)
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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
|
||||
</EuiButton>
|
||||
</>
|
||||
)
|
||||
)
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -22,7 +22,7 @@ export const getRuntimeFieldEditorLoader =
|
|||
(coreSetup: CoreSetup) => async (): Promise<LoadEditorResponse> => {
|
||||
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}
|
||||
/>
|
||||
</KibanaReactContextProvider>
|
||||
</KibanaReactContextProvider>,
|
||||
{ theme$: theme.theme$ }
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -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, {});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue