mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Changing where CodeEditor fields get useDarkMode value (#159638)
## Summary Closes https://github.com/elastic/kibana/issues/157203 Closes https://github.com/elastic/kibana/issues/158051 Closes https://github.com/elastic/kibana/issues/158049 With the addition of Per User Dark Mode, components can no longer rely on `uiSettings` as the source of truth for theme. CodeEditor fields used to call `uiSettings` to determine if Dark Mode was enabled, which had been provided in each callers Kibana React Context. The new source of truth for theme is the `CoreStart > ThemeServiceStart`. Currently, not all callers of CodeEditor provide the `theme` service in their Kibana Context in a similar way and some callers don't provide it at all. This PR updates CodeEditor to get theme values from the Kibana Context using a new `useKibanaTheme` react hook. It also attempts audit the callers of CodeEditor to see if their Kibana Context contains the theme service at the top level (Where I could add theme to a caller's Context without major changes, I did. Some cases will require CodeOwner guidance). The new `useKibanaTheme` react hook will throw a TypeError if theme isn't found in the top level of the Kibana Context, this will help with testing as the component will not render. I will remove this after testing so as not to introduce breaking changes. ## Testing Please review files for which you are CODEOWNER. I've attempted to tag all usages of `CodeEditor`/`CodeEditorFIeld` with a TODO comment with one of the following scenarios: 1) a note where theme was provided already/where I made changes to provide it in the appropriate context 2) I've asked for CODEOWNER guidance For scenario 1, please pull and test that CodeEditor locally: 1. Enable Dark Mode from Edit User Profiles by clicking on the Profile Icon on the top right, and updating your profile. 2. Navigate to the CodeEditors in the plugins you own. If they render and display in Dark Mode - add a green check to the table below - and you're done! 3. If it is not rendering, please help me figure out where the theme service should be provided in the context. For scenario 2, we will need to figure out where to make changes so your context is providing theme. Some of the more complex usages may need to addressed in separate issues. ## Tracking | Team | Plugin | Theme in Context ? | Verified Working | | - | - | - | - | | apm-ui | apm | APM Storybook broken | ? | | kibana-presentation | presentation_util | Yes. | Yes | | response-ops | trigger_actions_ui | Yes | Yes | | response-ops | stack_alerts | Yes | Yes | | kibana-security | security | Yes | Yes | | security-defend-workflows | osquery | Yes | Yes | | kibana-app-services | examples/expression_explorer | Yes | Yes | | ml-ui | transform | Yes | Yes | | ml-ui | ml | Yes | Yes | | uptime | synthetics | Yes | Yes | | kibana-gis | maps | Yes | Yes | | kibana-gis | file_upload | Yes | Yes | | platform-deployment-management | watcher | Yes | [AG] Yes | | platform-deployment-management | snapshot_restore | Yes | [AG] Yes | | platform-deployment-management | runtime_fields | Yes | [AG] Yes | | platform-deployment-management | painless_lab | Yes | [AG] Yes | | platform-deployment-management | ingest_pipelines | Yes | [AG] Yes | | platform-deployment-management | index_management | Yes | [AG] Yes | | platform-deployment-management | grokdebugger | Yes | [AG] Yes | | platform-deployment-management | es_ui_shared | Yes | [AG] Yes | | fleet | fleet | Yes | Yes | | enterprise-search-frontend | enterprise_search | Yes | [AG] Yes | | kibana-cloud-security-posture | cloud-security-posture | Yes | yes | | sec-cloudnative-integrations | cloud_defend | Yes | Yes | | kibana-visualizations/kibana-data-discovery | data | Yes | Yes | | kibana-visualizations | examples/testing_embedded_lens | Yes | Yes | | kibana-visualizations | vis_types | Yes | Yes | | kibana-visualizations | vis_default_editor | Yes | Yes | | kibana-visualizations | unified_search | Yes | Yes | | kibana-visualizations | packages/kbn-text-based-editor | Yes | Yes | | kibana-visualizatons | lens | Yes | Yes| | kibana-core | saved_objects_management | Yes | Yes | | kibana-presentation | inspector | Yes | Yes | | kibana-presentation | canvas | Yes | Yes | | kibana-data-discovery | discover | Yes | Yes | | kibana-data-discovery | data_view_management | Yes | Yes | | kibana-data-discovery | data_view_field_editor | Yes | Yes | | appex-sharedux | advanced_settings | Yes | Yes | | enterprise-search-frontend | serverless_search | Yes | [AG] Yes | | - | - | - | - | ## Unit tests Currently, many tests are failing since they are probably not providing `theme` in the context. Once CODEOWNERs have weighed in on CodeEditors usages that require discussion, I will update the accompanying tests. ## Release note - Fixes theming of CodeEditors --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Alison Goryachev <alisonmllr20@gmail.com> Co-authored-by: Dima Arnautov <dmitrii.arnautov@elastic.co> Co-authored-by: Dima Arnautov <arnautov.dima@gmail.com>
This commit is contained in:
parent
4ce8b3f4eb
commit
323b0477e3
44 changed files with 220 additions and 36 deletions
|
@ -18,7 +18,7 @@ import {
|
|||
EuiText,
|
||||
EuiLink,
|
||||
} from '@elastic/eui';
|
||||
import { AppMountParameters, IUiSettingsClient } from '@kbn/core/public';
|
||||
import { AppMountParameters, IUiSettingsClient, ThemeServiceStart } from '@kbn/core/public';
|
||||
import { ExpressionsStart } from '@kbn/expressions-plugin/public';
|
||||
import { Start as InspectorStart } from '@kbn/inspector-plugin/public';
|
||||
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
||||
|
@ -35,12 +35,21 @@ interface Props {
|
|||
actions: UiActionsStart;
|
||||
uiSettings: IUiSettingsClient;
|
||||
settings: SettingsStart;
|
||||
theme: ThemeServiceStart;
|
||||
}
|
||||
|
||||
const ExpressionsExplorer = ({ expressions, inspector, actions, uiSettings, settings }: Props) => {
|
||||
const ExpressionsExplorer = ({
|
||||
expressions,
|
||||
inspector,
|
||||
actions,
|
||||
uiSettings,
|
||||
settings,
|
||||
theme,
|
||||
}: Props) => {
|
||||
const { Provider: KibanaReactContextProvider } = createKibanaReactContext({
|
||||
uiSettings,
|
||||
settings,
|
||||
theme,
|
||||
});
|
||||
return (
|
||||
<KibanaReactContextProvider>
|
||||
|
|
|
@ -49,7 +49,7 @@ export class ExpressionsExplorerPlugin implements Plugin<void, void, SetupDeps,
|
|||
title: 'Expressions Explorer',
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
const [, depsStart] = await core.getStartServices();
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
const { renderApp } = await import('./app');
|
||||
return renderApp(
|
||||
{
|
||||
|
@ -58,6 +58,7 @@ export class ExpressionsExplorerPlugin implements Plugin<void, void, SetupDeps,
|
|||
actions: depsStart.uiActions,
|
||||
uiSettings: core.uiSettings,
|
||||
settings: core.settings,
|
||||
theme: coreStart.theme,
|
||||
},
|
||||
params
|
||||
);
|
||||
|
|
|
@ -16,18 +16,23 @@ import {
|
|||
TextBasedLanguagesEditor,
|
||||
TextBasedLanguagesEditorProps,
|
||||
} from './text_based_languages_editor';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('TextBasedLanguagesEditor', () => {
|
||||
const uiConfig: Record<string, any> = {};
|
||||
const uiSettings = {
|
||||
get: (key: string) => uiConfig[key],
|
||||
} as IUiSettingsClient;
|
||||
const theme = {
|
||||
theme$: of({ darkMode: false }),
|
||||
};
|
||||
|
||||
const services = {
|
||||
uiSettings,
|
||||
settings: {
|
||||
client: uiSettings,
|
||||
},
|
||||
theme,
|
||||
};
|
||||
|
||||
function renderTextBasedLanguagesEditorComponent(testProps: TextBasedLanguagesEditorProps) {
|
||||
|
|
|
@ -74,6 +74,7 @@ export class AdvancedSettings extends Component<AdvancedSettingsProps> {
|
|||
services={{
|
||||
uiSettings: this.props.settingsService.client,
|
||||
settings: this.props.settingsService,
|
||||
theme: { theme$: this.props.theme },
|
||||
}}
|
||||
>
|
||||
<Form
|
||||
|
|
|
@ -21,6 +21,12 @@ jest.mock('@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting', () => ({
|
|||
useUiSetting: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@kbn/kibana-react-plugin/public/theme/use_theme', () => ({
|
||||
useKibanaTheme: jest.fn(() => {
|
||||
return { darkMode: false };
|
||||
}),
|
||||
}));
|
||||
|
||||
const defaults = {
|
||||
requiresPageReload: false,
|
||||
readOnly: false,
|
||||
|
|
|
@ -16,6 +16,7 @@ import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui';
|
|||
import { JsonCodeEditorCommon } from '../../../../components/json_code_editor/json_code_editor_common';
|
||||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { buildDataTableRecord } from '../../../../utils/build_data_record';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
const mockDataView = {
|
||||
getComputedFields: () => [],
|
||||
|
@ -35,6 +36,9 @@ const services = {
|
|||
data: {
|
||||
dataViewService: mockDataViewService,
|
||||
},
|
||||
theme: {
|
||||
theme$: of({ darkMode: false }),
|
||||
},
|
||||
};
|
||||
|
||||
describe('Source Viewer component', () => {
|
||||
|
|
|
@ -106,6 +106,7 @@ export class InspectorPublicPlugin implements Plugin<Setup, Start> {
|
|||
uiSettings: core.uiSettings,
|
||||
share: startDeps.share,
|
||||
settings: core.settings,
|
||||
theme: core.theme,
|
||||
}}
|
||||
/>,
|
||||
{ theme$: core.theme.theme$ }
|
||||
|
|
|
@ -14,9 +14,10 @@ import { Adapters } from '../../common';
|
|||
import type { ApplicationStart, HttpSetup, IUiSettingsClient } from '@kbn/core/public';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
|
||||
import { applicationServiceMock } from '@kbn/core/public/mocks';
|
||||
import { applicationServiceMock, themeServiceMock } from '@kbn/core/public/mocks';
|
||||
import { settingsServiceMock } from '@kbn/core-ui-settings-browser-mocks';
|
||||
import type { SettingsStart } from '@kbn/core-ui-settings-browser';
|
||||
import { ThemeServiceStart } from '@kbn/core/public';
|
||||
|
||||
describe('InspectorPanel', () => {
|
||||
let adapters: Adapters;
|
||||
|
@ -27,12 +28,14 @@ describe('InspectorPanel', () => {
|
|||
share: sharePluginMock.createStartContract(),
|
||||
uiSettings: {},
|
||||
settings: settingsServiceMock.createStartContract(),
|
||||
theme: themeServiceMock.createStartContract(),
|
||||
} as unknown as {
|
||||
application: ApplicationStart;
|
||||
http: HttpSetup;
|
||||
share: SharePluginStart;
|
||||
uiSettings: IUiSettingsClient;
|
||||
settings: SettingsStart;
|
||||
theme: ThemeServiceStart;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -18,7 +18,12 @@ import {
|
|||
EuiFlyoutBody,
|
||||
EuiLoadingSpinner,
|
||||
} from '@elastic/eui';
|
||||
import { ApplicationStart, HttpStart, IUiSettingsClient } from '@kbn/core/public';
|
||||
import {
|
||||
ApplicationStart,
|
||||
HttpStart,
|
||||
IUiSettingsClient,
|
||||
ThemeServiceStart,
|
||||
} from '@kbn/core/public';
|
||||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { SettingsStart } from '@kbn/core-ui-settings-browser';
|
||||
|
@ -48,6 +53,7 @@ interface InspectorPanelProps {
|
|||
uiSettings: IUiSettingsClient;
|
||||
share: SharePluginStart;
|
||||
settings: SettingsStart;
|
||||
theme: ThemeServiceStart;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -115,8 +115,8 @@ describe('<CodeEditor />', () => {
|
|||
// Verify our mount callback will be called
|
||||
expect(editorWillMount.mock.calls.length).toBe(1);
|
||||
|
||||
// Verify that both, default and transparent theme will be setup
|
||||
expect((monaco.editor.defineTheme as jest.Mock).mock.calls.length).toBe(2);
|
||||
// Verify that both, default and transparent theme will be setup and then redefined as new values come through from the theme$ observable
|
||||
expect((monaco.editor.defineTheme as jest.Mock).mock.calls.length).toBe(4);
|
||||
|
||||
// Verify our language features have been registered
|
||||
expect((monaco.languages.onLanguage as jest.Mock).mock.calls.length).toBe(1);
|
||||
|
|
|
@ -357,6 +357,15 @@ export const CodeEditor: React.FC<Props> = ({
|
|||
]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Register themes when 'useDarkThem' changes
|
||||
monaco.editor.defineTheme('euiColors', useDarkTheme ? DARK_THEME : LIGHT_THEME);
|
||||
monaco.editor.defineTheme(
|
||||
'euiColorsTransparent',
|
||||
useDarkTheme ? DARK_THEME_TRANSPARENT : LIGHT_THEME_TRANSPARENT
|
||||
);
|
||||
}, [useDarkTheme]);
|
||||
|
||||
const _editorDidMount = useCallback(
|
||||
(editor: monaco.editor.IStandaloneCodeEditor, __monaco: unknown) => {
|
||||
if (__monaco !== monaco) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import React from 'react';
|
||||
import { EuiDelayRender, EuiErrorBoundary, EuiSkeletonText } from '@elastic/eui';
|
||||
|
||||
import { useUiSetting } from '../ui_settings';
|
||||
import { useKibanaTheme } from '../theme';
|
||||
import type { Props } from './code_editor';
|
||||
|
||||
export * from './languages/constants';
|
||||
|
@ -40,11 +40,11 @@ export type CodeEditorProps = Props;
|
|||
* @see CodeEditorField to render a code editor in the same style as other EUI form fields.
|
||||
*/
|
||||
export const CodeEditor: React.FunctionComponent<Props> = (props) => {
|
||||
const darkMode = useUiSetting<boolean>('theme:darkMode');
|
||||
const coreTheme = useKibanaTheme();
|
||||
return (
|
||||
<EuiErrorBoundary>
|
||||
<React.Suspense fallback={<Fallback height={props.height} />}>
|
||||
<LazyBaseEditor {...props} useDarkTheme={darkMode} />
|
||||
<LazyBaseEditor {...props} useDarkTheme={coreTheme.darkMode} />
|
||||
</React.Suspense>
|
||||
</EuiErrorBoundary>
|
||||
);
|
||||
|
@ -54,11 +54,11 @@ export const CodeEditor: React.FunctionComponent<Props> = (props) => {
|
|||
* Renders a Monaco code editor in the same style as other EUI form fields.
|
||||
*/
|
||||
export const CodeEditorField: React.FunctionComponent<Props> = (props) => {
|
||||
const darkMode = useUiSetting<boolean>('theme:darkMode');
|
||||
const coreTheme = useKibanaTheme();
|
||||
return (
|
||||
<EuiErrorBoundary>
|
||||
<React.Suspense fallback={<Fallback height={props.height} />}>
|
||||
<LazyCodeEditorField {...props} useDarkTheme={darkMode} />
|
||||
<LazyCodeEditorField {...props} useDarkTheme={coreTheme.darkMode} />
|
||||
</React.Suspense>
|
||||
</EuiErrorBoundary>
|
||||
);
|
||||
|
|
|
@ -86,7 +86,7 @@ export type { ToMountPointOptions } from './util';
|
|||
/** @deprecated Use `RedirectAppLinks` from `@kbn/shared-ux-link-redirect-app` */
|
||||
export { RedirectAppLinks } from './app_links';
|
||||
|
||||
export { wrapWithTheme, KibanaThemeProvider } from './theme';
|
||||
export { wrapWithTheme, KibanaThemeProvider, useKibanaTheme } from './theme';
|
||||
|
||||
/** dummy plugin, we just want kibanaReact to have its own bundle */
|
||||
export function plugin() {
|
||||
|
|
|
@ -19,6 +19,7 @@ jest.mock('../../../context', () => ({
|
|||
},
|
||||
application: { capabilities: { navLinks: { integrations: true } } },
|
||||
uiSettings: { get: jest.fn() },
|
||||
theme: { theme$: jest.fn() },
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
|
|
@ -8,4 +8,5 @@
|
|||
|
||||
export { wrapWithTheme } from './wrap_with_theme';
|
||||
export { KibanaThemeProvider } from './kibana_theme_provider';
|
||||
export { useKibanaTheme } from './use_theme';
|
||||
export type { EuiTheme } from './types';
|
||||
|
|
58
src/plugins/kibana_react/public/theme/use_theme.test.tsx
Normal file
58
src/plugins/kibana_react/public/theme/use_theme.test.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { FC, useEffect } from 'react';
|
||||
import { mountWithIntl } from '@kbn/test-jest-helpers';
|
||||
import type { CoreTheme } from '@kbn/core/public';
|
||||
import { KibanaContextProvider } from '../context';
|
||||
import { themeServiceMock } from '@kbn/core/public/mocks';
|
||||
import { useKibanaTheme } from './use_theme';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('useKibanaTheme', () => {
|
||||
let resultTheme: CoreTheme | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
resultTheme = undefined;
|
||||
});
|
||||
|
||||
const InnerComponent: FC = () => {
|
||||
const theme = useKibanaTheme();
|
||||
useEffect(() => {
|
||||
resultTheme = theme;
|
||||
}, [theme]);
|
||||
return <div>foo</div>;
|
||||
};
|
||||
|
||||
it('retrieve CoreTheme when theme service is provided in context', async () => {
|
||||
const expectedCoreTheme: CoreTheme = { darkMode: true };
|
||||
|
||||
const themeServiceStart = themeServiceMock.createStartContract();
|
||||
themeServiceStart.theme$ = of({ darkMode: true });
|
||||
|
||||
mountWithIntl(
|
||||
<KibanaContextProvider services={{ theme: themeServiceStart }}>
|
||||
<InnerComponent />
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
|
||||
expect(resultTheme).toEqual(expectedCoreTheme);
|
||||
});
|
||||
|
||||
it('does not throw error when theme service is not provided, default theme applied', async () => {
|
||||
const expectedCoreTheme: CoreTheme = { darkMode: false };
|
||||
|
||||
mountWithIntl(
|
||||
<KibanaContextProvider>
|
||||
<InnerComponent />
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
|
||||
expect(resultTheme).toEqual(expectedCoreTheme);
|
||||
});
|
||||
});
|
30
src/plugins/kibana_react/public/theme/use_theme.ts
Normal file
30
src/plugins/kibana_react/public/theme/use_theme.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 { CoreTheme } from '@kbn/core-theme-browser';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
import { of } from 'rxjs';
|
||||
import { useKibana } from '../context/context';
|
||||
|
||||
export const useKibanaTheme = (): CoreTheme => {
|
||||
const defaultTheme: CoreTheme = { darkMode: false };
|
||||
|
||||
const {
|
||||
services: { theme },
|
||||
} = useKibana();
|
||||
|
||||
let themeObservable;
|
||||
|
||||
if (!theme) {
|
||||
themeObservable = of(defaultTheme);
|
||||
} else {
|
||||
themeObservable = theme.theme$;
|
||||
}
|
||||
|
||||
return useObservable(themeObservable, defaultTheme);
|
||||
};
|
|
@ -11,7 +11,7 @@ import ReactDOM from 'react-dom';
|
|||
import { Observable } from 'rxjs';
|
||||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
import type { MountPoint, CoreTheme } from '@kbn/core/public';
|
||||
import { KibanaThemeProvider } from '../theme';
|
||||
import { KibanaThemeProvider } from '../theme/kibana_theme_provider';
|
||||
|
||||
export interface ToMountPointOptions {
|
||||
theme$?: Observable<CoreTheme>;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"@kbn/test-jest-helpers",
|
||||
"@kbn/i18n",
|
||||
"@kbn/i18n-react",
|
||||
"@kbn/core-theme-browser",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -32,6 +32,11 @@ exports[`SavedObjectEdition should render normally 1`] = `
|
|||
"set": [MockFunction],
|
||||
},
|
||||
},
|
||||
"theme": Object {
|
||||
"theme$": Observable {
|
||||
"_subscribe": [Function],
|
||||
},
|
||||
},
|
||||
"uiSettings": Object {
|
||||
"get": [MockFunction],
|
||||
"get$": [MockFunction],
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
uiSettingsServiceMock,
|
||||
scopedHistoryMock,
|
||||
docLinksServiceMock,
|
||||
themeServiceMock,
|
||||
} from '@kbn/core/public/mocks';
|
||||
|
||||
import type { SavedObjectWithMetadata } from '../../types';
|
||||
|
@ -42,6 +43,7 @@ describe('SavedObjectEdition', () => {
|
|||
let applications: ReturnType<typeof applicationServiceMock.createStartContract>;
|
||||
let docLinks: ReturnType<typeof docLinksServiceMock.createStartContract>;
|
||||
let settings: ReturnType<typeof settingsServiceMock.createStartContract>;
|
||||
let theme: ReturnType<typeof themeServiceMock.createStartContract>;
|
||||
|
||||
const shallowRender = (overrides: Partial<SavedObjectEditionProps> = {}) => {
|
||||
return shallowWithI18nProvider(
|
||||
|
@ -62,6 +64,7 @@ describe('SavedObjectEdition', () => {
|
|||
history = scopedHistoryMock.create();
|
||||
docLinks = docLinksServiceMock.createStartContract();
|
||||
applications = applicationServiceMock.createStartContract();
|
||||
theme = themeServiceMock.createStartContract();
|
||||
applications.capabilities = {
|
||||
navLinks: {},
|
||||
management: {},
|
||||
|
@ -86,6 +89,7 @@ describe('SavedObjectEdition', () => {
|
|||
uiSettings,
|
||||
docLinks: docLinks.links,
|
||||
settings,
|
||||
theme,
|
||||
};
|
||||
|
||||
bulkDeleteObjectsMock.mockResolvedValue([{}]);
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
HttpSetup,
|
||||
IUiSettingsClient,
|
||||
DocLinksStart,
|
||||
ThemeServiceStart,
|
||||
} from '@kbn/core/public';
|
||||
import type { SettingsStart } from '@kbn/core-ui-settings-browser';
|
||||
import { Header, Inspect, NotFoundErrors } from './components';
|
||||
|
@ -38,6 +39,7 @@ export interface SavedObjectEditionProps {
|
|||
uiSettings: IUiSettingsClient;
|
||||
docLinks: DocLinksStart['links'];
|
||||
settings: SettingsStart;
|
||||
theme: ThemeServiceStart;
|
||||
}
|
||||
export interface SavedObjectEditionState {
|
||||
type: string;
|
||||
|
@ -94,12 +96,12 @@ export class SavedObjectEdition extends Component<
|
|||
}
|
||||
|
||||
render() {
|
||||
const { capabilities, notFoundType, http, uiSettings, docLinks, settings } = this.props;
|
||||
const { capabilities, notFoundType, http, uiSettings, docLinks, settings, theme } = this.props;
|
||||
const { object } = this.state;
|
||||
const { delete: canDelete } = capabilities.savedObjectsManagement as Record<string, boolean>;
|
||||
const canView = this.canViewInApp(capabilities, object);
|
||||
return (
|
||||
<KibanaContextProvider services={{ uiSettings, settings }}>
|
||||
<KibanaContextProvider services={{ uiSettings, settings, theme }}>
|
||||
<EuiFlexGroup
|
||||
direction="column"
|
||||
data-test-subject="savedObjectsEdit"
|
||||
|
|
|
@ -65,6 +65,7 @@ const SavedObjectsEditionPage = ({
|
|||
history={history}
|
||||
docLinks={docLinks}
|
||||
settings={coreStart.settings}
|
||||
theme={coreStart.theme}
|
||||
/>
|
||||
</RedirectAppLinks>
|
||||
);
|
||||
|
|
|
@ -496,7 +496,11 @@ export const App = (props: {
|
|||
|
||||
return (
|
||||
<KibanaContextProvider
|
||||
services={{ uiSettings: props.core.uiSettings, settings: props.core.settings }}
|
||||
services={{
|
||||
uiSettings: props.core.uiSettings,
|
||||
settings: props.core.settings,
|
||||
theme: props.core.theme,
|
||||
}}
|
||||
>
|
||||
<EuiPage>
|
||||
<EuiPageBody style={{ maxWidth: 1200, margin: '0 auto' }}>
|
||||
|
|
|
@ -105,7 +105,7 @@ export const GenerateMap: Story<{}> = () => {
|
|||
</Cytoscape>
|
||||
|
||||
{json && (
|
||||
<CodeEditor
|
||||
<CodeEditor // TODO Unable to find context that provides theme. Need CODEOWNER Input
|
||||
languageId="json"
|
||||
value={json}
|
||||
height="200px"
|
||||
|
@ -152,7 +152,7 @@ export const MapFromJSON: Story<{}> = () => {
|
|||
<EuiForm isInvalid={error !== undefined} error={error}>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<CodeEditor
|
||||
<CodeEditor // TODO Unable to find context that provides theme. Need CODEOWNER Input
|
||||
languageId="json"
|
||||
value={json}
|
||||
options={{ fontFamily: 'monospace' }}
|
||||
|
|
|
@ -18,6 +18,7 @@ import { of } from '@kbn/kibana-utils-plugin/common';
|
|||
import { createPoint, rowClickData, TestEmbeddable } from './test/data';
|
||||
import { ROW_CLICK_TRIGGER } from '@kbn/ui-actions-plugin/public';
|
||||
import { settingsServiceMock } from '@kbn/core-ui-settings-browser-mocks';
|
||||
import { themeServiceMock } from '@kbn/core-theme-browser-mocks';
|
||||
|
||||
const mockDataPoints = [
|
||||
{
|
||||
|
@ -85,6 +86,9 @@ const createDrilldown = (isExternalUrlValid: boolean = true) => {
|
|||
getVariablesHelpDocsLink: () => 'http://localhost:5601/docs',
|
||||
navigateToUrl: mockNavigateToUrl,
|
||||
settings: settingsServiceMock.createSetupContract(),
|
||||
theme: () => {
|
||||
return themeServiceMock.createStartContract();
|
||||
},
|
||||
});
|
||||
return drilldown;
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { IExternalUrl } from '@kbn/core/public';
|
||||
import { IExternalUrl, ThemeServiceStart } from '@kbn/core/public';
|
||||
import {
|
||||
ChartActionContext,
|
||||
CONTEXT_MENU_TRIGGER,
|
||||
|
@ -52,6 +52,7 @@ interface UrlDrilldownDeps {
|
|||
getSyntaxHelpDocsLink: () => string;
|
||||
getVariablesHelpDocsLink: () => string;
|
||||
settings: SettingsStart;
|
||||
theme: () => ThemeServiceStart;
|
||||
}
|
||||
|
||||
export type ActionContext = ChartActionContext<EmbeddableWithQueryInput>;
|
||||
|
@ -124,6 +125,7 @@ export class UrlDrilldown implements Drilldown<Config, ActionContext, ActionFact
|
|||
<KibanaContextProvider
|
||||
services={{
|
||||
settings: this.deps.settings,
|
||||
theme: this.deps.theme(),
|
||||
}}
|
||||
>
|
||||
<UrlDrilldownCollectConfig
|
||||
|
|
|
@ -49,6 +49,7 @@ export class UrlDrilldownPlugin
|
|||
getVariablesHelpDocsLink: () =>
|
||||
startServices().core.docLinks.links.dashboard.urlDrilldownVariables,
|
||||
settings: core.settings,
|
||||
theme: () => startServices().core.theme,
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
"@kbn/std",
|
||||
"@kbn/image-embeddable-plugin",
|
||||
"@kbn/core-ui-settings-browser-mocks",
|
||||
"@kbn/core-ui-settings-browser"
|
||||
"@kbn/core-ui-settings-browser",
|
||||
"@kbn/core-theme-browser-mocks"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -7,6 +7,9 @@ exports[`Should render error when upload fails from elasticsearch request failur
|
|||
"settings": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
"theme": Object {
|
||||
"theme$": [MockFunction],
|
||||
},
|
||||
"uiSettings": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
|
@ -104,6 +107,9 @@ exports[`Should render error when upload fails from http request timeout 1`] = `
|
|||
"settings": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
"theme": Object {
|
||||
"theme$": [MockFunction],
|
||||
},
|
||||
"uiSettings": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
|
@ -201,6 +207,9 @@ exports[`Should render success 1`] = `
|
|||
"settings": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
"theme": Object {
|
||||
"theme$": [MockFunction],
|
||||
},
|
||||
"uiSettings": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
|
@ -361,6 +370,9 @@ exports[`Should render warning when some features failed import 1`] = `
|
|||
"settings": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
"theme": Object {
|
||||
"theme$": [MockFunction],
|
||||
},
|
||||
"uiSettings": Object {
|
||||
"get": [MockFunction],
|
||||
},
|
||||
|
|
|
@ -38,6 +38,11 @@ jest.mock('../kibana_services', () => ({
|
|||
get: jest.fn(),
|
||||
};
|
||||
},
|
||||
getTheme: () => {
|
||||
return {
|
||||
theme$: jest.fn(),
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
test('Should render success', () => {
|
||||
|
|
|
@ -20,13 +20,14 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { CodeEditor, KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { getDocLinks, getHttp, getUiSettings, getSettings } from '../kibana_services';
|
||||
import { getDocLinks, getHttp, getUiSettings, getSettings, getTheme } from '../kibana_services';
|
||||
import { ImportResults } from '../importer';
|
||||
import { getPartialImportMessage } from './utils';
|
||||
|
||||
const services = {
|
||||
uiSettings: getUiSettings(),
|
||||
settings: getSettings(),
|
||||
theme: getTheme(),
|
||||
};
|
||||
|
||||
interface Props {
|
||||
|
|
|
@ -21,3 +21,4 @@ export const getHttp = () => coreStart.http;
|
|||
export const getSavedObjectsClient = () => coreStart.savedObjects.client;
|
||||
export const getUiSettings = () => coreStart.settings.client;
|
||||
export const getSettings = () => coreStart.settings;
|
||||
export const getTheme = () => coreStart.theme;
|
||||
|
|
|
@ -258,7 +258,7 @@ export const FleetAppContext: React.FC<{
|
|||
return (
|
||||
<RedirectAppLinks application={startServices.application}>
|
||||
<startServices.i18n.Context>
|
||||
<KibanaContextProvider services={{ ...startServices }}>
|
||||
<KibanaContextProvider services={{ ...startServices, theme: { theme$ } }}>
|
||||
<EuiErrorBoundary>
|
||||
<ConfigContext.Provider value={config}>
|
||||
<KibanaVersionContext.Provider value={kibanaVersion}>
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
notificationServiceMock,
|
||||
docLinksServiceMock,
|
||||
uiSettingsServiceMock,
|
||||
themeServiceMock,
|
||||
executionContextServiceMock,
|
||||
} from '@kbn/core/public/mocks';
|
||||
import { GlobalFlyout } from '@kbn/es-ui-shared-plugin/public';
|
||||
|
@ -62,6 +63,7 @@ export const kibanaVersion = new SemVer(MAJOR_VERSION);
|
|||
const { Provider: KibanaReactContextProvider } = createKibanaReactContext({
|
||||
uiSettings: uiSettingsServiceMock.createSetupContract(),
|
||||
settings: settingsServiceMock.createStartContract(),
|
||||
theme: themeServiceMock.createStartContract(),
|
||||
kibanaVersion: {
|
||||
get: () => kibanaVersion,
|
||||
},
|
||||
|
|
|
@ -35,12 +35,12 @@ export const renderApp = (
|
|||
return () => undefined;
|
||||
}
|
||||
|
||||
const { i18n, docLinks, notifications, application, executionContext, overlays } = core;
|
||||
const { i18n, docLinks, notifications, application, executionContext, overlays, theme } = core;
|
||||
const { Context: I18nContext } = i18n;
|
||||
const { services, history, setBreadcrumbs, uiSettings, settings, kibanaVersion, theme$ } =
|
||||
dependencies;
|
||||
|
||||
// uiSettings is required by the CodeEditor component used to edit runtime field Painless scripts.
|
||||
// theme is required by the CodeEditor component used to edit runtime field Painless scripts.
|
||||
const { Provider: KibanaReactContextProvider } =
|
||||
createKibanaReactContext<KibanaReactContextServices>({
|
||||
application,
|
||||
|
@ -49,6 +49,7 @@ export const renderApp = (
|
|||
kibanaVersion: {
|
||||
get: () => kibanaVersion,
|
||||
},
|
||||
theme,
|
||||
});
|
||||
|
||||
const componentTemplateProviderValues = {
|
||||
|
@ -96,6 +97,7 @@ interface KibanaReactContextServices {
|
|||
kibanaVersion: {
|
||||
get: () => SemVer;
|
||||
};
|
||||
theme: CoreStart['theme'];
|
||||
}
|
||||
|
||||
// We override useKibana() from the react plugin to return a typed version for this app
|
||||
|
|
|
@ -67,7 +67,7 @@ export const renderApp = (
|
|||
>
|
||||
<I18nContext>
|
||||
<KibanaThemeProvider theme$={theme$}>
|
||||
<KibanaContextProvider services={services}>
|
||||
<KibanaContextProvider services={{ ...services, theme: { theme$ } }}>
|
||||
<App />
|
||||
</KibanaContextProvider>
|
||||
</KibanaThemeProvider>
|
||||
|
|
|
@ -20,8 +20,6 @@ interface MlJobEditorProps {
|
|||
width?: string;
|
||||
mode?: typeof ML_EDITOR_MODE[keyof typeof ML_EDITOR_MODE];
|
||||
readOnly?: boolean;
|
||||
syntaxChecking?: boolean;
|
||||
theme?: string;
|
||||
onChange?: EuiCodeEditorProps['onChange'];
|
||||
'data-test-subj'?: string;
|
||||
schema?: object;
|
||||
|
@ -32,8 +30,6 @@ export const MLJobEditor: FC<MlJobEditorProps> = ({
|
|||
width = '100%',
|
||||
mode = ML_EDITOR_MODE.JSON,
|
||||
readOnly = false,
|
||||
syntaxChecking = true,
|
||||
theme = 'textmate',
|
||||
onChange = () => {},
|
||||
'data-test-subj': dataTestSubj,
|
||||
schema,
|
||||
|
@ -50,10 +46,7 @@ export const MLJobEditor: FC<MlJobEditorProps> = ({
|
|||
return (
|
||||
<CodeEditor
|
||||
languageId={mode}
|
||||
options={{
|
||||
readOnly,
|
||||
theme,
|
||||
}}
|
||||
options={{ readOnly }}
|
||||
value={value}
|
||||
width={width}
|
||||
height={height}
|
||||
|
|
|
@ -36,6 +36,7 @@ export function renderApp(
|
|||
const { Provider: KibanaReactContextProvider } = createKibanaReactContext({
|
||||
uiSettings,
|
||||
settings,
|
||||
theme: { theme$ },
|
||||
});
|
||||
render(
|
||||
<I18nContext>
|
||||
|
|
|
@ -26,6 +26,7 @@ export const getRuntimeFieldEditorLoader =
|
|||
const { Provider: KibanaReactContextProvider } = createKibanaReactContext({
|
||||
uiSettings,
|
||||
settings,
|
||||
theme,
|
||||
});
|
||||
|
||||
let overlayRef: OverlayRef | null = null;
|
||||
|
|
|
@ -65,6 +65,7 @@ const appDependencies = {
|
|||
const kibanaContextDependencies = {
|
||||
uiSettings: core.uiSettings,
|
||||
settings: core.settings,
|
||||
theme: core.theme,
|
||||
};
|
||||
|
||||
export const setupEnvironment = () => {
|
||||
|
|
|
@ -31,6 +31,7 @@ export const renderApp = (elem: Element, dependencies: AppDependencies) => {
|
|||
services={{
|
||||
uiSettings: dependencies.services.uiSettings,
|
||||
settings: dependencies.services.settings,
|
||||
theme: dependencies.core.theme,
|
||||
}}
|
||||
>
|
||||
<AppProviders appDependencies={dependencies}>
|
||||
|
|
|
@ -91,7 +91,7 @@ export const App = ({ deps }: { deps: TriggersAndActionsUiServices }) => {
|
|||
<I18nProvider>
|
||||
<EuiThemeProvider darkMode={isDarkMode}>
|
||||
<KibanaThemeProvider theme$={theme$}>
|
||||
<KibanaContextProvider services={{ ...deps }}>
|
||||
<KibanaContextProvider services={{ ...deps, theme: { theme$ } }}>
|
||||
<Router history={deps.history}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<AppWithoutRouter sectionsRegex={sectionsRegex} />
|
||||
|
|
|
@ -29,7 +29,11 @@ export const renderApp = (bootDeps: BootDeps) => {
|
|||
render(
|
||||
<I18nContext>
|
||||
<KibanaContextProvider
|
||||
services={{ uiSettings: bootDeps.uiSettings, settings: bootDeps.settings }}
|
||||
services={{
|
||||
uiSettings: bootDeps.uiSettings,
|
||||
settings: bootDeps.settings,
|
||||
theme: bootDeps.theme,
|
||||
}}
|
||||
>
|
||||
<KibanaThemeProvider theme$={theme$}>
|
||||
<App {...appDeps} />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue