Skip to content

Commit

Permalink
[8.x] [Canvas] Cleanup services (#194634) (#195639)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.x`:
- [[Canvas] Cleanup services
(#194634)](#194634)

<!--- Backport version: 8.9.8 -->

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

<!--BACKPORT [{"author":{"name":"Hannah
Mudge","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-10-08T20:34:01Z","message":"[Canvas]
Cleanup services (#194634)\n\nCloses
https://github.com/elastic/kibana/issues/194050\r\n\r\n##
Summary\r\n\r\nThis PR refactors the Canvas services to no longer use
the\r\n`PluginServiceProvider` from the `PresentationUtil` plugin. Note
that\r\nthe Canvas storybooks are broken on main (and they have been for
who\r\nknows how long) and so, while I did make some changes to the
storybooks\r\nto make them **compile**, I didn't bother to get them
fully functional.\r\n\r\nNote that the Ecommerce workpad is broken -
this is not due to this PR,\r\nit is a
[bug](#195297) that
is\r\npresent on main.\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: Catherine Liu
<[email protected]>","sha":"91c045d698b2e68afd13f5d4bef9229d8a231abe","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Presentation","loe:medium","technical
debt","release_note:skip","impact:high","v9.0.0","backport:prev-minor"],"number":194634,"url":"https://github.com/elastic/kibana/pull/194634","mergeCommit":{"message":"[Canvas]
Cleanup services (#194634)\n\nCloses
https://github.com/elastic/kibana/issues/194050\r\n\r\n##
Summary\r\n\r\nThis PR refactors the Canvas services to no longer use
the\r\n`PluginServiceProvider` from the `PresentationUtil` plugin. Note
that\r\nthe Canvas storybooks are broken on main (and they have been for
who\r\nknows how long) and so, while I did make some changes to the
storybooks\r\nto make them **compile**, I didn't bother to get them
fully functional.\r\n\r\nNote that the Ecommerce workpad is broken -
this is not due to this PR,\r\nit is a
[bug](#195297) that
is\r\npresent on main.\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: Catherine Liu
<[email protected]>","sha":"91c045d698b2e68afd13f5d4bef9229d8a231abe"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/194634","number":194634,"mergeCommit":{"message":"[Canvas]
Cleanup services (#194634)\n\nCloses
https://github.com/elastic/kibana/issues/194050\r\n\r\n##
Summary\r\n\r\nThis PR refactors the Canvas services to no longer use
the\r\n`PluginServiceProvider` from the `PresentationUtil` plugin. Note
that\r\nthe Canvas storybooks are broken on main (and they have been for
who\r\nknows how long) and so, while I did make some changes to the
storybooks\r\nto make them **compile**, I didn't bother to get them
fully functional.\r\n\r\nNote that the Ecommerce workpad is broken -
this is not due to this PR,\r\nit is a
[bug](#195297) that
is\r\npresent on main.\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: Catherine Liu
<[email protected]>","sha":"91c045d698b2e68afd13f5d4bef9229d8a231abe"}}]}]
BACKPORT-->
  • Loading branch information
Heenawter authored Oct 9, 2024
1 parent e8992e3 commit a177282
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 a177282

Please sign in to comment.