Skip to content

Commit

Permalink
[Presentation Util] Cleanup services (elastic#194201)
Browse files Browse the repository at this point in the history
Closes elastic#167440

## Summary

This PR refactors the `PresentationUtil` services to no longer use its
own `PluginServiceProvider`. In doing this, it removes the
`PresentationUtil` context provider, since it is no longer necessary.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)


<!--ONMERGE {"backportTargets":["8.x"]} ONMERGE-->

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
Heenawter and kibanamachine authored Oct 8, 2024
1 parent 2873cbc commit 9f2208d
Show file tree
Hide file tree
Showing 67 changed files with 471 additions and 1,093 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};
Expand All @@ -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(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -88,7 +84,6 @@ export function InternalDashboardTopNav({
const { setHeaderActionMenu, onAppLeave } = useDashboardMountContext();

const dashboardApi = useDashboardApi();
const PresentationUtilContextProvider = getPresentationUtilContextProvider();

const [
allDataViews,
Expand Down Expand Up @@ -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" />}
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/dashboard/public/services/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -25,7 +25,6 @@ export interface EventAnnotationListingPageServices {
core: CoreStart;
savedObjectsTagging: SavedObjectsTaggingApi;
eventAnnotationService: EventAnnotationServiceType;
PresentationUtilContextProvider: FC;
dataViews: DataView[];
createDataView: (spec: DataViewSpec) => Promise<DataView>;
queryInputServices: QueryInputServices;
Expand Down
1 change: 0 additions & 1 deletion src/plugins/event_annotation_listing/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/links/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
*/
Expand All @@ -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,
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,30 @@

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,
title: 'Data View Picker',
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);
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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(() => {
Expand All @@ -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;
})
Expand All @@ -82,7 +81,7 @@ export const FloatingActions: FC<FloatingActionsProps> = ({
};

getActions();
}, [api, getTriggerCompatibleActions, viewMode, disabledActions]);
}, [api, viewMode, disabledActions]);

return (
<div className="presentationUtil__floatingActionsWrapper">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;

Expand All @@ -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' }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -74,17 +73,17 @@ 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;

const resetButton = (
<EuiButtonEmpty
onClick={() => {
reset();
setProjects(getProjects());
labsService.reset();
setProjects(labsService.getProjects());
}}
isDisabled={!overrideCount}
>
Expand Down
Loading

0 comments on commit 9f2208d

Please sign in to comment.