Skip to content

Commit

Permalink
[Canvas] Cleanup services (elastic#194634)
Browse files Browse the repository at this point in the history
Closes elastic#194050

## Summary

This PR refactors the Canvas services to no longer use the
`PluginServiceProvider` from the `PresentationUtil` plugin. Note that
the Canvas storybooks are broken on main (and they have been for who
knows how long) and so, while I did make some changes to the storybooks
to make them **compile**, I didn't bother to get them fully functional.

Note that the Ecommerce workpad is broken - this is not due to this PR,
it is a [bug](elastic#195297) that is
present on main.

### 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: Catherine Liu <[email protected]>
(cherry picked from commit 91c045d)
  • Loading branch information
Heenawter committed Oct 9, 2024
1 parent 1aceffc commit 82fa144
Show file tree
Hide file tree
Showing 123 changed files with 989 additions and 2,018 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import React, { FC } from 'react';
import ReactDOM from 'react-dom';
import { useSearchApi } from '@kbn/presentation-publishing';
import { omit } from 'lodash';
import { pluginServices } from '../../../public/services';
import { CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib';
import { RendererStrings } from '../../../i18n';
import {
Expand All @@ -32,6 +31,7 @@ import { EmbeddableExpression } from '../../expression_types/embeddable';
import { StartDeps } from '../../plugin';
import { embeddableInputToExpression } from './embeddable_input_to_expression';
import { useGetAppContext } from './use_get_app_context';
import { embeddableService } from '../../../public/services/kibana_services';

const { embeddable: strings } = RendererStrings;

Expand Down Expand Up @@ -132,13 +132,12 @@ export const embeddableRendererFactory = (
help: strings.getHelpDescription(),
reuseDomNode: true,
render: async (domNode, { input, embeddableType, canvasApi }, handlers) => {
const { embeddables } = pluginServices.getServices();
const uniqueId = handlers.getElementId();
const isByValueEnabled = plugins.presentationUtil.labsService.isProjectEnabled(
'labs:canvas:byValueEmbeddable'
);

if (embeddables.reactEmbeddableRegistryHasKey(embeddableType)) {
if (embeddableService.reactEmbeddableRegistryHasKey(embeddableType)) {
/**
* Prioritize React embeddables
*/
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/canvas/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ module.exports = {
collectCoverageFrom: [
'<rootDir>/x-pack/plugins/canvas/{canvas_plugin_src,common,i18n,public,server,shareable_runtime}/**/*.{js,ts,tsx}',
],
setupFiles: ['<rootDir>/x-pack/plugins/canvas/jest_setup.ts'],
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

export interface CanvasNavLinkService {
updatePath: (path: string) => void;
}
import { setStubKibanaServices } from './public/services/mocks';

// Start the kibana services with stubs
setStubKibanaServices();
25 changes: 8 additions & 17 deletions x-pack/plugins/canvas/public/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { AppMountParameters, CoreStart, CoreSetup, AppUpdater } from '@kbn/core/

import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { PluginServices } from '@kbn/presentation-util-plugin/public';

import { CanvasStartDeps, CanvasSetupDeps } from './plugin';
import { App } from './components/app';
Expand All @@ -32,12 +31,7 @@ import { init as initStatsReporter } from './lib/ui_metric';

import { CapabilitiesStrings } from '../i18n';

import {
startLegacyServices,
services,
LegacyServicesProvider,
CanvasPluginServices,
} from './services';
import { startLegacyServices, services, LegacyServicesProvider } from './services';
import { initFunctions } from './functions';
// @ts-expect-error untyped local
import { appUnload } from './state/actions/app';
Expand All @@ -56,29 +50,26 @@ export const renderApp = ({
startPlugins,
params,
canvasStore,
pluginServices,
appUpdater,
}: {
coreStart: CoreStart;
startPlugins: CanvasStartDeps;
params: AppMountParameters;
canvasStore: Store;
pluginServices: PluginServices<CanvasPluginServices>;
appUpdater: BehaviorSubject<AppUpdater>;
}) => {
const { element } = params;
element.classList.add('canvas');
element.classList.add('canvasContainerWrapper');
const ServicesContextProvider = pluginServices.getContextProvider();

ReactDOM.render(
<KibanaRenderContextProvider {...coreStart}>
<KibanaContextProvider services={{ ...startPlugins, ...coreStart }}>
<ServicesContextProvider>
<LegacyServicesProvider providers={services}>
<Provider store={canvasStore}>
<App history={params.history} />
</Provider>
</LegacyServicesProvider>
</ServicesContextProvider>
<LegacyServicesProvider providers={services}>
<Provider store={canvasStore}>
<App history={params.history} appUpdater={appUpdater} />
</Provider>
</LegacyServicesProvider>
</KibanaContextProvider>
</KibanaRenderContextProvider>,
element
Expand Down
26 changes: 19 additions & 7 deletions x-pack/plugins/canvas/public/components/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
* 2.0.
*/

import React, { FC, useEffect } from 'react';
import { AppUpdater, ScopedHistory } from '@kbn/core/public';
import PropTypes from 'prop-types';
import { ScopedHistory } from '@kbn/core/public';
import { useNavLinkService } from '../../services';
import React, { FC, useEffect } from 'react';
import { BehaviorSubject } from 'rxjs';
// @ts-expect-error
import { shortcutManager } from '../../lib/shortcut_manager';
import { CanvasRouter } from '../../routes';
import { Flyouts } from '../flyouts';
import { getSessionStorage } from '../../lib/storage';
import { SESSIONSTORAGE_LASTPATH } from '../../../common/lib';
import { coreServices } from '../../services/kibana_services';

class ShortcutManagerContextWrapper extends React.Component<React.PropsWithChildren<{}>> {
static childContextTypes = {
Expand All @@ -28,12 +31,21 @@ class ShortcutManagerContextWrapper extends React.Component<React.PropsWithChild
}
}

export const App: FC<{ history: ScopedHistory }> = ({ history }) => {
const { updatePath } = useNavLinkService();

export const App: FC<{ history: ScopedHistory; appUpdater: BehaviorSubject<AppUpdater> }> = ({
history,
appUpdater,
}) => {
useEffect(() => {
return history.listen(({ pathname, search }) => {
updatePath(pathname + search);
const path = pathname + search;
appUpdater.next(() => ({
defaultPath: path,
}));

getSessionStorage().set(
`${SESSIONSTORAGE_LASTPATH}:${coreServices.http.basePath.get()}`,
path
);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { State, AssetType, CanvasWorkpad } from '../../../types';

import { AssetManager as Component } from './asset_manager.component';
import { getFullWorkpadPersisted } from '../../state/selectors/workpad';
import { pluginServices } from '../../services';
import { getCanvasWorkpadService } from '../../services/canvas_workpad_service';

export const AssetManager = connect(
(state: State) => ({
Expand All @@ -31,7 +31,7 @@ export const AssetManager = connect(
onAddAsset: (workpad: CanvasWorkpad, type: AssetType['type'], content: AssetType['value']) => {
// make the ID here and pass it into the action
const asset = createAsset(type, content);
const { notify, workpad: workpadService } = pluginServices.getServices();
const workpadService = getCanvasWorkpadService();

return workpadService
.updateAssets(workpad.id, { ...workpad.assets, [asset.id]: asset })
Expand All @@ -40,7 +40,7 @@ export const AssetManager = connect(
// then return the id, so the caller knows the id that will be created
return asset.id;
})
.catch((error) => notifyError(error, notify.error));
.catch((error) => notifyError(error));
},
}),
(stateProps, dispatchProps, ownProps) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
import { isEqual } from 'lodash';
import { i18n } from '@kbn/i18n';

import { pluginServices } from '../../services';
import { dataViewsService } from '../../services/kibana_services';
import { DatasourceSelector } from './datasource_selector';
import { DatasourcePreview } from './datasource_preview';

Expand Down Expand Up @@ -67,12 +67,9 @@ export class DatasourceComponent extends PureComponent {
state = { defaultIndex: '' };

componentDidMount() {
pluginServices
.getServices()
.dataViews.getDefaultDataView()
.then((defaultDataView) => {
this.setState({ defaultIndex: defaultDataView.title });
});
dataViewsService.getDefaultDataView().then((defaultDataView) => {
this.setState({ defaultIndex: defaultDataView.title });
});
}

componentDidUpdate(prevProps) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,17 @@
import React, { useState, useEffect } from 'react';
import { PropTypes } from 'prop-types';
import { Loading } from '../../loading';
import { useExpressionsService } from '../../../services';
import { getCanvasExpressionService } from '../../../services/canvas_expressions_service';
import { DatasourcePreview as Component } from './datasource_preview';

export const DatasourcePreview = (props) => {
const [datatable, setDatatable] = useState();
const expressionsService = useExpressionsService();

useEffect(() => {
expressionsService
getCanvasExpressionService()
.interpretAst({ type: 'expression', chain: [props.function] }, {})
.then(setDatatable);
}, [expressionsService, props.function, setDatatable]);
}, [props.function, setDatatable]);

if (!datatable) {
return <Loading {...props} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@
* 2.0.
*/

import React from 'react';
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { getSelectedPage, getPageById } from '../../state/selectors/workpad';
import { useExpressionsService } from '../../services';
import { ElementContent as Component, Props as ComponentProps } from './element_content';
import { State } from '../../../types';
import { getCanvasExpressionService } from '../../services/canvas_expressions_service';

export type Props = Omit<ComponentProps, 'renderFunction' | 'backgroundColor'>;

export const ElementContent = (props: Props) => {
const expressionsService = useExpressionsService();
const selectedPageId = useSelector(getSelectedPage);
const backgroundColor =
useSelector((state: State) => getPageById(state, selectedPageId)?.style.background) || '';
const { renderable } = props;

const renderFunction = renderable ? expressionsService.getRenderer(renderable.as) : null;
const renderFunction = useMemo(() => {
return renderable ? getCanvasExpressionService().getRenderer(renderable.as) : null;
}, [renderable]);

return <Component {...{ ...props, renderFunction, backgroundColor }} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
* 2.0.
*/

import React, { FC, useCallback, useMemo } from 'react';
import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody, EuiTitle } from '@elastic/eui';
import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { FC, useCallback, useMemo } from 'react';

import { SavedObjectFinder, SavedObjectMetaData } from '@kbn/saved-objects-finder-plugin/public';
import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common';
import { EmbeddableFactory, ReactEmbeddableSavedObject } from '@kbn/embeddable-plugin/public';
import { useEmbeddablesService, usePlatformService } from '../../services';
import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common';
import { SavedObjectFinder, SavedObjectMetaData } from '@kbn/saved-objects-finder-plugin/public';
import {
contentManagementService,
coreServices,
embeddableService,
} from '../../services/kibana_services';

const strings = {
getNoItemsText: () =>
Expand Down Expand Up @@ -45,13 +49,8 @@ export const AddEmbeddableFlyout: FC<Props> = ({
onClose,
isByValueEnabled,
}) => {
const embeddablesService = useEmbeddablesService();
const platformService = usePlatformService();
const { getEmbeddableFactories, getReactEmbeddableSavedObjects } = embeddablesService;
const { getContentManagement, getUISettings } = platformService;

const legacyFactoriesBySavedObjectType: LegacyFactoryMap = useMemo(() => {
return [...getEmbeddableFactories()]
return [...embeddableService.getEmbeddableFactories()]
.filter(
(embeddableFactory) =>
Boolean(embeddableFactory.savedObjectMetaData?.type) && !embeddableFactory.isContainerType
Expand All @@ -60,10 +59,10 @@ export const AddEmbeddableFlyout: FC<Props> = ({
acc[factory.savedObjectMetaData!.type] = factory;
return acc;
}, {} as LegacyFactoryMap);
}, [getEmbeddableFactories]);
}, []);

const factoriesBySavedObjectType: FactoryMap = useMemo(() => {
return [...getReactEmbeddableSavedObjects()]
return [...embeddableService.getReactEmbeddableSavedObjects()]
.filter(([type, embeddableFactory]) => {
return Boolean(embeddableFactory.savedObjectMetaData?.type);
})
Expand All @@ -74,7 +73,7 @@ export const AddEmbeddableFlyout: FC<Props> = ({
};
return acc;
}, {} as FactoryMap);
}, [getReactEmbeddableSavedObjects]);
}, []);

const metaData = useMemo(
() =>
Expand Down Expand Up @@ -111,7 +110,7 @@ export const AddEmbeddableFlyout: FC<Props> = ({
onSelect(id, type, isByValueEnabled);
return;
}
const embeddableFactories = getEmbeddableFactories();
const embeddableFactories = embeddableService.getEmbeddableFactories();
// Find the embeddable type from the saved object type
const found = Array.from(embeddableFactories).find((embeddableFactory) => {
return Boolean(
Expand All @@ -124,7 +123,7 @@ export const AddEmbeddableFlyout: FC<Props> = ({

onSelect(id, foundEmbeddableType, isByValueEnabled);
},
[isByValueEnabled, getEmbeddableFactories, onSelect, factoriesBySavedObjectType]
[isByValueEnabled, onSelect, factoriesBySavedObjectType]
);

return (
Expand All @@ -141,8 +140,8 @@ export const AddEmbeddableFlyout: FC<Props> = ({
showFilter={true}
noItemsMessage={strings.getNoItemsText()}
services={{
contentClient: getContentManagement().client,
uiSettings: getUISettings(),
contentClient: contentManagementService.client,
uiSettings: coreServices.uiSettings,
}}
/>
</EuiFlyoutBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { getSelectedPage } from '../../state/selectors/workpad';
import { EmbeddableTypes } from '../../../canvas_plugin_src/expression_types/embeddable';
import { embeddableInputToExpression } from '../../../canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression';
import { State } from '../../../types';
import { useLabsService } from '../../services';
import { presentationUtilService } from '../../services/kibana_services';

const allowedEmbeddables = {
[EmbeddableTypes.map]: (id: string) => {
Expand Down Expand Up @@ -67,8 +67,9 @@ export const AddEmbeddablePanel: React.FunctionComponent<FlyoutProps> = ({
availableEmbeddables,
...restProps
}) => {
const labsService = useLabsService();
const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable');
const isByValueEnabled = presentationUtilService.labsService.isProjectEnabled(
'labs:canvas:byValueEmbeddable'
);

const dispatch = useDispatch();
const pageId = useSelector<State, string>((state) => getSelectedPage(state));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@

import React, { FocusEventHandler } from 'react';
import { EuiComboBox } from '@elastic/eui';
import { DataView } from '@kbn/data-views-plugin/common';

type DataViewOption = Pick<DataView, 'id' | 'name' | 'title'>;
import { DataViewListItem } from '@kbn/data-views-plugin/common';

export interface ESDataViewSelectProps {
loading: boolean;
value: string;
dataViews: DataViewOption[];
dataViews: DataViewListItem[];
onChange: (string: string) => void;
onBlur: FocusEventHandler<HTMLDivElement> | undefined;
onFocus: FocusEventHandler<HTMLDivElement> | undefined;
Expand All @@ -31,7 +29,7 @@ export const ESDataViewSelect: React.FunctionComponent<ESDataViewSelectProps> =
onFocus,
onBlur,
}) => {
const selectedDataView = dataViews.find((view) => value === view.title) as DataViewOption;
const selectedDataView = dataViews.find((view) => value === view.title);

const selectedOption = selectedDataView
? { value: selectedDataView.title, label: selectedDataView.name || selectedDataView.title }
Expand Down
Loading

0 comments on commit 82fa144

Please sign in to comment.