[8.x] [Presentation Util] Cleanup services (#194201) (#195445)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Presentation Util] Cleanup services
(#194201)](https://github.com/elastic/kibana/pull/194201)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Hannah
Mudge","email":"Heenawter@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-10-08T15:15:33Z","message":"[Presentation
Util] Cleanup services (#194201)\n\nCloses
https://github.com/elastic/kibana/issues/167440\r\n\r\n##
Summary\r\n\r\nThis PR refactors the `PresentationUtil` services to no
longer use its\r\nown `PluginServiceProvider`. In doing this, it removes
the\r\n`PresentationUtil` context provider, since it is no longer
necessary.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n### For
maintainers\r\n\r\n- [ ] This was checked for breaking API changes and
was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n\r\n<!--ONMERGE
{\"backportTargets\":[\"8.x\"]}
ONMERGE-->\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"9f2208db1a83889c76fd2413a0a133a858f4891e","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Presentation","loe:small","technical
debt","release_note:skip","impact:high","v9.0.0","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-management"],"title":"[Presentation
Util] Cleanup
services","number":194201,"url":"https://github.com/elastic/kibana/pull/194201","mergeCommit":{"message":"[Presentation
Util] Cleanup services (#194201)\n\nCloses
https://github.com/elastic/kibana/issues/167440\r\n\r\n##
Summary\r\n\r\nThis PR refactors the `PresentationUtil` services to no
longer use its\r\nown `PluginServiceProvider`. In doing this, it removes
the\r\n`PresentationUtil` context provider, since it is no longer
necessary.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n### For
maintainers\r\n\r\n- [ ] This was checked for breaking API changes and
was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n\r\n<!--ONMERGE
{\"backportTargets\":[\"8.x\"]}
ONMERGE-->\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"9f2208db1a83889c76fd2413a0a133a858f4891e"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/194201","number":194201,"mergeCommit":{"message":"[Presentation
Util] Cleanup services (#194201)\n\nCloses
https://github.com/elastic/kibana/issues/167440\r\n\r\n##
Summary\r\n\r\nThis PR refactors the `PresentationUtil` services to no
longer use its\r\nown `PluginServiceProvider`. In doing this, it removes
the\r\n`PresentationUtil` context provider, since it is no longer
necessary.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n### For
maintainers\r\n\r\n- [ ] This was checked for breaking API changes and
was
[labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n\r\n<!--ONMERGE
{\"backportTargets\":[\"8.x\"]}
ONMERGE-->\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"9f2208db1a83889c76fd2413a0a133a858f4891e"}}]}]
BACKPORT-->

Co-authored-by: Hannah Mudge <Heenawter@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2024-10-10 03:00:46 +11:00 committed by GitHub
parent a02cb35f39
commit 1aceffc3df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 471 additions and 1093 deletions

View file

@ -10,12 +10,13 @@
import React, { useImperativeHandle } from 'react';
import { BehaviorSubject } from 'rxjs';
import { pluginServices as presentationUtilPluginServices } from '@kbn/presentation-util-plugin/public/services';
import { registry as presentationUtilServicesRegistry } from '@kbn/presentation-util-plugin/public/services/plugin_services.story';
import { setMockedPresentationUtilServices } from '@kbn/presentation-util-plugin/public/mocks';
import { uiActionsService } from '@kbn/presentation-util-plugin/public/services/kibana_services';
import { render, waitFor } from '@testing-library/react';
import type { ControlLabelPosition, ControlWidth } from '../../../common';
import { ControlPanel } from './control_panel';
import { Action } from '@kbn/ui-actions-plugin/public';
describe('render', () => {
let mockApi = {};
@ -27,19 +28,14 @@ describe('render', () => {
}) as any;
beforeAll(() => {
presentationUtilServicesRegistry.start({});
presentationUtilPluginServices.setRegistry(presentationUtilServicesRegistry);
presentationUtilPluginServices.getServices().uiActions.getTriggerCompatibleActions = jest
.fn()
.mockImplementation(() => {
return [
{
isCompatible: jest.fn().mockResolvedValue(true),
id: 'testAction',
MenuItem: () => <div>test1</div>,
},
];
});
setMockedPresentationUtilServices();
jest.spyOn(uiActionsService, 'getTriggerCompatibleActions').mockResolvedValue([
{
isCompatible: jest.fn().mockResolvedValue(true),
id: 'testAction',
MenuItem: () => <div>test1</div>,
},
] as unknown as Action[]);
});
beforeEach(() => {

View file

@ -25,11 +25,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { getManagedContentBadge } from '@kbn/managed-content-badge';
import { TopNavMenuBadgeProps, TopNavMenuProps } from '@kbn/navigation-plugin/public';
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
import {
LazyLabsFlyout,
getContextProvider as getPresentationUtilContextProvider,
withSuspense,
} from '@kbn/presentation-util-plugin/public';
import { LazyLabsFlyout, withSuspense } from '@kbn/presentation-util-plugin/public';
import { UI_SETTINGS } from '../../common';
import { useDashboardApi } from '../dashboard_api/use_dashboard_api';
@ -88,7 +84,6 @@ export function InternalDashboardTopNav({
const { setHeaderActionMenu, onAppLeave } = useDashboardMountContext();
const dashboardApi = useDashboardApi();
const PresentationUtilContextProvider = getPresentationUtilContextProvider();
const [
allDataViews,
@ -405,9 +400,7 @@ export function InternalDashboardTopNav({
onSavedQueryIdChange={setSavedQueryId}
/>
{viewMode !== 'print' && isLabsEnabled && isLabsShown ? (
<PresentationUtilContextProvider>
<LabsFlyout solutions={['dashboard']} onClose={() => setIsLabsShown(false)} />
</PresentationUtilContextProvider>
<LabsFlyout solutions={['dashboard']} onClose={() => setIsLabsShown(false)} />
) : null}
{viewMode === 'edit' ? <DashboardEditingToolbar isDisabled={!!focusedPanelId} /> : null}
{showBorderBottom && <EuiHorizontalRule margin="none" />}

View file

@ -60,7 +60,7 @@ export const setStubKibanaServices = () => {
navigation: navigationPluginMock.createStartContract(),
noDataPage: noDataPagePublicMock.createStart(),
observabilityAIAssistant: observabilityAIAssistantPluginMock.createStartContract(),
presentationUtil: presentationUtilPluginMock.createStartContract(core),
presentationUtil: presentationUtilPluginMock.createStartContract(),
savedObjectsManagement: savedObjectsManagementPluginMock.createStartContract(),
savedObjectsTaggingOss: savedObjectTaggingOssPluginMock.createStart(),
screenshotMode: screenshotModePluginMock.createStartContract(),

View file

@ -7,7 +7,7 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React, { FC } from 'react';
import React from 'react';
import { FormattedRelative } from '@kbn/i18n-react';
import { TableListViewKibanaProvider } from '@kbn/content-management-table-list-view-table';
import { type TableListTabParentProps } from '@kbn/content-management-tabbed-table-list-view';
@ -25,7 +25,6 @@ export interface EventAnnotationListingPageServices {
core: CoreStart;
savedObjectsTagging: SavedObjectsTaggingApi;
eventAnnotationService: EventAnnotationServiceType;
PresentationUtilContextProvider: FC;
dataViews: DataView[];
createDataView: (spec: DataViewSpec) => Promise<DataView>;
queryInputServices: QueryInputServices;

View file

@ -74,7 +74,6 @@ export class EventAnnotationListingPlugin
LensEmbeddableComponent: pluginsStart.lens.EmbeddableComponent,
savedObjectsTagging: pluginsStart.savedObjectsTagging,
eventAnnotationService,
PresentationUtilContextProvider: pluginsStart.presentationUtil.ContextProvider,
dataViews,
createDataView: pluginsStart.dataViews.create.bind(pluginsStart.dataViews),
sessionService: pluginsStart.data.search.session,

View file

@ -40,7 +40,7 @@ export const setStubKibanaServices = () => {
dashboard: dashboardPluginMock.createStartContract(),
embeddable: embeddablePluginMock.createStartContract(),
contentManagement: contentManagementMock.createStartContract(),
presentationUtil: presentationUtilPluginMock.createStartContract(core),
presentationUtil: presentationUtilPluginMock.createStartContract(),
uiActions: uiActionsPluginMock.createStartContract(),
});
};

View file

@ -24,7 +24,7 @@ import { i18n } from '@kbn/i18n';
import { ToolbarButton } from '@kbn/shared-ux-button-toolbar';
import { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common';
import { pluginServices } from '../../services';
import { contentManagementService } from '../../services/kibana_services';
export interface DashboardPickerProps {
onChange: (dashboard: { name: string; id: string } | null) => void;
@ -53,10 +53,6 @@ export function DashboardPicker({ isDisabled, onChange, idsToOmit }: DashboardPi
const [selectedDashboard, setSelectedDashboard] = useState<DashboardOption | null>(null);
const {
contentManagement: { client: cmClient },
} = pluginServices.getServices();
/**
* Debounce the query to avoid many calls to content management.
*/
@ -77,7 +73,7 @@ export function DashboardPicker({ isDisabled, onChange, idsToOmit }: DashboardPi
(async () => {
setIsLoading(true);
const response = await cmClient.mSearch<DashboardHit>({
const response = await contentManagementService.client.mSearch<DashboardHit>({
contentTypes: [{ contentTypeId: 'dashboard' }],
query: {
text: debouncedQuery ? `${debouncedQuery}*` : undefined,
@ -95,7 +91,7 @@ export function DashboardPicker({ isDisabled, onChange, idsToOmit }: DashboardPi
return () => {
canceled = true;
};
}, [debouncedQuery, cmClient]);
}, [debouncedQuery]);
/**
* Format items with dashboard hits and selected option

View file

@ -9,12 +9,10 @@
import React, { useState } from 'react';
import useMount from 'react-use/lib/useMount';
import { DataView, DataViewListItem } from '@kbn/data-views-plugin/common';
import useMount from 'react-use/lib/useMount';
import { DataViewPicker } from './data_view_picker';
import { injectStorybookDataView } from '../../services/data_views/data_views.story';
import { storybookFlightsDataView } from '../../mocks';
import { pluginServices, registry, StorybookParams } from '../../services/plugin_services.story';
import { dataViewsService } from '../../services/kibana_services';
export default {
component: DataViewPicker,
@ -22,27 +20,19 @@ export default {
argTypes: {},
};
injectStorybookDataView(storybookFlightsDataView);
export function Example({}: {} & StorybookParams) {
pluginServices.setRegistry(registry.start({}));
const {
dataViews: { getIdsWithTitle, get },
} = pluginServices.getServices();
export function Example() {
const [dataViews, setDataViews] = useState<DataViewListItem[]>();
const [dataView, setDataView] = useState<DataView | undefined>(undefined);
useMount(() => {
(async () => {
const listItems = await getIdsWithTitle();
const listItems = await dataViewsService.getIdsWithTitle();
setDataViews(listItems);
})();
});
const onChange = (newId: string) => {
get(newId).then((newDataView) => {
dataViewsService.get(newId).then((newDataView) => {
setDataView(newDataView);
});
};

View file

@ -12,15 +12,15 @@ import React, { FC, ReactElement, useEffect, useState } from 'react';
import { v4 } from 'uuid';
import {
panelHoverTrigger,
PANEL_HOVER_TRIGGER,
panelHoverTrigger,
type EmbeddableInput,
type ViewMode,
} from '@kbn/embeddable-plugin/public';
import { apiHasUniqueId } from '@kbn/presentation-publishing';
import { Action } from '@kbn/ui-actions-plugin/public';
import { pluginServices } from '../../services';
import { uiActionsService } from '../../services/kibana_services';
import './floating_actions.scss';
export interface FloatingActionsProps {
@ -41,9 +41,6 @@ export const FloatingActions: FC<FloatingActionsProps> = ({
className = '',
disabledActions,
}) => {
const {
uiActions: { getTriggerCompatibleActions },
} = pluginServices.getServices();
const [floatingActions, setFloatingActions] = useState<JSX.Element | undefined>(undefined);
useEffect(() => {
@ -55,7 +52,9 @@ export const FloatingActions: FC<FloatingActionsProps> = ({
embeddable: api,
trigger: panelHoverTrigger,
};
const actions = (await getTriggerCompatibleActions(PANEL_HOVER_TRIGGER, context))
const actions = (
await uiActionsService.getTriggerCompatibleActions(PANEL_HOVER_TRIGGER, context)
)
.filter((action): action is Action & { MenuItem: React.FC<{ context: unknown }> } => {
return action.MenuItem !== undefined && (disabledActions ?? []).indexOf(action.id) === -1;
})
@ -82,7 +81,7 @@ export const FloatingActions: FC<FloatingActionsProps> = ({
};
getActions();
}, [api, getTriggerCompatibleActions, viewMode, disabledActions]);
}, [api, viewMode, disabledActions]);
return (
<div className="presentationUtil__floatingActionsWrapper">

View file

@ -7,7 +7,7 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React from 'react';
import React, { useMemo } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
@ -17,9 +17,9 @@ import {
EuiScreenReaderOnly,
} from '@elastic/eui';
import { pluginServices } from '../../services';
import { EnvironmentName } from '../../../common/labs';
import { LabsStrings } from '../../i18n';
import { getPresentationCapabilities } from '../../utils/get_presentation_capabilities';
const { Switch: strings } = LabsStrings.Components;
@ -37,9 +37,11 @@ export interface Props {
}
export const EnvironmentSwitch = ({ env, isChecked, onChange, name }: Props) => {
const { capabilities } = pluginServices.getHooks();
const { canSetAdvancedSettings } = useMemo(() => {
return getPresentationCapabilities();
}, []);
const canSet = env === 'kibana' ? capabilities.useService().canSetAdvancedSettings() : true;
const canSet = env === 'kibana' ? canSetAdvancedSettings : true;
return (
<EuiFlexItem grow={false} style={{ marginBottom: '.25rem' }}>

View file

@ -7,20 +7,20 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React, { useState } from 'react';
import React, { useMemo, useState } from 'react';
import { EuiButton, EuiIcon, EuiNotificationBadge, EuiButtonProps } from '@elastic/eui';
import { pluginServices } from '../../services';
import { LabsFlyout, Props as FlyoutProps } from './labs_flyout';
import { getPresentationLabsService } from '../../services/presentation_labs_service';
export type Props = EuiButtonProps & Pick<FlyoutProps, 'solutions'>;
export const LabsBeakerButton = ({ solutions, ...props }: Props) => {
const { labs: labsService } = pluginServices.getHooks();
const { getProjects } = labsService.useService();
const labsService = useMemo(() => getPresentationLabsService(), []);
const [isOpen, setIsOpen] = useState(false);
const projects = getProjects();
const projects = labsService.getProjects();
const [overrideCount, onEnabledCountChange] = useState(
Object.values(projects).filter((project) => project.status.isOverride).length

View file

@ -7,26 +7,26 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React, { ReactNode, useRef, useState, useEffect } from 'react';
import {
EuiButton,
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiFlyout,
EuiTitle,
EuiSpacer,
EuiText,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlyoutHeader,
EuiButton,
EuiButtonEmpty,
EuiFlexItem,
EuiFlexGroup,
EuiIcon,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import React, { ReactNode, useEffect, useMemo, useRef, useState } from 'react';
import { SolutionName, ProjectStatus, ProjectID, Project, EnvironmentName } from '../../../common';
import { pluginServices } from '../../services';
import { EnvironmentName, Project, ProjectID, ProjectStatus, SolutionName } from '../../../common';
import { LabsStrings } from '../../i18n';
import { getPresentationLabsService } from '../../services/presentation_labs_service';
import { ProjectList } from './project_list';
const { Flyout: strings } = LabsStrings.Components;
@ -56,12 +56,11 @@ export const getOverridenCount = (projects: Record<ProjectID, Project>) =>
export const LabsFlyout = (props: Props) => {
const { solutions, onEnabledCountChange = () => {}, onClose } = props;
const { labs: labsService } = pluginServices.getHooks();
const { getProjects, setProjectStatus, reset } = labsService.useService();
const labsService = useMemo(() => getPresentationLabsService(), []);
const [projects, setProjects] = useState(getProjects());
const [projects, setProjects] = useState(labsService.getProjects());
const [overrideCount, setOverrideCount] = useState(getOverridenCount(projects));
const initialStatus = useRef(getProjects());
const initialStatus = useRef(labsService.getProjects());
const isChanged = hasStatusChanged(initialStatus.current, projects);
@ -74,8 +73,8 @@ export const LabsFlyout = (props: Props) => {
}, [onEnabledCountChange, overrideCount]);
const onStatusChange = (id: ProjectID, env: EnvironmentName, enabled: boolean) => {
setProjectStatus(id, env, enabled);
setProjects(getProjects());
labsService.setProjectStatus(id, env, enabled);
setProjects(labsService.getProjects());
};
let footer: ReactNode = null;
@ -83,8 +82,8 @@ export const LabsFlyout = (props: Props) => {
const resetButton = (
<EuiButtonEmpty
onClick={() => {
reset();
setProjects(getProjects());
labsService.reset();
setProjects(labsService.getProjects());
}}
isDisabled={!overrideCount}
>

View file

@ -7,15 +7,15 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React from 'react';
import { action } from '@storybook/addon-actions';
import { mapValues } from 'lodash';
import React from 'react';
import { EnvironmentStatus, ProjectConfig, ProjectID, ProjectStatus } from '../../../common';
import { applyProjectStatus } from '../../services/labs/types';
import { ProjectListItem, Props } from './project_list_item';
import { projects as projectConfigs } from '../../../common';
import { applyProjectStatus } from '../../services/presentation_labs_service';
import { ProjectList } from './project_list';
export default {

View file

@ -7,7 +7,7 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React, { useState } from 'react';
import React, { useMemo, useState } from 'react';
import { i18n } from '@kbn/i18n';
@ -17,20 +17,21 @@ import {
type SaveModalState,
} from '@kbn/saved-objects-plugin/public';
import { pluginServices } from '../services';
import { SaveModalDashboardProps } from './types';
import { SaveModalDashboardSelector } from './saved_object_save_modal_dashboard_selector';
import { getPresentationCapabilities } from '../utils/get_presentation_capabilities';
function SavedObjectSaveModalDashboard(props: SaveModalDashboardProps) {
const { documentInfo, tagOptions, objectType, onClose, canSaveByReference } = props;
const { id: documentId } = documentInfo;
const initialCopyOnSave = !Boolean(documentId);
const { capabilities } = pluginServices.getHooks();
const { canAccessDashboards, canCreateNewDashboards } = capabilities.useService();
const { canAccessDashboards, canCreateNewDashboards } = useMemo(() => {
return getPresentationCapabilities();
}, []);
// Disable the dashboard options if the user can't access dashboards or if they're read-only
const disableDashboardOptions = !canAccessDashboards() || !canCreateNewDashboards();
const disableDashboardOptions = !canAccessDashboards || !canCreateNewDashboards;
const [dashboardOption, setDashboardOption] = useState<'new' | 'existing' | null>(
documentId || disableDashboardOptions ? null : 'existing'

View file

@ -10,7 +10,6 @@
import React, { useState } from 'react';
import { action } from '@storybook/addon-actions';
import { StorybookParams } from '../services/plugin_services.story';
import { SaveModalDashboardSelector } from './saved_object_save_modal_dashboard_selector';
export default {
@ -49,7 +48,7 @@ export function Example({
copyOnSave: boolean;
hasDocumentId: boolean;
canSaveVisualizations: boolean;
} & StorybookParams) {
}) {
const [dashboardOption, setDashboardOption] = useState<'new' | 'existing' | null>('existing');
const [isAddToLibrarySelected, setAddToLibrary] = useState(false);

View file

@ -9,9 +9,8 @@
import { ExpressionFunction } from '@kbn/expressions-plugin/common';
import { PresentationUtilPlugin } from './plugin';
import { pluginServices } from './services';
export type { PresentationCapabilitiesService, PresentationLabsService } from './services';
export type { PresentationLabsService } from './services/presentation_labs_service';
export type {
KibanaPluginServiceFactory,
@ -70,7 +69,3 @@ export const registerExpressionsLanguage = async (expressionFunctions: Expressio
export function plugin() {
return new PresentationUtilPlugin();
}
export const useLabs = () => (() => pluginServices.getHooks().labs.useService())();
export const getContextProvider = () => pluginServices.getContextProvider();

View file

@ -7,20 +7,21 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { CoreStart } from '@kbn/core/public';
import { PresentationUtilPluginStart } from './types';
import { pluginServices } from './services';
import { registry as stubRegistry } from './services/plugin_services.story';
import { ReduxToolsPackage, registerExpressionsLanguage } from '.';
import { createReduxEmbeddableTools } from './redux_tools/redux_embeddables/create_redux_embeddable_tools';
import { createReduxTools } from './redux_tools/create_redux_tools';
import { setStubKibanaServices } from './services/mocks';
const createStartContract = (coreStart: CoreStart): PresentationUtilPluginStart => {
pluginServices.setRegistry(stubRegistry.start({}));
const createStartContract = (): PresentationUtilPluginStart => {
const startContract: PresentationUtilPluginStart = {
ContextProvider: pluginServices.getContextProvider(),
labsService: pluginServices.getServices().labs,
labsService: {
getProjects: jest.fn(),
getProject: jest.fn(),
isProjectEnabled: jest.fn(),
reset: jest.fn(),
setProjectStatus: jest.fn(),
},
registerExpressionsLanguage,
};
return startContract;
@ -40,5 +41,5 @@ export const mockedReduxEmbeddablePackage: ReduxToolsPackage = {
export * from './__stories__/fixtures/flights';
export const setMockedPresentationUtilServices = () => {
pluginServices.setRegistry(stubRegistry.start({}));
setStubKibanaServices();
};

View file

@ -8,15 +8,16 @@
*/
import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
import { pluginServices, registry } from './services/plugin_services';
import {
PresentationUtilPluginSetupDeps,
PresentationUtilPluginStartDeps,
PresentationUtilPluginSetup,
PresentationUtilPluginSetupDeps,
PresentationUtilPluginStart,
PresentationUtilPluginStartDeps,
} from './types';
import { registerExpressionsLanguage } from '.';
import { setKibanaServices } from './services/kibana_services';
import { getPresentationLabsService } from './services/presentation_labs_service';
export class PresentationUtilPlugin
implements
@ -38,11 +39,10 @@ export class PresentationUtilPlugin
coreStart: CoreStart,
startPlugins: PresentationUtilPluginStartDeps
): PresentationUtilPluginStart {
pluginServices.setRegistry(registry.start({ coreStart, startPlugins }));
setKibanaServices(coreStart, startPlugins);
return {
ContextProvider: pluginServices.getContextProvider(),
labsService: pluginServices.getServices().labs,
labsService: getPresentationLabsService(),
registerExpressionsLanguage,
};
}

View file

@ -1,32 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PluginServiceFactory } from '../create';
import { StorybookParams } from '../plugin_services.story';
import { PresentationCapabilitiesService } from './types';
type CapabilitiesServiceFactory = PluginServiceFactory<
PresentationCapabilitiesService,
StorybookParams
>;
export const capabilitiesServiceFactory: CapabilitiesServiceFactory = ({
canAccessDashboards,
canCreateNewDashboards,
canSaveVisualizations,
canSetAdvancedSettings,
}) => {
const check = (value: boolean = true) => value;
return {
canAccessDashboards: () => check(canAccessDashboards),
canCreateNewDashboards: () => check(canCreateNewDashboards),
canSaveVisualizations: () => check(canSaveVisualizations),
canSetAdvancedSettings: () => check(canSetAdvancedSettings),
};
};

View file

@ -1,20 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PluginServiceFactory } from '../create';
import { PresentationCapabilitiesService } from './types';
type CapabilitiesServiceFactory = PluginServiceFactory<PresentationCapabilitiesService>;
export const capabilitiesServiceFactory: CapabilitiesServiceFactory = () => ({
canAccessDashboards: () => true,
canCreateNewDashboards: () => true,
canSaveVisualizations: () => true,
canSetAdvancedSettings: () => true,
});

View file

@ -1,28 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PresentationUtilPluginStartDeps } from '../../types';
import { KibanaPluginServiceFactory } from '../create';
import { PresentationCapabilitiesService } from './types';
export type CapabilitiesServiceFactory = KibanaPluginServiceFactory<
PresentationCapabilitiesService,
PresentationUtilPluginStartDeps
>;
export const capabilitiesServiceFactory: CapabilitiesServiceFactory = ({ coreStart }) => {
const { dashboard, visualize, advancedSettings } = coreStart.application.capabilities;
return {
canAccessDashboards: () => Boolean(dashboard.show),
canCreateNewDashboards: () => Boolean(dashboard.createNew),
canSaveVisualizations: () => Boolean(visualize.save),
canSetAdvancedSettings: () => Boolean(advancedSettings.save),
};
};

View file

@ -1,15 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
export interface PresentationCapabilitiesService {
canAccessDashboards: () => boolean;
canCreateNewDashboards: () => boolean;
canSaveVisualizations: () => boolean;
canSetAdvancedSettings: () => boolean;
}

View file

@ -1,26 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PluginServiceFactory } from '../create';
import { PresentationContentManagementService } from './types';
type ContentManagementServiceFactory = PluginServiceFactory<PresentationContentManagementService>;
export const contentManagementServiceFactory: ContentManagementServiceFactory = () => ({
client: {
get: jest.fn(),
get$: jest.fn(),
create: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
search: jest.fn(),
search$: jest.fn(),
mSearch: jest.fn(),
} as unknown as PresentationContentManagementService['client'],
});

View file

@ -1,25 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PresentationUtilPluginStartDeps } from '../../types';
import { PresentationContentManagementService } from './types';
import { KibanaPluginServiceFactory } from '../create';
export type PresentationContentManagementServiceFactory = KibanaPluginServiceFactory<
PresentationContentManagementService,
PresentationUtilPluginStartDeps
>;
export const contentManagementServiceFactory: PresentationContentManagementServiceFactory = ({
startPlugins,
}) => {
return {
client: startPlugins.contentManagement.client,
};
};

View file

@ -1,14 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
export interface PresentationContentManagementService {
client: ContentManagementPublicStart['client'];
}

View file

@ -1,30 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { DataView } from '@kbn/data-views-plugin/common';
import { PluginServiceFactory } from '../create';
import { PresentationDataViewsService } from './types';
export type DataViewsServiceFactory = PluginServiceFactory<PresentationDataViewsService>;
let currentDataView: DataView;
export const injectStorybookDataView = (dataView: DataView) => (currentDataView = dataView);
export const dataViewsServiceFactory: DataViewsServiceFactory = () => ({
get: (() =>
new Promise((r) =>
setTimeout(() => r(currentDataView), 100)
) as unknown) as DataViewsPublicPluginStart['get'],
getIdsWithTitle: (() =>
new Promise((r) =>
setTimeout(() => r([{ id: currentDataView.id, title: currentDataView.title }]), 100)
) as unknown) as DataViewsPublicPluginStart['getIdsWithTitle'],
getDefaultId: () => Promise.resolve(currentDataView?.id ?? null),
});

View file

@ -1,29 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PresentationUtilPluginStartDeps } from '../../types';
import { PresentationDataViewsService } from './types';
import { KibanaPluginServiceFactory } from '../create';
export type DataViewsServiceFactory = KibanaPluginServiceFactory<
PresentationDataViewsService,
PresentationUtilPluginStartDeps
>;
export const dataViewsServiceFactory: DataViewsServiceFactory = ({ startPlugins }) => {
const {
dataViews: { get, getIdsWithTitle, getDefaultId },
} = startPlugins;
return {
get,
getDefaultId,
getIdsWithTitle,
};
};

View file

@ -1,16 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
export interface PresentationDataViewsService {
get: DataViewsPublicPluginStart['get'];
getDefaultId: DataViewsPublicPluginStart['getDefaultId'];
getIdsWithTitle: DataViewsPublicPluginStart['getIdsWithTitle'];
}

View file

@ -1,12 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
export { pluginServices } from './plugin_services';
export type { PresentationCapabilitiesService, PresentationLabsService } from './types';

View file

@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { BehaviorSubject } from 'rxjs';
import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
import type { CoreStart } from '@kbn/core/public';
import type { UiActionsPublicStart } from '@kbn/ui-actions-plugin/public/plugin';
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { PresentationUtilPluginStartDeps } from '../types';
export let coreServices: CoreStart;
export let contentManagementService: ContentManagementPublicStart;
export let dataViewsService: DataViewsPublicPluginStart;
export let uiActionsService: UiActionsPublicStart;
const servicesReady$ = new BehaviorSubject(false);
export const setKibanaServices = (kibanaCore: CoreStart, deps: PresentationUtilPluginStartDeps) => {
coreServices = kibanaCore;
contentManagementService = deps.contentManagement;
dataViewsService = deps.dataViews;
uiActionsService = deps.uiActions;
servicesReady$.next(true);
};
export const untilPluginStartServicesReady = () => {
if (servicesReady$.value) return Promise.resolve();
return new Promise<void>((resolve) => {
const subscription = servicesReady$.subscribe((isInitialized) => {
if (isInitialized) {
subscription.unsubscribe();
resolve();
}
});
});
};

View file

@ -1,64 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { EnvironmentName, projectIDs, Project } from '../../../common';
import { PluginServiceFactory } from '../create';
import { projects, ProjectID, getProjectIDs, SolutionName } from '../../../common';
import { PresentationLabsService, isEnabledByStorageValue, applyProjectStatus } from './types';
export type LabsServiceFactory = PluginServiceFactory<PresentationLabsService>;
export const labsServiceFactory: LabsServiceFactory = () => {
const storage = window.sessionStorage;
const getProjects = (solutions: SolutionName[] = []) =>
projectIDs.reduce((acc, id) => {
const project = getProject(id);
if (
solutions.length === 0 ||
solutions.some((solution) => project.solutions.includes(solution))
) {
acc[id] = project;
}
return acc;
}, {} as { [id in ProjectID]: Project });
const getProject = (id: ProjectID) => {
const project = projects[id];
const { isActive } = project;
const status = {
session: isEnabledByStorageValue(project, 'session', sessionStorage.getItem(id)),
browser: isEnabledByStorageValue(project, 'browser', localStorage.getItem(id)),
kibana: isActive,
};
return applyProjectStatus(project, status);
};
const setProjectStatus = (name: ProjectID, env: EnvironmentName, enabled: boolean) => {
if (env === 'session') {
storage.setItem(name, enabled ? 'enabled' : 'disabled');
}
};
const reset = () => {
// This is normally not ok, but it's our isolated Storybook instance.
storage.clear();
};
const isProjectEnabled = (id: ProjectID) => getProject(id).status.isEnabled;
return {
getProjectIDs,
getProjects,
getProject,
isProjectEnabled,
reset,
setProjectStatus,
};
};

View file

@ -1,92 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import {
projects,
projectIDs,
ProjectID,
EnvironmentName,
getProjectIDs,
Project,
SolutionName,
} from '../../../common';
import { PluginServiceFactory } from '../create';
import { PresentationLabsService, isEnabledByStorageValue, applyProjectStatus } from './types';
export type LabsServiceFactory = PluginServiceFactory<PresentationLabsService>;
type Statuses = {
[id in ProjectID]: {
defaultValue: boolean;
session: boolean | null;
browser: boolean | null;
kibana: boolean;
};
};
export const labsServiceFactory: LabsServiceFactory = () => {
let statuses = {} as Statuses;
const getProject = (id: ProjectID) => {
const project = projects[id];
const value = statuses[id];
const status = {
session: isEnabledByStorageValue(project, 'session', value.session),
browser: isEnabledByStorageValue(project, 'browser', value.browser),
kibana: isEnabledByStorageValue(project, 'kibana', value.kibana),
};
return applyProjectStatus(project, status);
};
const reset = () =>
projectIDs.reduce((acc, id) => {
const project = projects[id];
const defaultValue = project.isActive;
acc[id] = {
defaultValue,
session: null,
browser: null,
kibana: defaultValue,
};
return acc;
}, {} as Statuses);
statuses = reset();
const getProjects = (solutions: SolutionName[] = []) =>
projectIDs.reduce((acc, id) => {
const project = getProject(id);
if (
solutions.length === 0 ||
solutions.some((solution) => project.solutions.includes(solution))
) {
acc[id] = project;
}
return acc;
}, {} as { [id in ProjectID]: Project });
const setProjectStatus = (id: ProjectID, env: EnvironmentName, value: boolean) => {
statuses[id] = { ...statuses[id], [env]: value };
};
const isProjectEnabled = (id: ProjectID) => getProject(id).status.isEnabled;
return {
getProjectIDs,
getProject,
getProjects,
isProjectEnabled,
setProjectStatus,
reset: () => {
statuses = reset();
},
};
};

View file

@ -1,85 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { IUiSettingsClient } from '@kbn/core/public';
import {
EnvironmentName,
projectIDs,
Project,
ProjectConfig,
ProjectID,
EnvironmentStatus,
environmentNames,
isProjectEnabledByStatus,
SolutionName,
} from '../../../common';
export interface PresentationLabsService {
isProjectEnabled: (id: ProjectID) => boolean;
getProjectIDs: () => typeof projectIDs;
getProject: (id: ProjectID) => Project;
getProjects: (solutions?: SolutionName[]) => Record<ProjectID, Project>;
setProjectStatus: (id: ProjectID, env: EnvironmentName, status: boolean) => void;
reset: () => void;
}
export const isEnabledByStorageValue = (
project: ProjectConfig,
environment: EnvironmentName,
value: string | boolean | null
): boolean => {
const defaultValue = project.isActive;
if (!project.environments.includes(environment)) {
return defaultValue;
}
if (value === true || value === false) {
return value;
}
if (value === 'enabled') {
return true;
}
if (value === 'disabled') {
return false;
}
return defaultValue;
};
export const setStorageStatus = (storage: Storage, id: ProjectID, enabled: boolean) =>
storage.setItem(id, enabled ? 'enabled' : 'disabled');
export const applyProjectStatus = (project: ProjectConfig, status: EnvironmentStatus): Project => {
const { isActive, environments } = project;
environmentNames.forEach((name) => {
if (!environments.includes(name)) {
delete status[name];
}
});
const isEnabled = isProjectEnabledByStatus(isActive, status);
const isOverride = isEnabled !== isActive;
return {
...project,
status: {
...status,
defaultValue: isActive,
isEnabled,
isOverride,
},
};
};
export const setUISettingsStatus = (client: IUiSettingsClient, id: ProjectID, enabled: boolean) =>
client.set(id, enabled);

View file

@ -0,0 +1,43 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks';
import { CoreStart } from '@kbn/core/public';
import { coreMock } from '@kbn/core/public/mocks';
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks';
import { setKibanaServices } from './kibana_services';
const setDefaultPresentationUtilCapabilities = (core: CoreStart) => {
core.application.capabilities = {
...core.application.capabilities,
dashboard: {
show: true,
createNew: true,
},
visualize: {
save: true,
},
advancedSettings: {
save: true,
},
};
};
export const setStubKibanaServices = () => {
const core = coreMock.createStart();
setDefaultPresentationUtilCapabilities(core);
setKibanaServices(core, {
contentManagement: contentManagementMock.createStartContract(),
uiActions: uiActionsPluginMock.createStartContract(),
dataViews: dataViewPluginMocks.createStartContract(),
});
};

View file

@ -1,41 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import {
PluginServices,
PluginServiceProviders,
PluginServiceProvider,
PluginServiceRegistry,
} from './create';
import { PresentationUtilServices } from './types';
import { capabilitiesServiceFactory } from './capabilities/capabilities.story';
import { dataViewsServiceFactory } from './data_views/data_views.story';
import { contentManagementServiceFactory } from './content_management/content_management.stub';
import { labsServiceFactory } from './labs/labs.story';
import { uiActionsServiceFactory } from './ui_actions/ui_actions.stub';
export const providers: PluginServiceProviders<PresentationUtilServices> = {
capabilities: new PluginServiceProvider(capabilitiesServiceFactory),
labs: new PluginServiceProvider(labsServiceFactory),
dataViews: new PluginServiceProvider(dataViewsServiceFactory),
contentManagement: new PluginServiceProvider(contentManagementServiceFactory),
uiActions: new PluginServiceProvider(uiActionsServiceFactory),
};
export const pluginServices = new PluginServices<PresentationUtilServices>();
export const registry = new PluginServiceRegistry<PresentationUtilServices>(providers);
export interface StorybookParams {
canAccessDashboards?: boolean;
canCreateNewDashboards?: boolean;
canSaveVisualizations?: boolean;
canSetAdvancedSettings?: boolean;
}

View file

@ -1,38 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PluginServices, PluginServiceProviders, PluginServiceProvider } from './create';
import { PresentationUtilServices } from './types';
import { registry as stubRegistry } from './plugin_services.story';
import { PresentationUtilPluginStart, registerExpressionsLanguage } from '..';
import { capabilitiesServiceFactory } from './capabilities/capabilities.story';
import { dataViewsServiceFactory } from './data_views/data_views.story';
import { labsServiceFactory } from './labs/labs.story';
import { uiActionsServiceFactory } from './ui_actions/ui_actions.stub';
import { contentManagementServiceFactory } from './content_management/content_management.stub';
export const providers: PluginServiceProviders<PresentationUtilServices> = {
contentManagement: new PluginServiceProvider(contentManagementServiceFactory),
capabilities: new PluginServiceProvider(capabilitiesServiceFactory),
labs: new PluginServiceProvider(labsServiceFactory),
dataViews: new PluginServiceProvider(dataViewsServiceFactory),
uiActions: new PluginServiceProvider(uiActionsServiceFactory),
};
export const pluginServices = new PluginServices<PresentationUtilServices>();
export const getStubPluginServices = (): PresentationUtilPluginStart => {
pluginServices.setRegistry(stubRegistry.start({}));
return {
ContextProvider: pluginServices.getContextProvider(),
labsService: pluginServices.getServices().labs,
registerExpressionsLanguage,
};
};

View file

@ -1,42 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import {
PluginServices,
PluginServiceProviders,
KibanaPluginServiceParams,
PluginServiceProvider,
PluginServiceRegistry,
} from './create';
import { PresentationUtilPluginStartDeps } from '../types';
import { capabilitiesServiceFactory } from './capabilities/capabilities_service';
import { dataViewsServiceFactory } from './data_views/data_views_service';
import { contentManagementServiceFactory } from './content_management/content_management_service';
import { uiActionsServiceFactory } from './ui_actions/ui_actions_service';
import { labsServiceFactory } from './labs/labs_service';
import { PresentationUtilServices } from './types';
export const providers: PluginServiceProviders<
PresentationUtilServices,
KibanaPluginServiceParams<PresentationUtilPluginStartDeps>
> = {
capabilities: new PluginServiceProvider(capabilitiesServiceFactory),
labs: new PluginServiceProvider(labsServiceFactory),
dataViews: new PluginServiceProvider(dataViewsServiceFactory),
uiActions: new PluginServiceProvider(uiActionsServiceFactory),
contentManagement: new PluginServiceProvider(contentManagementServiceFactory),
};
export const pluginServices = new PluginServices<PresentationUtilServices>();
export const registry = new PluginServiceRegistry<
PresentationUtilServices,
KibanaPluginServiceParams<PresentationUtilPluginStartDeps>
>(providers);

View file

@ -7,43 +7,31 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
import {
EnvironmentName,
EnvironmentStatus,
LABS_PROJECT_PREFIX,
Project,
ProjectConfig,
ProjectID,
SolutionName,
isProjectEnabledByStatus,
projectIDs,
projects,
ProjectID,
Project,
getProjectIDs,
SolutionName,
LABS_PROJECT_PREFIX,
} from '../../../common';
import { PresentationUtilPluginStartDeps } from '../../types';
import { KibanaPluginServiceFactory } from '../create';
import {
PresentationLabsService,
isEnabledByStorageValue,
setStorageStatus,
setUISettingsStatus,
applyProjectStatus,
} from './types';
} from '../../common';
import { coreServices } from './kibana_services';
export type LabsServiceFactory = KibanaPluginServiceFactory<
PresentationLabsService,
PresentationUtilPluginStartDeps
>;
export interface PresentationLabsService {
isProjectEnabled: (id: ProjectID) => boolean;
getProject: (id: ProjectID) => Project;
getProjects: (solutions?: SolutionName[]) => Record<ProjectID, Project>;
setProjectStatus: (id: ProjectID, env: EnvironmentName, status: boolean) => void;
reset: () => void;
}
const clearLabsFromStorage = (storage: Storage) => {
projectIDs.forEach((projectID) => storage.removeItem(projectID));
// This is a redundancy, to catch any labs that may have been removed above.
// We could consider gathering telemetry to see how often this happens, or this may be unnecessary.
Object.keys(storage)
.filter((key) => key.startsWith(LABS_PROJECT_PREFIX))
.forEach((key) => storage.removeItem(key));
};
export const labsServiceFactory: LabsServiceFactory = ({ coreStart }) => {
const { uiSettings } = coreStart;
export const getPresentationLabsService = (): PresentationLabsService => {
const { uiSettings } = coreServices;
const localStorage = window.localStorage;
const sessionStorage = window.sessionStorage;
@ -94,7 +82,6 @@ export const labsServiceFactory: LabsServiceFactory = ({ coreStart }) => {
const isProjectEnabled = (id: ProjectID) => getProject(id).status.isEnabled;
return {
getProjectIDs,
getProjects,
getProject,
isProjectEnabled,
@ -102,3 +89,71 @@ export const labsServiceFactory: LabsServiceFactory = ({ coreStart }) => {
setProjectStatus,
};
};
/**
* Helpers
*/
const isEnabledByStorageValue = (
project: ProjectConfig,
environment: EnvironmentName,
value: string | boolean | null
): boolean => {
const defaultValue = project.isActive;
if (!project.environments.includes(environment)) {
return defaultValue;
}
if (value === true || value === false) {
return value;
}
if (value === 'enabled') {
return true;
}
if (value === 'disabled') {
return false;
}
return defaultValue;
};
const setStorageStatus = (storage: Storage, id: ProjectID, enabled: boolean) =>
storage.setItem(id, enabled ? 'enabled' : 'disabled');
export const applyProjectStatus = (project: ProjectConfig, status: EnvironmentStatus): Project => {
const { isActive, environments } = project;
environments.forEach((name) => {
if (!environments.includes(name)) {
delete status[name];
}
});
const isEnabled = isProjectEnabledByStatus(isActive, status);
const isOverride = isEnabled !== isActive;
return {
...project,
status: {
...status,
defaultValue: isActive,
isEnabled,
isOverride,
},
};
};
const setUISettingsStatus = (client: IUiSettingsClient, id: ProjectID, enabled: boolean) =>
client.set(id, enabled);
const clearLabsFromStorage = (storage: Storage) => {
projectIDs.forEach((projectID) => storage.removeItem(projectID));
// This is a redundancy, to catch any labs that may have been removed above.
// We could consider gathering telemetry to see how often this happens, or this may be unnecessary.
Object.keys(storage)
.filter((key) => key.startsWith(LABS_PROJECT_PREFIX))
.forEach((key) => storage.removeItem(key));
};

View file

@ -1,24 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PresentationLabsService } from './labs/types';
import { PresentationCapabilitiesService } from './capabilities/types';
import { PresentationDataViewsService } from './data_views/types';
import { PresentationUiActionsService } from './ui_actions/types';
import { PresentationContentManagementService } from './content_management/types';
export interface PresentationUtilServices {
contentManagement: PresentationContentManagementService;
capabilities: PresentationCapabilitiesService;
dataViews: PresentationDataViewsService;
uiActions: PresentationUiActionsService;
labs: PresentationLabsService;
}
export type { PresentationCapabilitiesService, PresentationLabsService };

View file

@ -1,14 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';
export interface PresentationUiActionsService {
getTriggerCompatibleActions: UiActionsStart['getTriggerCompatibleActions'];
}

View file

@ -1,20 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks';
import { PluginServiceFactory } from '../create';
import { PresentationUiActionsService } from './types';
type CapabilitiesServiceFactory = PluginServiceFactory<PresentationUiActionsService>;
export const uiActionsServiceFactory: CapabilitiesServiceFactory = () => {
const { getTriggerCompatibleActions } = uiActionsPluginMock.createStartContract();
return { getTriggerCompatibleActions };
};

View file

@ -1,26 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { PresentationUtilPluginStartDeps } from '../../types';
import { PresentationUiActionsService } from './types';
import { KibanaPluginServiceFactory } from '../create';
export type UiActionsServiceFactory = KibanaPluginServiceFactory<
PresentationUiActionsService,
PresentationUtilPluginStartDeps
>;
export const uiActionsServiceFactory: UiActionsServiceFactory = ({ startPlugins }) => {
const {
uiActions: { getTriggerCompatibleActions },
} = startPlugins;
return {
getTriggerCompatibleActions,
};
};

View file

@ -7,18 +7,15 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { FC, PropsWithChildren } from 'react';
import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import { registerExpressionsLanguage } from '.';
import { PresentationLabsService } from './services/labs/types';
import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import { type PresentationLabsService, registerExpressionsLanguage } from '.';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface PresentationUtilPluginSetup {}
export interface PresentationUtilPluginStart {
ContextProvider: FC<PropsWithChildren<unknown>>;
labsService: PresentationLabsService;
registerExpressionsLanguage: typeof registerExpressionsLanguage;
}

View file

@ -0,0 +1,28 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { coreServices } from '../services/kibana_services';
interface PresentationCapabilities {
canAccessDashboards: boolean;
canCreateNewDashboards: boolean;
canSaveVisualizations: boolean;
canSetAdvancedSettings: boolean;
}
export const getPresentationCapabilities = (): PresentationCapabilities => {
const { dashboard, visualize, advancedSettings } = coreServices.application.capabilities;
return {
canAccessDashboards: Boolean(dashboard.show),
canCreateNewDashboards: Boolean(dashboard.createNew),
canSaveVisualizations: Boolean(visualize.save),
canSetAdvancedSettings: Boolean(advancedSettings.save),
};
};

View file

@ -9,13 +9,10 @@
import React from 'react';
import { DecoratorFn } from '@storybook/react';
import { I18nProvider } from '@kbn/i18n-react';
import { KibanaContextProvider as KibanaReactProvider } from '@kbn/kibana-react-plugin/public';
import { pluginServices } from '../public/services';
import { PresentationUtilServices } from '../public/services/types';
import { providers, StorybookParams } from '../public/services/plugin_services.story';
import { PluginServiceRegistry } from '../public/services/create';
import { DecoratorFn } from '@storybook/react';
import { setStubKibanaServices } from '../public/services/mocks';
const settings = new Map();
settings.set('darkMode', true);
@ -33,15 +30,11 @@ const services = {
};
export const servicesContextDecorator: DecoratorFn = (story: Function, storybook) => {
const registry = new PluginServiceRegistry<PresentationUtilServices, StorybookParams>(providers);
pluginServices.setRegistry(registry.start(storybook.args));
const ContextProvider = pluginServices.getContextProvider();
setStubKibanaServices();
return (
<I18nProvider>
<KibanaReactProvider services={services}>
<ContextProvider>{story()}</ContextProvider>
</KibanaReactProvider>
<KibanaReactProvider services={services}>{story()}</KibanaReactProvider>
</I18nProvider>
);
};

View file

@ -9,4 +9,10 @@
import { defaultConfig } from '@kbn/storybook';
module.exports = defaultConfig;
module.exports = {
...defaultConfig,
define: {
global: 'window',
},
stories: ['../../**/*.stories.+(tsx|mdx)'],
};

View file

@ -8,13 +8,18 @@
*/
import React from 'react';
import * as jest from 'jest-mock';
import { addDecorator } from '@storybook/react';
import { Title, Subtitle, Description, Primary, Stories } from '@storybook/addon-docs/blocks';
import { servicesContextDecorator } from './decorator';
addDecorator(servicesContextDecorator);
// @ts-ignore
window.jest = jest;
export const parameters = {
docs: {
page: () => (

View file

@ -36,6 +36,7 @@
"@kbn/calculate-width-from-char-count",
"@kbn/field-utils",
"@kbn/presentation-publishing",
"@kbn/core-ui-settings-browser",
],
"exclude": ["target/**/*"]
}

View file

@ -81,7 +81,7 @@ const createInstance = async () => {
savedObjectsTaggingOss: savedObjectTaggingOssPluginMock.createStart(),
savedSearch: savedSearchPluginMock.createStartContract(),
navigation: navigationPluginMock.createStartContract(),
presentationUtil: presentationUtilPluginMock.createStartContract(coreMock.createStart()),
presentationUtil: presentationUtilPluginMock.createStartContract(),
urlForwarding: urlForwardingPluginMock.createStartContract(),
screenshotMode: screenshotModePluginMock.createStartContract(),
fieldFormats: fieldFormatsServiceMock.createStartContract(),

View file

@ -35,17 +35,15 @@ export const renderApp = (
<KibanaRenderContextProvider {...services.core}>
<Router history={services.history}>
<KibanaContextProvider services={services}>
<services.presentationUtil.ContextProvider>
<TableListViewKibanaProvider
{...{
core: services.core,
savedObjectsTagging: services.savedObjectsTagging,
FormattedRelative,
}}
>
<VisualizeApp onAppLeave={onAppLeave} />
</TableListViewKibanaProvider>
</services.presentationUtil.ContextProvider>
<TableListViewKibanaProvider
{...{
core: services.core,
savedObjectsTagging: services.savedObjectsTagging,
FormattedRelative,
}}
>
<VisualizeApp onAppLeave={onAppLeave} />
</TableListViewKibanaProvider>
</KibanaContextProvider>
</Router>
</KibanaRenderContextProvider>

View file

@ -623,7 +623,7 @@ export const getTopNavConfig = (
);
}
showSaveModal(saveModal, presentationUtil.ContextProvider);
showSaveModal(saveModal);
},
},
]

View file

@ -82,39 +82,34 @@ export const ChangePointDetectionAppState: FC<ChangePointDetectionAppStateProps>
appContextValue.embeddingOrigin = AIOPS_EMBEDDABLE_ORIGIN.ML_AIOPS_LABS;
const PresentationContextProvider =
appContextValue.presentationUtil?.ContextProvider ?? React.Fragment;
const CasesContext = appContextValue.cases?.ui.getCasesContext() ?? React.Fragment;
const casesPermissions = appContextValue.cases?.helpers.canUseCases();
return (
<PresentationContextProvider>
<KibanaThemeProvider theme={appContextValue.theme}>
<CasesContext owner={[]} permissions={casesPermissions!}>
<AiopsAppContext.Provider value={appContextValue}>
<UrlStateProvider>
<DataSourceContext.Provider value={{ dataView, savedSearch }}>
<StorageContextProvider storage={localStorage} storageKeys={AIOPS_STORAGE_KEYS}>
<DatePickerContextProvider {...datePickerDeps}>
<PageHeader />
<EuiSpacer />
<ReloadContextProvider reload$={reload$}>
<FilterQueryContextProvider>
<ChangePointDetectionContextProvider>
<ChangePointDetectionControlsContextProvider>
<ChangePointDetectionPage />
</ChangePointDetectionControlsContextProvider>
</ChangePointDetectionContextProvider>
</FilterQueryContextProvider>
</ReloadContextProvider>
</DatePickerContextProvider>
</StorageContextProvider>
</DataSourceContext.Provider>
</UrlStateProvider>
</AiopsAppContext.Provider>
</CasesContext>
</KibanaThemeProvider>
</PresentationContextProvider>
<KibanaThemeProvider theme={appContextValue.theme}>
<CasesContext owner={[]} permissions={casesPermissions!}>
<AiopsAppContext.Provider value={appContextValue}>
<UrlStateProvider>
<DataSourceContext.Provider value={{ dataView, savedSearch }}>
<StorageContextProvider storage={localStorage} storageKeys={AIOPS_STORAGE_KEYS}>
<DatePickerContextProvider {...datePickerDeps}>
<PageHeader />
<EuiSpacer />
<ReloadContextProvider reload$={reload$}>
<FilterQueryContextProvider>
<ChangePointDetectionContextProvider>
<ChangePointDetectionControlsContextProvider>
<ChangePointDetectionPage />
</ChangePointDetectionControlsContextProvider>
</ChangePointDetectionContextProvider>
</FilterQueryContextProvider>
</ReloadContextProvider>
</DatePickerContextProvider>
</StorageContextProvider>
</DataSourceContext.Provider>
</UrlStateProvider>
</AiopsAppContext.Provider>
</CasesContext>
</KibanaThemeProvider>
);
};

View file

@ -24,7 +24,6 @@ import type {
ThemeServiceStart,
} from '@kbn/core/public';
import type { LensPublicStart } from '@kbn/lens-plugin/public';
import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public';
import type { EmbeddableStart } from '@kbn/embeddable-plugin/public';
import type { CasesPublicStart } from '@kbn/cases-plugin/public';
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
@ -105,7 +104,6 @@ export interface AiopsAppContextValue {
* Internationalisation service
*/
i18n: CoreStart['i18n'];
presentationUtil?: PresentationUtilPluginStart;
embeddable?: EmbeddableStart;
cases?: CasesPublicStart;
isServerless?: boolean;

View file

@ -64,7 +64,6 @@ export const renderApp = ({
canvasStore: Store;
pluginServices: PluginServices<CanvasPluginServices>;
}) => {
const { presentationUtil } = startPlugins;
const { element } = params;
element.classList.add('canvas');
element.classList.add('canvasContainerWrapper');
@ -75,11 +74,9 @@ export const renderApp = ({
<KibanaContextProvider services={{ ...startPlugins, ...coreStart }}>
<ServicesContextProvider>
<LegacyServicesProvider providers={services}>
<presentationUtil.ContextProvider>
<Provider store={canvasStore}>
<App history={params.history} />
</Provider>
</presentationUtil.ContextProvider>
<Provider store={canvasStore}>
<App history={params.history} />
</Provider>
</LegacyServicesProvider>
</ServicesContextProvider>
</KibanaContextProvider>

View file

@ -28,14 +28,7 @@ export const servicesContextDecorator = (): DecoratorFn => {
storybook.args.useStaticData = true;
}
pluginServices.setRegistry(pluginServiceRegistry.start(storybook.args));
const ContextProvider = pluginServices.getContextProvider();
return (
<I18nProvider>
<ContextProvider>{story()}</ContextProvider>
</I18nProvider>
);
return <I18nProvider>{story()}</I18nProvider>;
};
};

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { FC, PropsWithChildren, useCallback, useEffect, useState, useMemo } from 'react';
import React, { useCallback, useEffect, useState, useMemo } from 'react';
import { AppMountParameters, CoreSetup, CoreStart } from '@kbn/core/public';
import { FormattedMessage } from '@kbn/i18n-react';
import { RouteComponentProps } from 'react-router-dom';
@ -147,18 +147,11 @@ export async function mountApp(
mountProps: {
createEditorFrame: EditorFrameStart['createInstance'];
attributeService: LensAttributeService;
getPresentationUtilContext: () => FC<PropsWithChildren<{}>>;
topNavMenuEntryGenerators: LensTopNavMenuEntryGenerator[];
locator?: LensAppLocator;
}
) {
const {
createEditorFrame,
attributeService,
getPresentationUtilContext,
topNavMenuEntryGenerators,
locator,
} = mountProps;
const { createEditorFrame, attributeService, topNavMenuEntryGenerators, locator } = mountProps;
const [[coreStart, startDependencies], instance] = await Promise.all([
core.getStartServices(),
createEditorFrame(),
@ -411,25 +404,21 @@ export async function mountApp(
params.element.classList.add('lnsAppWrapper');
const PresentationUtilContext = getPresentationUtilContext();
render(
<KibanaRenderContextProvider {...coreStart}>
<KibanaContextProvider services={lensServices}>
<PresentationUtilContext>
<HashRouter>
<Routes>
<Route exact path="/edit/:id" component={EditorRoute} />
<Route
exact
path={`/${LENS_EDIT_BY_VALUE}`}
render={(routeProps) => <EditorRoute {...routeProps} editByValue />}
/>
<Route exact path="/" component={EditorRoute} />
<Route path="/" component={NotFound} />
</Routes>
</HashRouter>
</PresentationUtilContext>
<HashRouter>
<Routes>
<Route exact path="/edit/:id" component={EditorRoute} />
<Route
exact
path={`/${LENS_EDIT_BY_VALUE}`}
render={(routeProps) => <EditorRoute {...routeProps} editByValue />}
/>
<Route exact path="/" component={EditorRoute} />
<Route path="/" component={NotFound} />
</Routes>
</HashRouter>
</KibanaContextProvider>
</KibanaRenderContextProvider>,
params.element

View file

@ -57,13 +57,9 @@ export function getSaveModalComponent(
return <LoadingSpinnerWithOverlay />;
}
const { ContextProvider: PresentationUtilContext } = lensServices.presentationUtil;
return (
<EuiOverlayMask>
<PresentationUtilContext>
<LensSavedModalLazy {...props} lensServices={lensServices} />
</PresentationUtilContext>
<LensSavedModalLazy {...props} lensServices={lensServices} />
</EuiOverlayMask>
);
};

View file

@ -145,7 +145,7 @@ export function makeDefaultServices(
inspect: jest.fn(),
close: jest.fn(),
},
presentationUtil: presentationUtilPluginMock.createStartContract(core),
presentationUtil: presentationUtilPluginMock.createStartContract(),
savedObjectStore: {
load: jest.fn(),
search: jest.fn(),

View file

@ -455,9 +455,6 @@ export class LensPlugin {
() => startServices().plugins.data.nowProvider.get()
);
const getPresentationUtilContext = () =>
startServices().plugins.presentationUtil.ContextProvider;
core.application.register({
id: APP_ID,
title: NOT_INTERNATIONALIZED_PRODUCT_NAME,
@ -490,7 +487,6 @@ export class LensPlugin {
return mountApp(core, params, {
createEditorFrame: frameStart.createInstance,
attributeService: getLensAttributeService(coreStart, deps),
getPresentationUtilContext,
topNavMenuEntryGenerators: this.topNavMenuEntries,
locator: this.locator,
});

View file

@ -89,7 +89,6 @@ export const getNavigateToApp = () => coreStart.application.navigateToApp;
export const getUrlForApp = () => coreStart.application.getUrlForApp;
export const getNavigateToUrl = () => coreStart.application.navigateToUrl;
export const getSavedObjectsTagging = () => pluginsStart.savedObjectsTagging;
export const getPresentationUtilContext = () => pluginsStart.presentationUtil.ContextProvider;
export const getSpacesApi = () => pluginsStart.spaces;
export const getTheme = () => coreStart.theme;
export const getApplication = () => coreStart.application;

View file

@ -24,7 +24,6 @@ import {
getInspector,
getCoreOverlays,
getSavedObjectsTagging,
getPresentationUtilContext,
} from '../../kibana_services';
import { MAP_EMBEDDABLE_NAME } from '../../../common/constants';
import { SavedMap } from './saved_map';
@ -210,7 +209,6 @@ export function getTopNavConfig({
defaultMessage: 'map',
}),
};
const PresentationUtilContext = getPresentationUtilContext();
let saveModal;
@ -251,7 +249,7 @@ export function getTopNavConfig({
);
}
showSaveModal(saveModal, PresentationUtilContext);
showSaveModal(saveModal);
},
});

View file

@ -64,7 +64,6 @@ export const ChangePointDetectionPage: FC = () => {
'i18n',
'lens',
'notifications',
'presentationUtil',
'share',
'storage',
'theme',

View file

@ -39,7 +39,7 @@ export const ExplorerUrlStateManager: FC<ExplorerUrlStateManagerProps> = ({
jobsWithTimeRange,
}) => {
const {
services: { cases, presentationUtil, uiSettings, mlServices },
services: { cases, uiSettings, mlServices },
} = useMlKibana();
const { mlApi } = mlServices;
@ -194,7 +194,6 @@ export const ExplorerUrlStateManager: FC<ExplorerUrlStateManagerProps> = ({
}
const CasesContext = cases?.ui.getCasesContext() ?? React.Fragment;
const PresentationContextProvider = presentationUtil?.ContextProvider ?? React.Fragment;
const casesPermissions = cases?.helpers.canUseCases();
@ -218,27 +217,25 @@ export const ExplorerUrlStateManager: FC<ExplorerUrlStateManagerProps> = ({
</EuiFlexGroup>
</MlPageHeader>
<CasesContext owner={[]} permissions={casesPermissions!}>
<PresentationContextProvider>
{jobsWithTimeRange.length === 0 ? (
<AnomalyDetectionEmptyState />
) : (
<Explorer
{...{
explorerState,
overallSwimlaneData,
showCharts,
severity: tableSeverity.val,
stoppedPartitions,
invalidTimeRangeError,
selectedJobsRunning,
timeBuckets,
timefilter,
selectedCells,
swimLaneSeverity,
}}
/>
)}
</PresentationContextProvider>
{jobsWithTimeRange.length === 0 ? (
<AnomalyDetectionEmptyState />
) : (
<Explorer
{...{
explorerState,
overallSwimlaneData,
showCharts,
severity: tableSeverity.val,
stoppedPartitions,
invalidTimeRangeError,
selectedJobsRunning,
timeBuckets,
timefilter,
selectedCells,
swimLaneSeverity,
}}
/>
)}
</CasesContext>
</div>
);

View file

@ -33,9 +33,8 @@ export const TimeSeriesExplorerPage: FC<PropsWithChildren<TimeSeriesExplorerPage
noSingleMetricJobsFound,
}) => {
const {
services: { cases, docLinks, presentationUtil },
services: { cases, docLinks },
} = useMlKibana();
const PresentationContextProvider = presentationUtil?.ContextProvider ?? React.Fragment;
const CasesContext = cases?.ui.getCasesContext() ?? React.Fragment;
const casesPermissions = cases?.helpers.canUseCases();
const helpLink = docLinks.links.ml.anomalyDetection;
@ -65,7 +64,7 @@ export const TimeSeriesExplorerPage: FC<PropsWithChildren<TimeSeriesExplorerPage
<JobSelector dateFormatTz={dateFormatTz!} singleSelection={true} timeseriesOnly={true} />
)}
<CasesContext owner={[]} permissions={casesPermissions!}>
<PresentationContextProvider>{children}</PresentationContextProvider>
{children}
</CasesContext>
<HelpMenu docLink={helpLink} />
</div>

View file

@ -83,52 +83,46 @@ export const renderApp = ({
const ApplicationUsageTrackingProvider =
usageCollection?.components.ApplicationUsageTrackingProvider ?? React.Fragment;
const CloudProvider = plugins.cloud?.CloudContextProvider ?? React.Fragment;
const PresentationContextProvider = plugins.presentationUtil?.ContextProvider ?? React.Fragment;
ReactDOM.render(
<KibanaRenderContextProvider {...core}>
<PresentationContextProvider>
<ApplicationUsageTrackingProvider>
<KibanaThemeProvider {...{ theme: { theme$ } }}>
<CloudProvider>
<KibanaContextProvider
services={{
...core,
...plugins,
storage: new Storage(localStorage),
<ApplicationUsageTrackingProvider>
<KibanaThemeProvider {...{ theme: { theme$ } }}>
<CloudProvider>
<KibanaContextProvider
services={{
...core,
...plugins,
storage: new Storage(localStorage),
isDev,
kibanaVersion,
isServerless,
}}
>
<PluginContext.Provider
value={{
isDev,
kibanaVersion,
isServerless,
config,
appMountParameters,
observabilityRuleTypeRegistry,
ObservabilityPageTemplate,
}}
>
<PluginContext.Provider
value={{
isDev,
config,
appMountParameters,
observabilityRuleTypeRegistry,
ObservabilityPageTemplate,
}}
>
<Router history={history}>
<EuiThemeProvider darkMode={isDarkMode}>
<RedirectAppLinks
coreStart={core}
data-test-subj="observabilityMainContainer"
>
<QueryClientProvider client={queryClient}>
<App />
<HideableReactQueryDevTools />
</QueryClientProvider>
</RedirectAppLinks>
</EuiThemeProvider>
</Router>
</PluginContext.Provider>
</KibanaContextProvider>
</CloudProvider>
</KibanaThemeProvider>
</ApplicationUsageTrackingProvider>
</PresentationContextProvider>
<Router history={history}>
<EuiThemeProvider darkMode={isDarkMode}>
<RedirectAppLinks coreStart={core} data-test-subj="observabilityMainContainer">
<QueryClientProvider client={queryClient}>
<App />
<HideableReactQueryDevTools />
</QueryClientProvider>
</RedirectAppLinks>
</EuiThemeProvider>
</Router>
</PluginContext.Provider>
</KibanaContextProvider>
</CloudProvider>
</KibanaThemeProvider>
</ApplicationUsageTrackingProvider>
</KibanaRenderContextProvider>,
element
);

View file

@ -82,8 +82,6 @@ export const renderApp = ({
usageCollection?.components.ApplicationUsageTrackingProvider ?? React.Fragment;
const CloudProvider = plugins.cloud?.CloudContextProvider ?? React.Fragment;
const PresentationContextProvider = plugins.presentationUtil?.ContextProvider ?? React.Fragment;
const unregisterPrompts = plugins.observabilityAIAssistant?.service.setScreenContext({
starterPrompts: [
{
@ -109,50 +107,45 @@ export const renderApp = ({
ReactDOM.render(
<KibanaRenderContextProvider {...core}>
<PresentationContextProvider>
<ApplicationUsageTrackingProvider>
<KibanaThemeProvider {...{ theme: { theme$ } }}>
<CloudProvider>
<KibanaContextProvider
services={{
...core,
...plugins,
storage: new Storage(localStorage),
<ApplicationUsageTrackingProvider>
<KibanaThemeProvider {...{ theme: { theme$ } }}>
<CloudProvider>
<KibanaContextProvider
services={{
...core,
...plugins,
storage: new Storage(localStorage),
isDev,
kibanaVersion,
isServerless,
}}
>
<PluginContext.Provider
value={{
isDev,
kibanaVersion,
isServerless,
appMountParameters,
ObservabilityPageTemplate,
observabilityRuleTypeRegistry,
experimentalFeatures,
}}
>
<PluginContext.Provider
value={{
isDev,
isServerless,
appMountParameters,
ObservabilityPageTemplate,
observabilityRuleTypeRegistry,
experimentalFeatures,
}}
>
<Router history={history}>
<EuiThemeProvider darkMode={isDarkMode}>
<RedirectAppLinks
coreStart={core}
data-test-subj="observabilityMainContainer"
>
<PerformanceContextProvider>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</PerformanceContextProvider>
</RedirectAppLinks>
</EuiThemeProvider>
</Router>
</PluginContext.Provider>
</KibanaContextProvider>
</CloudProvider>
</KibanaThemeProvider>
</ApplicationUsageTrackingProvider>
</PresentationContextProvider>
<Router history={history}>
<EuiThemeProvider darkMode={isDarkMode}>
<RedirectAppLinks coreStart={core} data-test-subj="observabilityMainContainer">
<PerformanceContextProvider>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</PerformanceContextProvider>
</RedirectAppLinks>
</EuiThemeProvider>
</Router>
</PluginContext.Provider>
</KibanaContextProvider>
</CloudProvider>
</KibanaThemeProvider>
</ApplicationUsageTrackingProvider>
</KibanaRenderContextProvider>,
element
);

View file

@ -24,15 +24,8 @@ import { PageRouter } from './routes';
import { setBasePath, store } from './state';
const Application = (props: SyntheticsAppProps) => {
const {
basePath,
canSave,
coreStart,
startPlugins,
renderGlobalHelpControls,
setBadge,
appMountParameters,
} = props;
const { basePath, canSave, coreStart, renderGlobalHelpControls, setBadge, appMountParameters } =
props;
useEffect(() => {
renderGlobalHelpControls();
@ -55,9 +48,6 @@ const Application = (props: SyntheticsAppProps) => {
store.dispatch(setBasePath(basePath));
const PresentationContextProvider =
startPlugins.presentationUtil?.ContextProvider ?? React.Fragment;
return (
<KibanaRenderContextProvider {...coreStart}>
<KibanaThemeProvider
@ -70,21 +60,19 @@ const Application = (props: SyntheticsAppProps) => {
}}
>
<SyntheticsSharedContext {...props}>
<PresentationContextProvider>
<Router history={appMountParameters.history}>
<SyntheticsSettingsContextProvider {...props}>
<PerformanceContextProvider>
<div className={APP_WRAPPER_CLASS} data-test-subj="syntheticsApp">
<InspectorContextProvider>
<PageRouter />
<ActionMenu appMountParameters={appMountParameters} />
<TestNowModeFlyoutContainer />
</InspectorContextProvider>
</div>
</PerformanceContextProvider>
</SyntheticsSettingsContextProvider>
</Router>
</PresentationContextProvider>
<Router history={appMountParameters.history}>
<SyntheticsSettingsContextProvider {...props}>
<PerformanceContextProvider>
<div className={APP_WRAPPER_CLASS} data-test-subj="syntheticsApp">
<InspectorContextProvider>
<PageRouter />
<ActionMenu appMountParameters={appMountParameters} />
<TestNowModeFlyoutContainer />
</InspectorContextProvider>
</div>
</PerformanceContextProvider>
</SyntheticsSettingsContextProvider>
</Router>
</SyntheticsSharedContext>
</KibanaThemeProvider>
</KibanaRenderContextProvider>