diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx index d088988c243fe..a21528fb970fb 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx @@ -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 { @@ -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; @@ -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 */ diff --git a/x-pack/plugins/canvas/jest.config.js b/x-pack/plugins/canvas/jest.config.js index 2bff284e94ad8..f7a9224795b4a 100644 --- a/x-pack/plugins/canvas/jest.config.js +++ b/x-pack/plugins/canvas/jest.config.js @@ -17,4 +17,5 @@ module.exports = { collectCoverageFrom: [ '/x-pack/plugins/canvas/{canvas_plugin_src,common,i18n,public,server,shareable_runtime}/**/*.{js,ts,tsx}', ], + setupFiles: ['/x-pack/plugins/canvas/jest_setup.ts'], }; diff --git a/x-pack/plugins/canvas/public/services/nav_link.ts b/x-pack/plugins/canvas/jest_setup.ts similarity index 65% rename from x-pack/plugins/canvas/public/services/nav_link.ts rename to x-pack/plugins/canvas/jest_setup.ts index 02c7ca50219a6..d9c0c26ea5a38 100644 --- a/x-pack/plugins/canvas/public/services/nav_link.ts +++ b/x-pack/plugins/canvas/jest_setup.ts @@ -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(); diff --git a/x-pack/plugins/canvas/public/application.tsx b/x-pack/plugins/canvas/public/application.tsx index 72440e3e6873c..222b64e4175e9 100644 --- a/x-pack/plugins/canvas/public/application.tsx +++ b/x-pack/plugins/canvas/public/application.tsx @@ -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'; @@ -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'; @@ -56,29 +50,26 @@ export const renderApp = ({ startPlugins, params, canvasStore, - pluginServices, + appUpdater, }: { coreStart: CoreStart; startPlugins: CanvasStartDeps; params: AppMountParameters; canvasStore: Store; - pluginServices: PluginServices; + appUpdater: BehaviorSubject; }) => { const { element } = params; element.classList.add('canvas'); element.classList.add('canvasContainerWrapper'); - const ServicesContextProvider = pluginServices.getContextProvider(); ReactDOM.render( - - - - - - - + + + + + , element diff --git a/x-pack/plugins/canvas/public/components/app/index.tsx b/x-pack/plugins/canvas/public/components/app/index.tsx index e23891ccc9bca..0ae3fcf95e6be 100644 --- a/x-pack/plugins/canvas/public/components/app/index.tsx +++ b/x-pack/plugins/canvas/public/components/app/index.tsx @@ -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> { static childContextTypes = { @@ -28,12 +31,21 @@ class ShortcutManagerContextWrapper extends React.Component = ({ history }) => { - const { updatePath } = useNavLinkService(); - +export const App: FC<{ history: ScopedHistory; appUpdater: BehaviorSubject }> = ({ + 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 + ); }); }); diff --git a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.ts b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.ts index b46c9f07f7caa..582c5174b663f 100644 --- a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.ts +++ b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.ts @@ -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) => ({ @@ -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 }) @@ -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) => { diff --git a/x-pack/plugins/canvas/public/components/datasource/datasource_component.js b/x-pack/plugins/canvas/public/components/datasource/datasource_component.js index 4b64149d2a8f6..0d61015536294 100644 --- a/x-pack/plugins/canvas/public/components/datasource/datasource_component.js +++ b/x-pack/plugins/canvas/public/components/datasource/datasource_component.js @@ -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'; @@ -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) { diff --git a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/index.js b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/index.js index 1ca674bfb6f9d..f6f535058ea21 100644 --- a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/index.js +++ b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/index.js @@ -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 ; diff --git a/x-pack/plugins/canvas/public/components/element_content/index.tsx b/x-pack/plugins/canvas/public/components/element_content/index.tsx index bdbfc205d4c81..72ff04cbf2055 100644 --- a/x-pack/plugins/canvas/public/components/element_content/index.tsx +++ b/x-pack/plugins/canvas/public/components/element_content/index.tsx @@ -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; 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 ; }; diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx index 9adde7ab57718..fbb7b971bfcb4 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx @@ -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: () => @@ -45,13 +49,8 @@ export const AddEmbeddableFlyout: FC = ({ 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 @@ -60,10 +59,10 @@ export const AddEmbeddableFlyout: FC = ({ 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); }) @@ -74,7 +73,7 @@ export const AddEmbeddableFlyout: FC = ({ }; return acc; }, {} as FactoryMap); - }, [getReactEmbeddableSavedObjects]); + }, []); const metaData = useMemo( () => @@ -111,7 +110,7 @@ export const AddEmbeddableFlyout: FC = ({ 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( @@ -124,7 +123,7 @@ export const AddEmbeddableFlyout: FC = ({ onSelect(id, foundEmbeddableType, isByValueEnabled); }, - [isByValueEnabled, getEmbeddableFactories, onSelect, factoriesBySavedObjectType] + [isByValueEnabled, onSelect, factoriesBySavedObjectType] ); return ( @@ -141,8 +140,8 @@ export const AddEmbeddableFlyout: FC = ({ showFilter={true} noItemsMessage={strings.getNoItemsText()} services={{ - contentClient: getContentManagement().client, - uiSettings: getUISettings(), + contentClient: contentManagementService.client, + uiSettings: coreServices.uiSettings, }} /> diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx index d2772a04cdc2e..3ecabeb8974f1 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.tsx @@ -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) => { @@ -67,8 +67,9 @@ export const AddEmbeddablePanel: React.FunctionComponent = ({ 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) => getSelectedPage(state)); diff --git a/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx b/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx index 4539b1f7274fc..18a98630635cb 100644 --- a/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx +++ b/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.component.tsx @@ -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; +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 | undefined; onFocus: FocusEventHandler | undefined; @@ -31,7 +29,7 @@ export const ESDataViewSelect: React.FunctionComponent = 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 } diff --git a/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx b/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx index 271662755d32a..217b7c79c8e75 100644 --- a/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx +++ b/x-pack/plugins/canvas/public/components/es_data_view_select/es_data_view_select.tsx @@ -5,25 +5,24 @@ * 2.0. */ -import { DataView } from '@kbn/data-views-plugin/common'; +import { DataViewListItem } from '@kbn/data-views-plugin/common'; import { sortBy } from 'lodash'; import React, { FC, useRef, useState } from 'react'; import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { useDataViewsService } from '../../services'; import { ESDataViewSelect as Component, ESDataViewSelectProps as Props, } from './es_data_view_select.component'; +import { getDataViews } from '../../lib/data_view_helpers'; type ESDataViewSelectProps = Omit; export const ESDataViewSelect: FC = (props) => { const { value, onChange } = props; - const [dataViews, setDataViews] = useState>>([]); + const [dataViews, setDataViews] = useState([]); const [loading, setLoading] = useState(true); const mounted = useRef(true); - const { getDataViews } = useDataViewsService(); useEffectOnce(() => { getDataViews().then((newDataViews) => { diff --git a/x-pack/plugins/canvas/public/components/es_field_select/index.tsx b/x-pack/plugins/canvas/public/components/es_field_select/index.tsx index 653eec22d77d9..f41f67bb6ee95 100644 --- a/x-pack/plugins/canvas/public/components/es_field_select/index.tsx +++ b/x-pack/plugins/canvas/public/components/es_field_select/index.tsx @@ -6,8 +6,8 @@ */ import React, { useState, useEffect, useRef } from 'react'; -import { useDataViewsService } from '../../services'; import { ESFieldSelect as Component, ESFieldSelectProps as Props } from './es_field_select'; +import { getDataViewFields } from '../../lib/data_view_helpers'; type ESFieldSelectProps = Omit; @@ -15,17 +15,16 @@ export const ESFieldSelect: React.FunctionComponent = (props const { index, value, onChange } = props; const [fields, setFields] = useState([]); const loadingFields = useRef(false); - const { getFields } = useDataViewsService(); useEffect(() => { loadingFields.current = true; - getFields(index) + getDataViewFields(index) .then((newFields) => setFields(newFields || [])) .finally(() => { loadingFields.current = false; }); - }, [index, getFields]); + }, [index]); useEffect(() => { if (!loadingFields.current && value && !fields.includes(value)) { diff --git a/x-pack/plugins/canvas/public/components/es_fields_select/es_fields_select.tsx b/x-pack/plugins/canvas/public/components/es_fields_select/es_fields_select.tsx index c929203f9e094..0cde66199b4b3 100644 --- a/x-pack/plugins/canvas/public/components/es_fields_select/es_fields_select.tsx +++ b/x-pack/plugins/canvas/public/components/es_fields_select/es_fields_select.tsx @@ -8,11 +8,11 @@ import React, { useState, useEffect, useRef } from 'react'; import { isEqual } from 'lodash'; import usePrevious from 'react-use/lib/usePrevious'; -import { useDataViewsService } from '../../services'; import { ESFieldsSelect as Component, ESFieldsSelectProps as Props, } from './es_fields_select.component'; +import { getDataViewFields } from '../../lib/data_view_helpers'; type ESFieldsSelectProps = Omit & { index: string }; @@ -21,11 +21,10 @@ export const ESFieldsSelect: React.FunctionComponent = (pro const [fields, setFields] = useState([]); const prevIndex = usePrevious(index); const mounted = useRef(true); - const { getFields } = useDataViewsService(); useEffect(() => { if (prevIndex !== index) { - getFields(index).then((newFields) => { + getDataViewFields(index).then((newFields) => { if (!mounted.current) { return; } @@ -37,7 +36,7 @@ export const ESFieldsSelect: React.FunctionComponent = (pro } }); } - }, [fields, index, onChange, prevIndex, selected, getFields]); + }, [fields, index, onChange, prevIndex, selected]); useEffect( () => () => { diff --git a/x-pack/plugins/canvas/public/components/expression/index.tsx b/x-pack/plugins/canvas/public/components/expression/index.tsx index 37bbbd1f5a4c1..1d0c9915bf347 100644 --- a/x-pack/plugins/canvas/public/components/expression/index.tsx +++ b/x-pack/plugins/canvas/public/components/expression/index.tsx @@ -8,7 +8,6 @@ import React, { FC, useState, useCallback, useMemo, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { fromExpression } from '@kbn/interpreter'; -import { useExpressionsService } from '../../services'; import { getSelectedPage, getSelectedElement } from '../../state/selectors/workpad'; // @ts-expect-error import { setExpression, flushContext } from '../../state/actions/elements'; @@ -16,6 +15,7 @@ import { setExpression, flushContext } from '../../state/actions/elements'; import { ElementNotSelected } from './element_not_selected'; import { Expression as Component } from './expression'; import { State, CanvasElement } from '../../../types'; +import { getCanvasExpressionService } from '../../services/canvas_expressions_service'; interface ExpressionProps { done: () => void; @@ -45,7 +45,6 @@ export const Expression: FC = ({ done }) => { }; const ExpressionContainer: FC = ({ done, element, pageId }) => { - const expressions = useExpressionsService(); const dispatch = useDispatch(); const [isCompact, setCompact] = useState(true); const toggleCompactView = useCallback(() => { @@ -111,8 +110,8 @@ const ExpressionContainer: FC = ({ done, element, page }, [element, setFormState, formState]); const functionDefinitions = useMemo( - () => Object.values(expressions.getFunctions()), - [expressions] + () => Object.values(getCanvasExpressionService().getFunctions()), + [] ); return ( diff --git a/x-pack/plugins/canvas/public/components/function_form/index.tsx b/x-pack/plugins/canvas/public/components/function_form/index.tsx index 202bb4384d696..f58eb496f7139 100644 --- a/x-pack/plugins/canvas/public/components/function_form/index.tsx +++ b/x-pack/plugins/canvas/public/components/function_form/index.tsx @@ -34,8 +34,8 @@ import { findExistingAsset } from '../../lib/find_existing_asset'; import { FunctionForm as Component } from './function_form'; import { Args, ArgType, ArgTypeDef } from '../../expression_types/types'; import { State, ExpressionContext, CanvasElement, AssetType } from '../../../types'; -import { useNotifyService, useWorkpadService } from '../../services'; import { createAsset, notifyError } from '../../lib/assets'; +import { getCanvasWorkpadService } from '../../services/canvas_workpad_service'; interface FunctionFormProps { name: string; @@ -54,8 +54,6 @@ interface FunctionFormProps { export const FunctionForm: React.FunctionComponent = (props) => { const { expressionIndex, ...restProps } = props; const { nextArgType, path, parentPath, argType } = restProps; - const service = useWorkpadService(); - const notifyService = useNotifyService(); const dispatch = useDispatch(); const context = useSelector( @@ -113,16 +111,16 @@ export const FunctionForm: React.FunctionComponent = (props) // make the ID here and pass it into the action const asset = createAsset(type, content); - return service + return getCanvasWorkpadService() .updateAssets(workpad.id, { ...workpad.assets, [asset.id]: asset }) .then((res) => { dispatch(setAsset(asset)); // then return the id, so the caller knows the id that will be created return asset.id; }) - .catch((error) => notifyError(error, notifyService.error)); + .catch((error) => notifyError(error)); }, - [dispatch, notifyService, service, workpad.assets, workpad.id] + [dispatch, workpad.assets, workpad.id] ); const onAssetAdd = useCallback( diff --git a/x-pack/plugins/canvas/public/components/function_form_list/index.js b/x-pack/plugins/canvas/public/components/function_form_list/index.js index 0ad6651e3f57e..6de7b81b12b01 100644 --- a/x-pack/plugins/canvas/public/components/function_form_list/index.js +++ b/x-pack/plugins/canvas/public/components/function_form_list/index.js @@ -8,7 +8,7 @@ import { compose, withProps } from 'react-recompose'; import { get } from 'lodash'; import { toExpression } from '@kbn/interpreter'; -import { pluginServices } from '../../services'; +import { getCanvasExpressionService } from '../../services/canvas_expressions_service'; import { getArgTypeDef } from '../../lib/args'; import { FunctionFormList as Component } from './function_form_list'; @@ -78,7 +78,7 @@ const componentFactory = ({ parentPath, removable, }) => { - const { expressions } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); return { args, nestedFunctionsArgs: argsWithExprFunctions, diff --git a/x-pack/plugins/canvas/public/components/home/home.stories.tsx b/x-pack/plugins/canvas/public/components/home/home.stories.tsx index 0130f9f3f894b..cfebd509c80ef 100644 --- a/x-pack/plugins/canvas/public/components/home/home.stories.tsx +++ b/x-pack/plugins/canvas/public/components/home/home.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { reduxDecorator } from '../../../storybook'; -import { argTypes } from '../../services/storybook'; +import { argTypes } from '../../../storybook/constants'; import { Home } from './home'; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_clone_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_clone_workpad.ts index 001a711a58a72..90a7c4c33de89 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_clone_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_clone_workpad.ts @@ -9,16 +9,17 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; import { getId } from '../../../lib/get_id'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useCloneWorkpad = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const history = useHistory(); return useCallback( async (workpadId: string) => { + const workpadService = getCanvasWorkpadService(); try { let workpad = await workpadService.get(workpadId); @@ -35,7 +36,7 @@ export const useCloneWorkpad = () => { notifyService.error(err, { title: errors.getCloneFailureErrorMessage() }); } }, - [notifyService, workpadService, history] + [notifyService, history] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_create_from_template.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_create_from_template.ts index 968f9398ba857..6b57cf61ca905 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_create_from_template.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_create_from_template.ts @@ -9,15 +9,16 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { CanvasTemplate } from '../../../../types'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useCreateFromTemplate = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const history = useHistory(); return useCallback( async (template: CanvasTemplate) => { + const workpadService = getCanvasWorkpadService(); try { const result = await workpadService.createFromTemplate(template.id); history.push(`/workpad/${result.id}/page/1`); @@ -27,6 +28,6 @@ export const useCreateFromTemplate = () => { }); } }, - [workpadService, notifyService, history] + [notifyService, history] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_create_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_create_workpad.ts index 3290bc8227a29..f950a4adcd037 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_create_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_create_workpad.ts @@ -11,17 +11,18 @@ import { i18n } from '@kbn/i18n'; // @ts-expect-error import { getDefaultWorkpad } from '../../../state/defaults'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; import type { CanvasWorkpad } from '../../../../types'; export const useCreateWorkpad = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const history = useHistory(); return useCallback( async (_workpad?: CanvasWorkpad | null) => { + const workpadService = getCanvasWorkpadService(); const workpad = _workpad || (getDefaultWorkpad() as CanvasWorkpad); try { @@ -34,7 +35,7 @@ export const useCreateWorkpad = () => { } return; }, - [notifyService, history, workpadService] + [notifyService, history] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_delete_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_delete_workpad.ts index 722ddae7411c9..dc52fe2e82d5c 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_delete_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_delete_workpad.ts @@ -8,51 +8,48 @@ import { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { getCanvasNotifyService } from '../../../services/canvas_notify_service'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useDeleteWorkpads = () => { - const workpadService = useWorkpadService(); - const notifyService = useNotifyService(); - - return useCallback( - async (workpadIds: string[]) => { - const removedWorkpads = workpadIds.map(async (id) => { - try { - await workpadService.remove(id); - return { id, err: null }; - } catch (err) { - return { id, err }; - } - }); - - return Promise.all(removedWorkpads).then((results) => { - const [passes, errored] = results.reduce<[string[], string[]]>( - ([passesArr, errorsArr], result) => { - if (result.err) { - errorsArr.push(result.id); - } else { - passesArr.push(result.id); - } - - return [passesArr, errorsArr]; - }, - [[], []] - ); - - const removedIds = workpadIds.filter((id) => passes.includes(id)); - - if (errored.length > 0) { - notifyService.error(errors.getDeleteFailureErrorMessage()); - } - - return { - removedIds, - errored, - }; - }); - }, - [workpadService, notifyService] - ); + return useCallback(async (workpadIds: string[]) => { + const workpadService = getCanvasWorkpadService(); + + const removedWorkpads = workpadIds.map(async (id) => { + try { + await workpadService.remove(id); + return { id, err: null }; + } catch (err) { + return { id, err }; + } + }); + + return Promise.all(removedWorkpads).then((results) => { + const [passes, errored] = results.reduce<[string[], string[]]>( + ([passesArr, errorsArr], result) => { + if (result.err) { + errorsArr.push(result.id); + } else { + passesArr.push(result.id); + } + + return [passesArr, errorsArr]; + }, + [[], []] + ); + + const removedIds = workpadIds.filter((id) => passes.includes(id)); + + if (errored.length > 0) { + getCanvasNotifyService().error(errors.getDeleteFailureErrorMessage()); + } + + return { + removedIds, + errored, + }; + }); + }, []); }; const errors = { diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_find_templates.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_find_templates.ts index 9364a79987908..426b612774762 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_find_templates.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_find_templates.ts @@ -6,10 +6,8 @@ */ import { useCallback } from 'react'; - -import { useWorkpadService } from '../../../services'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useFindTemplates = () => { - const workpadService = useWorkpadService(); - return useCallback(async () => await workpadService.findTemplates(), [workpadService]); + return useCallback(async () => await getCanvasWorkpadService().findTemplates(), []); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_find_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_find_workpad.ts index 10352d0472e8c..59ff5cd0561b5 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_find_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_find_workpad.ts @@ -8,21 +8,21 @@ import { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useFindWorkpads = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); return useCallback( async (text = '') => { try { - return await workpadService.find(text); + return await getCanvasWorkpadService().find(text); } catch (err) { notifyService.error(err, { title: errors.getFindFailureErrorMessage() }); } }, - [notifyService, workpadService] + [notifyService] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/hooks/use_import_workpad.ts b/x-pack/plugins/canvas/public/components/home/hooks/use_import_workpad.ts index bd780ee01507d..bb3f447cd107b 100644 --- a/x-pack/plugins/canvas/public/components/home/hooks/use_import_workpad.ts +++ b/x-pack/plugins/canvas/public/components/home/hooks/use_import_workpad.ts @@ -9,17 +9,18 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; import type { CanvasWorkpad } from '../../../../types'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useImportWorkpad = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const history = useHistory(); return useCallback( async (workpad: CanvasWorkpad) => { + const workpadService = getCanvasWorkpadService(); try { const importedWorkpad = await workpadService.import(workpad); history.push(`/workpad/${importedWorkpad.id}/page/1`); @@ -30,7 +31,7 @@ export const useImportWorkpad = () => { } return; }, - [notifyService, history, workpadService] + [notifyService, history] ); }; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.component.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.component.tsx index d9e3f0e4e2c99..6f25bbf8720cf 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.component.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.component.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { FoundWorkpad } from '../../../services/workpad'; +import { FoundWorkpad } from '../../../services/canvas_workpad_service'; import { UploadDropzone } from './upload_dropzone'; import { HomeEmptyPrompt } from './empty_prompt'; import { WorkpadTable } from './workpad_table'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.stories.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.stories.tsx index 52afd552bbc49..967419e9b8b06 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.stories.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.stories.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EuiPanel } from '@elastic/eui'; import { reduxDecorator } from '../../../../storybook'; -import { argTypes } from '../../../services/storybook'; +import { argTypes } from '../../../../storybook/constants'; import { MyWorkpads as Component } from './my_workpads'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.tsx index b75c8864ad495..44b3c5938af6c 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/my_workpads.tsx @@ -7,7 +7,7 @@ import React, { useState, useEffect, createContext, Dispatch, SetStateAction } from 'react'; import { useFindWorkpads } from '../hooks'; -import { FoundWorkpad } from '../../../services/workpad'; +import { FoundWorkpad } from '../../../services/canvas_workpad_service'; import { Loading } from '../loading'; import { MyWorkpads as Component } from './my_workpads.component'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.component.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.component.tsx index c64ab50ad8a09..f8e349351ba4c 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.component.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.component.tsx @@ -21,7 +21,7 @@ import { import moment from 'moment'; import { RoutingLink } from '../../routing'; -import { FoundWorkpad } from '../../../services/workpad'; +import { FoundWorkpad } from '../../../services/canvas_workpad_service'; import { WorkpadTableTools } from './workpad_table_tools'; import { WorkpadImport } from './workpad_import'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.stories.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.stories.tsx index 6675dea238cc4..f9418f35e6256 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.stories.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.stories.tsx @@ -9,9 +9,9 @@ import React, { useState, useEffect } from 'react'; import { EuiPanel } from '@elastic/eui'; import { reduxDecorator } from '../../../../storybook'; +import { argTypes } from '../../../../storybook/constants'; -import { argTypes } from '../../../services/storybook'; -import { getSomeWorkpads } from '../../../services/stubs/workpad'; +import { getSomeWorkpads } from '../../../services/mocks'; import { WorkpadTable as Component } from './workpad_table'; import { WorkpadsContext } from './my_workpads'; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.tsx index 6d88691f2eabe..7bbb3a57ab9ce 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table.tsx @@ -8,17 +8,16 @@ import React, { useContext } from 'react'; import { useSelector } from 'react-redux'; -import { canUserWrite as canUserWriteSelector } from '../../../state/selectors/app'; import type { State } from '../../../../types'; -import { usePlatformService } from '../../../services'; -import { useCloneWorkpad } from '../hooks'; +import { canUserWrite as canUserWriteSelector } from '../../../state/selectors/app'; import { useDownloadWorkpad } from '../../hooks'; +import { useCloneWorkpad } from '../hooks'; -import { WorkpadTable as Component } from './workpad_table.component'; +import { coreServices } from '../../../services/kibana_services'; import { WorkpadsContext } from './my_workpads'; +import { WorkpadTable as Component } from './workpad_table.component'; export const WorkpadTable = () => { - const platformService = usePlatformService(); const onCloneWorkpad = useCloneWorkpad(); const onExportWorkpad = useDownloadWorkpad(); const context = useContext(WorkpadsContext); @@ -33,7 +32,7 @@ export const WorkpadTable = () => { const { workpads } = context; - const dateFormat = platformService.getUISetting('dateFormat'); + const dateFormat = coreServices.uiSettings.get('dateFormat'); return ; }; diff --git a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table_tools.component.tsx b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table_tools.component.tsx index 251a40ff4d45d..148e1973352bc 100644 --- a/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table_tools.component.tsx +++ b/x-pack/plugins/canvas/public/components/home/my_workpads/workpad_table_tools.component.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { EuiButton, EuiToolTip, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { ConfirmModal } from '../../confirm_modal'; -import { FoundWorkpad } from '../../../services/workpad'; +import { FoundWorkpad } from '../../../services/canvas_workpad_service'; export interface Props { workpads: FoundWorkpad[]; diff --git a/x-pack/plugins/canvas/public/components/home/workpad_templates/workpad_templates.stories.tsx b/x-pack/plugins/canvas/public/components/home/workpad_templates/workpad_templates.stories.tsx index 92583ca845aa8..c6a3347f6c39a 100644 --- a/x-pack/plugins/canvas/public/components/home/workpad_templates/workpad_templates.stories.tsx +++ b/x-pack/plugins/canvas/public/components/home/workpad_templates/workpad_templates.stories.tsx @@ -9,7 +9,7 @@ import { EuiPanel } from '@elastic/eui'; import React from 'react'; import { reduxDecorator } from '../../../../storybook'; -import { argTypes } from '../../../services/storybook'; +import { argTypes } from '../../../../storybook/constants'; import { WorkpadTemplates as Component } from './workpad_templates'; diff --git a/x-pack/plugins/canvas/public/components/home_app/home_app.tsx b/x-pack/plugins/canvas/public/components/home_app/home_app.tsx index 086a737d525e9..54d9659f5a1d8 100644 --- a/x-pack/plugins/canvas/public/components/home_app/home_app.tsx +++ b/x-pack/plugins/canvas/public/components/home_app/home_app.tsx @@ -11,17 +11,16 @@ import { useDispatch } from 'react-redux'; import { getBaseBreadcrumb } from '../../lib/breadcrumbs'; import { resetWorkpad } from '../../state/actions/workpad'; import { HomeApp as Component } from './home_app.component'; -import { usePlatformService } from '../../services'; +import { coreServices } from '../../services/kibana_services'; export const HomeApp = () => { - const { setBreadcrumbs } = usePlatformService(); const dispatch = useDispatch(); const onLoad = () => dispatch(resetWorkpad()); const history = useHistory(); useEffect(() => { - setBreadcrumbs([getBaseBreadcrumb(history)]); - }, [setBreadcrumbs, history]); + coreServices.chrome.setBreadcrumbs([getBaseBreadcrumb(history)]); + }, [history]); return ; }; diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/use_download_workpad.ts b/x-pack/plugins/canvas/public/components/hooks/workpad/use_download_workpad.ts index dadf03a8fac5a..394274b1eb133 100644 --- a/x-pack/plugins/canvas/public/components/hooks/workpad/use_download_workpad.ts +++ b/x-pack/plugins/canvas/public/components/hooks/workpad/use_download_workpad.ts @@ -8,9 +8,10 @@ import { useCallback } from 'react'; import fileSaver from 'file-saver'; import { i18n } from '@kbn/i18n'; -import { useNotifyService, useWorkpadService } from '../../../services'; +import { useNotifyService } from '../../../services'; import { CanvasWorkpad } from '../../../../types'; import type { CanvasRenderedWorkpad } from '../../../../shareable_runtime/types'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; const strings = { getDownloadFailureErrorMessage: () => @@ -28,12 +29,12 @@ const strings = { export const useDownloadWorkpad = () => { const notifyService = useNotifyService(); - const workpadService = useWorkpadService(); const download = useDownloadWorkpadBlob(); return useCallback( async (workpadId: string) => { try { + const workpadService = getCanvasWorkpadService(); const workpad = await workpadService.get(workpadId); download(workpad, `canvas-workpad-${workpad.name}-${workpad.id}`); @@ -41,7 +42,7 @@ export const useDownloadWorkpad = () => { notifyService.error(err, { title: strings.getDownloadFailureErrorMessage() }); } }, - [workpadService, notifyService, download] + [notifyService, download] ); }; diff --git a/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts index 0a4e66917814d..50c3e527bbbae 100644 --- a/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts +++ b/x-pack/plugins/canvas/public/components/hooks/workpad/use_incoming_embeddable.ts @@ -12,7 +12,7 @@ import { ErrorStrings } from '../../../../i18n'; import { CANVAS_APP } from '../../../../common/lib'; import { decode } from '../../../../common/lib/embeddable_dataurl'; import { CanvasElement, CanvasPage } from '../../../../types'; -import { useEmbeddablesService, useLabsService, useNotifyService } from '../../../services'; +import { useNotifyService } from '../../../services'; // @ts-expect-error unconverted file import { addElement, fetchAllRenderables } from '../../../state/actions/elements'; // @ts-expect-error unconverted file @@ -24,16 +24,16 @@ import { } from '../../../state/actions/embeddable'; import { clearValue } from '../../../state/actions/resolved_args'; import { embeddableInputToExpression } from '../../../../canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression'; +import { embeddableService, presentationUtilService } from '../../../services/kibana_services'; const { actionsElements: strings } = ErrorStrings; export const useIncomingEmbeddable = (selectedPage: CanvasPage) => { - const embeddablesService = useEmbeddablesService(); - const labsService = useLabsService(); + const labsService = presentationUtilService.labsService; const dispatch = useDispatch(); const notifyService = useNotifyService(); const isByValueEnabled = labsService.isProjectEnabled('labs:canvas:byValueEmbeddable'); - const stateTransferService = embeddablesService.getStateTransfer(); + const stateTransferService = embeddableService.getStateTransfer(); // fetch incoming embeddable from state transfer service. const incomingEmbeddable = stateTransferService.getIncomingEmbeddablePackage(CANVAS_APP, true); diff --git a/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.tsx b/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.tsx index 19e786edfd5fb..5aeb8847ab887 100644 --- a/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.tsx +++ b/x-pack/plugins/canvas/public/components/saved_elements_modal/saved_elements_modal.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { camelCase } from 'lodash'; import { cloneSubgraphs } from '../../lib/clone_subgraphs'; -import { useNotifyService, useCustomElementService } from '../../services'; +import { useNotifyService } from '../../services'; // @ts-expect-error untyped local import { selectToplevelNodes } from '../../state/actions/transient'; // @ts-expect-error untyped local @@ -21,6 +21,7 @@ import { Props as ComponentProps, } from './saved_elements_modal.component'; import { PositionedElement, CustomElement } from '../../../types'; +import { getCustomElementService } from '../../services/canvas_custom_element_service'; const customElementAdded = 'elements-custom-added'; @@ -28,7 +29,7 @@ export type Props = Pick; export const SavedElementsModal = ({ onClose }: Props) => { const notifyService = useNotifyService(); - const customElementService = useCustomElementService(); + const customElementService = useMemo(() => getCustomElementService(), []); const dispatch = useDispatch(); const pageId = useSelector(getSelectedPage); const [customElements, setCustomElements] = useState([]); diff --git a/x-pack/plugins/canvas/public/components/workpad/workpad.tsx b/x-pack/plugins/canvas/public/components/workpad/workpad.tsx index 1e604a6deb850..6052e6951a8e9 100644 --- a/x-pack/plugins/canvas/public/components/workpad/workpad.tsx +++ b/x-pack/plugins/canvas/public/components/workpad/workpad.tsx @@ -24,10 +24,10 @@ import { useZoomHandlers } from '../../lib/app_handler_creators'; import { trackCanvasUiMetric, METRIC_TYPE } from '../../lib/ui_metric'; import { LAUNCHED_FULLSCREEN, LAUNCHED_FULLSCREEN_AUTOPLAY } from '../../../common/lib/constants'; import { WorkpadRoutingContext } from '../../routes/workpad'; -import { usePlatformService } from '../../services'; import { Workpad as WorkpadComponent, Props } from './workpad.component'; import { State } from '../../../types'; import { useIncomingEmbeddable } from '../hooks'; +import { coreServices } from '../../services/kibana_services'; type ContainerProps = Pick; @@ -40,9 +40,7 @@ export const Workpad: FC = (props) => { const { isFullscreen, setFullscreen, undo, redo, autoplayInterval, nextPage, previousPage } = useContext(WorkpadRoutingContext); - const platformService = usePlatformService(); - - const hasHeaderBanner = useObservable(platformService.hasHeaderBanner$()); + const hasHeaderBanner = useObservable(coreServices.chrome.hasHeaderBanner$()); const propsFromState = useSelector((state: State) => { const { width, height, id: workpadId, css: workpadCss } = getWorkpad(state); diff --git a/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts b/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts index bdccc8040c5de..9aa9aecdfd516 100644 --- a/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts +++ b/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts @@ -5,17 +5,19 @@ * 2.0. */ +import { useMemo } from 'react'; import { AstFunction, fromExpression } from '@kbn/interpreter'; import { shallowEqual, useSelector } from 'react-redux'; + import { State } from '../../../../types'; import { getFiltersByFilterExpressions } from '../../../lib/filter'; import { adaptCanvasFilter } from '../../../lib/filter_adapters'; -import { useFiltersService } from '../../../services'; +import { getCanvasFiltersService } from '../../../services/canvas_filters_service'; const extractExpressionAST = (filters: string[]) => fromExpression(filters.join(' | ')); export function useCanvasFilters(filterExprsToGroupBy: AstFunction[] = []) { - const filtersService = useFiltersService(); + const filtersService = useMemo(() => getCanvasFiltersService(), []); const filterExpressions = useSelector( (state: State) => filtersService.getFilters(state), shallowEqual diff --git a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx index fd644903ac25d..06d20e919dcbe 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/editor_menu/editor_menu.tsx @@ -21,11 +21,6 @@ import { import { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public/actions'; import { trackCanvasUiMetric, METRIC_TYPE } from '../../../lib/ui_metric'; -import { - useEmbeddablesService, - useUiActionsService, - useVisualizationsService, -} from '../../../services'; import { CANVAS_APP } from '../../../../common/lib'; import { ElementSpec } from '../../../../types'; import { EditorMenu as Component } from './editor_menu.component'; @@ -33,6 +28,11 @@ import { embeddableInputToExpression } from '../../../../canvas_plugin_src/rende import { EmbeddableInput as CanvasEmbeddableInput } from '../../../../canvas_plugin_src/expression_types'; import { useCanvasApi } from '../../hooks/use_canvas_api'; import { ADD_CANVAS_ELEMENT_TRIGGER } from '../../../state/triggers/add_canvas_element_trigger'; +import { + embeddableService, + uiActionsService, + visualizationsService, +} from '../../../services/kibana_services'; interface Props { /** @@ -47,18 +47,15 @@ interface UnwrappedEmbeddableFactory { } export const EditorMenu: FC = ({ addElement }) => { - const embeddablesService = useEmbeddablesService(); const { pathname, search, hash } = useLocation(); - const stateTransferService = embeddablesService.getStateTransfer(); - const visualizationsService = useVisualizationsService(); - const uiActions = useUiActionsService(); + const stateTransferService = embeddableService.getStateTransfer(); const canvasApi = useCanvasApi(); const [addPanelActions, setAddPanelActions] = useState>>([]); const embeddableFactories = useMemo( - () => (embeddablesService ? Array.from(embeddablesService.getEmbeddableFactories()) : []), - [embeddablesService] + () => (embeddableService ? Array.from(embeddableService.getEmbeddableFactories()) : []), + [] ); const [unwrappedEmbeddableFactories, setUnwrappedEmbeddableFactories] = useState< @@ -79,7 +76,7 @@ export const EditorMenu: FC = ({ addElement }) => { useEffect(() => { let mounted = true; async function loadPanelActions() { - const registeredActions = await uiActions?.getTriggerCompatibleActions?.( + const registeredActions = await uiActionsService.getTriggerCompatibleActions( ADD_CANVAS_ELEMENT_TRIGGER, { embeddable: canvasApi } ); @@ -89,7 +86,7 @@ export const EditorMenu: FC = ({ addElement }) => { return () => { mounted = false; }; - }, [uiActions, canvasApi]); + }, [canvasApi]); const createNewVisType = useCallback( (visType?: BaseVisType | VisTypeAlias) => () => { diff --git a/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx b/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx index 75d6f8064f32a..6e6ca58f0dd72 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/labs_control/labs_control.tsx @@ -5,13 +5,14 @@ * 2.0. */ -import React, { useState } from 'react'; import { EuiButtonEmpty, EuiNotificationBadge } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import React, { useState } from 'react'; import { LazyLabsFlyout, withSuspense } from '@kbn/presentation-util-plugin/public'; -import { useLabsService } from '../../../services'; +import { UI_SETTINGS } from '../../../../common'; +import { coreServices, presentationUtilService } from '../../../services/kibana_services'; const strings = { getLabsButtonLabel: () => @@ -23,14 +24,13 @@ const strings = { const Flyout = withSuspense(LazyLabsFlyout, null); export const LabsControl = () => { - const { isLabsEnabled, getProjects } = useLabsService(); const [isShown, setIsShown] = useState(false); - if (!isLabsEnabled()) { + if (!coreServices.uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI)) { return null; } - const projects = getProjects(['canvas']); + const projects = presentationUtilService.labsService.getProjects(['canvas']); const overrideCount = Object.values(projects).filter( (project) => project.status.isOverride ).length; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/hooks/use_download_runtime.ts b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/hooks/use_download_runtime.ts index cd1635d65a573..49bd93c290ce8 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/hooks/use_download_runtime.ts +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/flyout/hooks/use_download_runtime.ts @@ -5,14 +5,16 @@ * 2.0. */ -import { useCallback } from 'react'; -import fileSaver from 'file-saver'; import { i18n } from '@kbn/i18n'; +import fileSaver from 'file-saver'; +import { useCallback } from 'react'; import { API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD } from '../../../../../../common/lib/constants'; import { ZIP } from '../../../../../../i18n/constants'; -import { usePlatformService, useNotifyService, useWorkpadService } from '../../../../../services'; import type { CanvasRenderedWorkpad } from '../../../../../../shareable_runtime/types'; +import { useNotifyService } from '../../../../../services'; +import { coreServices } from '../../../../../services/kibana_services'; +import { getCanvasWorkpadService } from '../../../../../services/canvas_workpad_service'; const strings = { getDownloadRuntimeFailureErrorMessage: () => @@ -35,28 +37,28 @@ const strings = { }; export const useDownloadRuntime = () => { - const platformService = usePlatformService(); const notifyService = useNotifyService(); const downloadRuntime = useCallback(() => { try { - const path = `${platformService.getBasePath()}${API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD}`; + const path = `${coreServices.http.basePath.get()}${API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD}`; window.open(path); return; } catch (err) { notifyService.error(err, { title: strings.getDownloadRuntimeFailureErrorMessage() }); } - }, [platformService, notifyService]); + }, [notifyService]); return downloadRuntime; }; export const useDownloadZippedRuntime = () => { - const workpadService = useWorkpadService(); const notifyService = useNotifyService(); const downloadZippedRuntime = useCallback( (workpad: CanvasRenderedWorkpad) => { + const workpadService = getCanvasWorkpadService(); + const downloadZip = async () => { try { let runtimeZipBlob: Blob | undefined; @@ -80,7 +82,7 @@ export const useDownloadZippedRuntime = () => { downloadZip(); }, - [notifyService, workpadService] + [notifyService] ); return downloadZippedRuntime; }; diff --git a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx index c66336a9153c0..e4239864c1915 100644 --- a/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx +++ b/x-pack/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx @@ -9,11 +9,11 @@ import React, { useCallback } from 'react'; import { useSelector } from 'react-redux'; import { i18n } from '@kbn/i18n'; import { State } from '../../../../types'; -import { useReportingService, usePlatformService } from '../../../services'; import { getPages, getWorkpad } from '../../../state/selectors/workpad'; import { useDownloadWorkpad } from '../../hooks'; import { ShareMenu as ShareMenuComponent } from './share_menu.component'; import { getPdfJobParams } from './utils'; +import { kibanaVersion, reportingService } from '../../../services/kibana_services'; const strings = { getUnknownExportErrorMessage: (type: string) => @@ -27,32 +27,30 @@ const strings = { export const ShareMenu = () => { const downloadWorkpad = useDownloadWorkpad(); - const reportingService = useReportingService(); - const platformService = usePlatformService(); const { workpad, pageCount } = useSelector((state: State) => ({ workpad: getWorkpad(state), pageCount: getPages(state).length, })); - const ReportingPanelPDFComponent = reportingService.getReportingPanelPDFComponent(); - const sharingData = { workpad, pageCount, }; - const ReportingComponent = - ReportingPanelPDFComponent !== null - ? ({ onClose }: { onClose: () => void }) => ( - getPdfJobParams(sharingData, platformService.getKibanaVersion())} + const ReportingComponent = reportingService + ? ({ onClose }: { onClose: () => void }) => { + const ReportingPanelPDFV2 = reportingService!.components.ReportingPanelPDFV2; + return ( + getPdfJobParams(sharingData, kibanaVersion)} layoutOption="canvas" onClose={onClose} objectId={workpad.id} /> - ) - : null; + ); + } + : null; const onExport = useCallback( (type: string) => { diff --git a/x-pack/plugins/canvas/public/functions/filters.ts b/x-pack/plugins/canvas/public/functions/filters.ts index a168020b6eef8..a37953657e157 100644 --- a/x-pack/plugins/canvas/public/functions/filters.ts +++ b/x-pack/plugins/canvas/public/functions/filters.ts @@ -7,10 +7,11 @@ import { fromExpression } from '@kbn/interpreter'; import { get } from 'lodash'; -import { pluginServices } from '../services'; import type { FiltersFunction } from '../../common/functions'; import { buildFiltersFunction } from '../../common/functions'; import { InitializeArguments } from '.'; +import { getCanvasFiltersService } from '../services/canvas_filters_service'; +import { getCanvasExpressionService } from '../services/canvas_expressions_service'; export interface Arguments { group: string[]; @@ -40,7 +41,8 @@ function getFiltersByGroup(allFilters: string[], groups?: string[], ungrouped = export function filtersFunctionFactory(initialize: InitializeArguments): () => FiltersFunction { const fn: FiltersFunction['fn'] = (input, { group, ungrouped }) => { - const { expressions, filters: filtersService } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); + const filtersService = getCanvasFiltersService(); const filterList = getFiltersByGroup(filtersService.getFilters(), group, ungrouped); diff --git a/x-pack/plugins/canvas/public/lib/assets.ts b/x-pack/plugins/canvas/public/lib/assets.ts index d7fd0ecbac57f..b51cda9216fbc 100644 --- a/x-pack/plugins/canvas/public/lib/assets.ts +++ b/x-pack/plugins/canvas/public/lib/assets.ts @@ -6,8 +6,8 @@ */ import { i18n } from '@kbn/i18n'; import { AssetType, CanvasAsset } from '../../types'; -import { CanvasNotifyService } from '../services/notify'; import { getId } from './get_id'; +import { getCanvasNotifyService } from '../services/canvas_notify_service'; const strings = { getSaveFailureTitle: () => @@ -32,7 +32,8 @@ export const createAsset = (type: AssetType['type'], content: AssetType['value'] '@created': new Date().toISOString(), }); -export const notifyError = (err: any, notifyErrorFn: CanvasNotifyService['error']) => { +export const notifyError = (err: any) => { + const { error: notifyErrorFn } = getCanvasNotifyService(); const statusCode = err.response && err.response.status; switch (statusCode) { case 400: diff --git a/x-pack/plugins/canvas/public/lib/create_handlers.ts b/x-pack/plugins/canvas/public/lib/create_handlers.ts index 374bdaff99721..8b78914d77071 100644 --- a/x-pack/plugins/canvas/public/lib/create_handlers.ts +++ b/x-pack/plugins/canvas/public/lib/create_handlers.ts @@ -12,8 +12,10 @@ import { } from '@kbn/expressions-plugin/public'; import { updateEmbeddableExpression, fetchEmbeddableRenderable } from '../state/actions/embeddable'; import { RendererHandlers, CanvasElement } from '../../types'; -import { pluginServices } from '../services'; +import { getCanvasFiltersService } from '../services/canvas_filters_service'; import { clearValue } from '../state/actions/resolved_args'; +// @ts-expect-error unconverted file +import { fetchAllRenderables } from '../state/actions/elements'; // This class creates stub handlers to ensure every element and renderer fulfills the contract. // TODO: consider warning if these methods are invoked but not implemented by the renderer...? @@ -80,7 +82,7 @@ export const createDispatchedHandlerFactory = ( oldElement = element; } - const { filters } = pluginServices.getServices(); + const filters = getCanvasFiltersService(); const handlers: RendererHandlers & { event: IInterpreterRenderHandlers['event']; @@ -94,6 +96,7 @@ export const createDispatchedHandlerFactory = ( break; case 'applyFilterAction': filters.updateFilter(element.id, event.data); + dispatch(fetchAllRenderables()); break; case 'onComplete': this.onComplete(event.data); diff --git a/x-pack/plugins/canvas/public/lib/data_view_helpers.ts b/x-pack/plugins/canvas/public/lib/data_view_helpers.ts new file mode 100644 index 0000000000000..0bec688f6788a --- /dev/null +++ b/x-pack/plugins/canvas/public/lib/data_view_helpers.ts @@ -0,0 +1,26 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { dataViewsService } from '../services/kibana_services'; +import { getCanvasNotifyService } from '../services/canvas_notify_service'; +import { ErrorStrings } from '../../i18n'; + +export const getDataViews = async () => { + try { + return await dataViewsService.getIdsWithTitle(); + } catch (e) { + const { esService: strings } = ErrorStrings; + getCanvasNotifyService().error(e, { title: strings.getIndicesFetchErrorMessage() }); + } + return []; +}; + +export const getDataViewFields = async (dataViewTitle: string) => { + const dataView = await dataViewsService.create({ title: dataViewTitle }); + + return dataView.fields.filter((field) => !field.name.startsWith('_')).map((field) => field.name); +}; diff --git a/x-pack/plugins/canvas/public/lib/element_handler_creators.ts b/x-pack/plugins/canvas/public/lib/element_handler_creators.ts index 82b9827529040..72a7df3a26775 100644 --- a/x-pack/plugins/canvas/public/lib/element_handler_creators.ts +++ b/x-pack/plugins/canvas/public/lib/element_handler_creators.ts @@ -8,10 +8,11 @@ import { camelCase } from 'lodash'; import { getClipboardData, setClipboardData } from './clipboard'; import { cloneSubgraphs } from './clone_subgraphs'; -import { pluginServices } from '../services'; import { getId } from './get_id'; import { PositionedElement } from '../../types'; import { ELEMENT_NUDGE_OFFSET, ELEMENT_SHIFT_OFFSET } from '../../common/lib/constants'; +import { getCanvasNotifyService } from '../services/canvas_notify_service'; +import { getCustomElementService } from '../services/canvas_custom_element_service'; const extractId = (node: { id: string }): string => node.id; @@ -71,8 +72,8 @@ export const basicHandlerCreators = { createCustomElement: ({ selectedNodes }: Props) => (name = '', description = '', image = ''): void => { - const notifyService = pluginServices.getServices().notify; - const customElementService = pluginServices.getServices().customElement; + const notifyService = getCanvasNotifyService(); + const customElementService = getCustomElementService(); if (selectedNodes.length) { const content = JSON.stringify({ selectedNodes }); @@ -145,7 +146,7 @@ export const clipboardHandlerCreators = { cutNodes: ({ pageId, removeNodes, selectedNodes }: Props) => (): void => { - const notifyService = pluginServices.getServices().notify; + const notifyService = getCanvasNotifyService(); if (selectedNodes.length) { setClipboardData({ selectedNodes }); @@ -156,7 +157,7 @@ export const clipboardHandlerCreators = { copyNodes: ({ selectedNodes }: Props) => (): void => { - const notifyService = pluginServices.getServices().notify; + const notifyService = getCanvasNotifyService(); if (selectedNodes.length) { setClipboardData({ selectedNodes }); diff --git a/x-pack/plugins/canvas/public/lib/fullscreen.js b/x-pack/plugins/canvas/public/lib/fullscreen.js index fd4e0b65785b9..50a9578b07b78 100644 --- a/x-pack/plugins/canvas/public/lib/fullscreen.js +++ b/x-pack/plugins/canvas/public/lib/fullscreen.js @@ -5,22 +5,21 @@ * 2.0. */ -import { pluginServices } from '../services'; +import { coreServices } from '../services/kibana_services'; export const fullscreenClass = 'canvas-isFullscreen'; export function setFullscreen(fullscreen, doc = document) { - const platformService = pluginServices.getServices().platform; const enabled = Boolean(fullscreen); const body = doc.querySelector('body'); const bodyClassList = body.classList; const isFullscreen = bodyClassList.contains(fullscreenClass); if (enabled && !isFullscreen) { - platformService.setFullscreen(false); + coreServices.chrome.setIsVisible(false); bodyClassList.add(fullscreenClass); } else if (!enabled && isFullscreen) { bodyClassList.remove(fullscreenClass); - platformService.setFullscreen(true); + coreServices.chrome.setIsVisible(true); } } diff --git a/x-pack/plugins/canvas/public/lib/template_service.ts b/x-pack/plugins/canvas/public/lib/template_service.ts index d5ec467f18740..481733b781d85 100644 --- a/x-pack/plugins/canvas/public/lib/template_service.ts +++ b/x-pack/plugins/canvas/public/lib/template_service.ts @@ -9,12 +9,11 @@ import { API_ROUTE_TEMPLATES } from '../../common/lib/constants'; import { fetch } from '../../common/lib/fetch'; -import { pluginServices } from '../services'; import { CanvasTemplate } from '../../types'; +import { coreServices } from '../services/kibana_services'; const getApiPath = function () { - const platformService = pluginServices.getServices().platform; - const basePath = platformService.getBasePath(); + const basePath = coreServices.http.basePath.get(); return `${basePath}${API_ROUTE_TEMPLATES}`; }; diff --git a/x-pack/plugins/canvas/public/plugin.tsx b/x-pack/plugins/canvas/public/plugin.tsx index 5f385ce5f079b..bd4e920a56f7e 100644 --- a/x-pack/plugins/canvas/public/plugin.tsx +++ b/x-pack/plugins/canvas/public/plugin.tsx @@ -38,6 +38,7 @@ import { initLoadingIndicator } from './lib/loading_indicator'; import { getPluginApi, CanvasApi } from './plugin_api'; import { setupExpressions } from './setup_expressions'; import { addCanvasElementTrigger } from './state/triggers/add_canvas_element_trigger'; +import { setKibanaServices, untilPluginStartServicesReady } from './services/kibana_services'; export type { CoreStart, CoreSetup }; @@ -121,22 +122,13 @@ export class CanvasPlugin setupExpressions({ coreSetup, setupPlugins }); // Get start services - const [coreStart, startPlugins] = await coreSetup.getStartServices(); + const [[coreStart, startPlugins]] = await Promise.all([ + coreSetup.getStartServices(), + untilPluginStartServicesReady(), + ]); srcPlugin.start(coreStart, startPlugins); - const { pluginServices } = await import('./services'); - const { pluginServiceRegistry } = await import('./services/kibana'); - - pluginServices.setRegistry( - pluginServiceRegistry.start({ - coreStart, - startPlugins, - appUpdater: this.appUpdater, - initContext: this.initContext, - }) - ); - const { expressions, presentationUtil } = startPlugins; await presentationUtil.registerExpressionsLanguage( Object.values(expressions.getFunctions()) @@ -154,7 +146,13 @@ export class CanvasPlugin this.appUpdater ); - const unmount = renderApp({ coreStart, startPlugins, params, canvasStore, pluginServices }); + const unmount = renderApp({ + coreStart, + startPlugins, + params, + canvasStore, + appUpdater: this.appUpdater, + }); return () => { unmount(); @@ -190,6 +188,7 @@ export class CanvasPlugin } public start(coreStart: CoreStart, startPlugins: CanvasStartDeps) { + setKibanaServices(coreStart, startPlugins, this.initContext); initLoadingIndicator(coreStart.http.addLoadingCountSource); } } diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_fullscreen_presentation_helper.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_fullscreen_presentation_helper.ts index ca66fa227e4eb..e517f74030c87 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_fullscreen_presentation_helper.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_fullscreen_presentation_helper.ts @@ -6,32 +6,30 @@ */ import { useContext, useEffect } from 'react'; import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { usePlatformService } from '../../../services'; import { WorkpadRoutingContext } from '..'; +import { coreServices } from '../../../services/kibana_services'; const fullscreenClass = 'canvas-isFullscreen'; export const useFullscreenPresentationHelper = () => { const { isFullscreen } = useContext(WorkpadRoutingContext); - const { setFullscreen } = usePlatformService(); - useEffect(() => { const body = document.querySelector('body'); const bodyClassList = body!.classList; const hasFullscreenClass = bodyClassList.contains(fullscreenClass); if (isFullscreen && !hasFullscreenClass) { - setFullscreen(false); + coreServices.chrome.setIsVisible(false); bodyClassList.add(fullscreenClass); } else if (!isFullscreen && hasFullscreenClass) { bodyClassList.remove(fullscreenClass); - setFullscreen(true); + coreServices.chrome.setIsVisible(true); } - }, [isFullscreen, setFullscreen]); + }, [isFullscreen]); // Remove fullscreen when component unmounts useEffectOnce(() => () => { - setFullscreen(true); + coreServices.chrome.setIsVisible(true); document.querySelector('body')?.classList.remove(fullscreenClass); }); }; diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.test.tsx b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.test.tsx index 0d73fe49601c8..1ba0dacd8c143 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.test.tsx +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.test.tsx @@ -7,6 +7,7 @@ import { renderHook } from '@testing-library/react-hooks'; import { useWorkpad } from './use_workpad'; +import { spacesService } from '../../../services/kibana_services'; const mockDispatch = jest.fn(); const mockSelector = jest.fn(); @@ -25,21 +26,22 @@ const workpadResponse = { assets, }; -// Mock the hooks and actions used by the UseWorkpad hook +// Mock the hooks, actions, and services used by the UseWorkpad hook jest.mock('react-redux', () => ({ useDispatch: () => mockDispatch, useSelector: () => mockSelector, })); -jest.mock('../../../services', () => ({ - useWorkpadService: () => ({ - resolve: mockResolveWorkpad, - }), - usePlatformService: () => ({ - redirectLegacyUrl: mockRedirectLegacyUrl, - }), +jest.mock('../../../services/canvas_workpad_service', () => ({ + getCanvasWorkpadService: () => { + return { + resolve: mockResolveWorkpad, + }; + }, })); +spacesService!.ui.redirectLegacyUrl = mockRedirectLegacyUrl; + jest.mock('../../../state/actions/workpad', () => ({ setWorkpad: (payload: any) => ({ type: 'setWorkpad', diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts index 61908d96828fd..c02432477a840 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad.ts @@ -8,7 +8,6 @@ import { useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { useDispatch, useSelector } from 'react-redux'; -import { useWorkpadService, usePlatformService } from '../../../services'; import { getWorkpad } from '../../../state/selectors/workpad'; import { setWorkpad } from '../../../state/actions/workpad'; // @ts-expect-error @@ -16,7 +15,11 @@ import { setAssets } from '../../../state/actions/assets'; // @ts-expect-error import { setZoomScale } from '../../../state/actions/transient'; import { CanvasWorkpad } from '../../../../types'; -import type { ResolveWorkpadResponse } from '../../../services/workpad'; +import { + ResolveWorkpadResponse, + getCanvasWorkpadService, +} from '../../../services/canvas_workpad_service'; +import { spacesService } from '../../../services/kibana_services'; const getWorkpadLabel = () => i18n.translate('xpack.canvas.workpadResolve.redirectLabel', { @@ -32,9 +35,6 @@ export const useWorkpad = ( loadPages: boolean = true, getRedirectPath: (workpadId: string) => string ): [CanvasWorkpad | undefined, string | Error | undefined] => { - const workpadService = useWorkpadService(); - const workpadResolve = workpadService.resolve; - const platformService = usePlatformService(); const dispatch = useDispatch(); const storedWorkpad = useSelector(getWorkpad); const [error, setError] = useState(undefined); @@ -47,14 +47,12 @@ export const useWorkpad = ( const { workpad: { assets, ...workpad }, ...resolveProps - } = await workpadResolve(workpadId); - + } = await getCanvasWorkpadService().resolve(workpadId); setResolveInfo({ id: workpadId, ...resolveProps }); // If it's an alias match, we know we are going to redirect so don't even dispatch that we got the workpad if (storedWorkpad.id !== workpadId && resolveProps.outcome !== 'aliasMatch') { workpad.aliasId = resolveProps.aliasId; - dispatch(setAssets(assets)); dispatch(setWorkpad(workpad, { loadPages })); dispatch(setZoomScale(1)); @@ -63,7 +61,7 @@ export const useWorkpad = ( setError(e as Error | string); } })(); - }, [workpadId, dispatch, setError, loadPages, workpadResolve, storedWorkpad.id]); + }, [workpadId, dispatch, setError, loadPages, storedWorkpad.id]); useEffect(() => { // If the resolved info is not for the current workpad id, bail out @@ -75,16 +73,16 @@ export const useWorkpad = ( if (!resolveInfo) return; const { aliasId, outcome, aliasPurpose } = resolveInfo; - if (outcome === 'aliasMatch' && platformService.redirectLegacyUrl && aliasId) { + if (outcome === 'aliasMatch' && spacesService && aliasId) { const redirectPath = getRedirectPath(aliasId); - await platformService.redirectLegacyUrl({ + await spacesService.ui.redirectLegacyUrl({ path: `#${redirectPath}`, aliasPurpose, objectNoun: getWorkpadLabel(), }); } })(); - }, [workpadId, resolveInfo, getRedirectPath, platformService]); + }, [workpadId, resolveInfo, getRedirectPath]); return [storedWorkpad.id === workpadId ? storedWorkpad : undefined, error]; }; diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.test.tsx b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.test.tsx index 395cf774760fd..3193ad3dd79e5 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.test.tsx +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.test.tsx @@ -19,12 +19,17 @@ jest.mock('react-redux', () => ({ useSelector: (selector: any) => selector(mockGetState()), })); +jest.mock('../../../services/canvas_workpad_service', () => ({ + getCanvasWorkpadService: () => { + return { + updateWorkpad: mockUpdateWorkpad, + updateAssets: mockUpdateAssets, + update: mockUpdate, + }; + }, +})); + jest.mock('../../../services', () => ({ - useWorkpadService: () => ({ - updateWorkpad: mockUpdateWorkpad, - updateAssets: mockUpdateAssets, - update: mockUpdate, - }), useNotifyService: () => ({ error: mockNotifyError, }), diff --git a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.ts b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.ts index 45e21e59717ad..f0f885c94eabc 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.ts +++ b/x-pack/plugins/canvas/public/routes/workpad/hooks/use_workpad_persist.ts @@ -10,13 +10,10 @@ import { useSelector } from 'react-redux'; import { CanvasWorkpad, State } from '../../../../types'; import { getWorkpad } from '../../../state/selectors/workpad'; import { canUserWrite } from '../../../state/selectors/app'; -import { useWorkpadService, useNotifyService } from '../../../services'; import { notifyError } from '../../../lib/assets'; +import { getCanvasWorkpadService } from '../../../services/canvas_workpad_service'; export const useWorkpadPersist = () => { - const service = useWorkpadService(); - const notifyService = useNotifyService(); - // Watch for workpad state and then persist those changes const [workpad, canWrite]: [CanvasWorkpad, boolean] = useSelector((state: State) => [ getWorkpad(state), @@ -30,10 +27,12 @@ export const useWorkpadPersist = () => { useEffect(() => { if (canWrite) { if (workpadChanged) { - service.updateWorkpad(workpad.id, workpad).catch((err) => { - notifyError(err, notifyService.error); - }); + getCanvasWorkpadService() + .updateWorkpad(workpad.id, workpad) + .catch((err) => { + notifyError(err); + }); } } - }, [service, workpad, workpadChanged, canWrite, notifyService.error]); + }, [workpad, workpadChanged, canWrite]); }; diff --git a/x-pack/plugins/canvas/public/routes/workpad/workpad_presentation_helper.tsx b/x-pack/plugins/canvas/public/routes/workpad/workpad_presentation_helper.tsx index 0dfb4dd8fbf78..bde100182788e 100644 --- a/x-pack/plugins/canvas/public/routes/workpad/workpad_presentation_helper.tsx +++ b/x-pack/plugins/canvas/public/routes/workpad/workpad_presentation_helper.tsx @@ -14,7 +14,7 @@ import { getWorkpad } from '../../state/selectors/workpad'; import { useFullscreenPresentationHelper } from './hooks/use_fullscreen_presentation_helper'; import { useAutoplayHelper } from './hooks/use_autoplay_helper'; import { useRefreshHelper } from './hooks/use_refresh_helper'; -import { usePlatformService } from '../../services'; +import { coreServices, spacesService } from '../../services/kibana_services'; const getWorkpadLabel = () => i18n.translate('xpack.canvas.workpadConflict.redirectLabel', { @@ -22,7 +22,6 @@ const getWorkpadLabel = () => }); export const WorkpadPresentationHelper: FC> = ({ children }) => { - const platformService = usePlatformService(); const workpad = useSelector(getWorkpad); useFullscreenPresentationHelper(); useAutoplayHelper(); @@ -30,18 +29,18 @@ export const WorkpadPresentationHelper: FC> = ({ chil const history = useHistory(); useEffect(() => { - platformService.setBreadcrumbs([ + coreServices.chrome.setBreadcrumbs([ getBaseBreadcrumb(history), getWorkpadBreadcrumb({ name: workpad.name }), ]); - }, [workpad.name, platformService, history]); + }, [workpad.name, history]); useEffect(() => { setDocTitle(workpad.name || getUntitledWorkpadLabel()); }, [workpad.name, workpad.id]); const conflictElement = workpad.aliasId - ? platformService.getLegacyUrlConflict?.({ + ? spacesService?.ui.components.getLegacyUrlConflict({ objectNoun: getWorkpadLabel(), currentObjectId: workpad.id, otherObjectId: workpad.aliasId, diff --git a/x-pack/plugins/canvas/public/services/canvas_custom_element_service.ts b/x-pack/plugins/canvas/public/services/canvas_custom_element_service.ts new file mode 100644 index 0000000000000..1f0e13d2fbeae --- /dev/null +++ b/x-pack/plugins/canvas/public/services/canvas_custom_element_service.ts @@ -0,0 +1,62 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { API_ROUTE_CUSTOM_ELEMENT } from '../../common/lib'; +import { CustomElement } from '../../types'; +import { coreServices } from './kibana_services'; + +export interface CustomElementFindResponse { + total: number; + customElements: CustomElement[]; +} + +class CanvasCustomElementService { + public apiPath = `${API_ROUTE_CUSTOM_ELEMENT}`; + + public async create(customElement: CustomElement) { + await coreServices.http.post(this.apiPath, { + body: JSON.stringify(customElement), + version: '1', + }); + } + + public async get(customElementId: string): Promise { + return await coreServices.http + .get<{ data: CustomElement }>(`${this.apiPath}/${customElementId}`, { version: '1' }) + .then(({ data: element }) => element); + } + + public async update(id: string, element: Partial) { + await coreServices.http.put(`${this.apiPath}/${id}`, { + body: JSON.stringify(element), + version: '1', + }); + } + + public async remove(id: string) { + await coreServices.http.delete(`${this.apiPath}/${id}`, { version: '1' }); + } + + public async find(searchTerm: string): Promise { + return await coreServices.http.get(`${this.apiPath}/find`, { + query: { + name: searchTerm, + perPage: 10000, + }, + version: '1', + }); + } +} + +let canvasCustomElementService: CanvasCustomElementService; + +export const getCustomElementService = () => { + if (!canvasCustomElementService) { + canvasCustomElementService = new CanvasCustomElementService(); + } + return canvasCustomElementService; +}; diff --git a/x-pack/plugins/canvas/public/services/kibana/expressions.ts b/x-pack/plugins/canvas/public/services/canvas_expressions_service.ts similarity index 65% rename from x-pack/plugins/canvas/public/services/kibana/expressions.ts rename to x-pack/plugins/canvas/public/services/canvas_expressions_service.ts index 248cd462bea90..0621c3e89416c 100644 --- a/x-pack/plugins/canvas/public/services/kibana/expressions.ts +++ b/x-pack/plugins/canvas/public/services/canvas_expressions_service.ts @@ -4,34 +4,29 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { fromExpression, getType } from '@kbn/interpreter'; import { ExpressionAstExpression, ExpressionExecutionParams, ExpressionValue, } from '@kbn/expressions-plugin/common'; +import { fromExpression, getType } from '@kbn/interpreter'; import { pluck } from 'rxjs'; -import { ExpressionsServiceStart } from '@kbn/expressions-plugin/public'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { buildEmbeddableFilters } from '../../../common/lib/build_embeddable_filters'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasFiltersService } from './filters'; -import { CanvasNotifyService } from '../notify'; +import { buildEmbeddableFilters } from '../../common/lib/build_embeddable_filters'; +import { expressionsService } from './kibana_services'; +import { getCanvasNotifyService } from './canvas_notify_service'; +import { getCanvasFiltersService } from './canvas_filters_service'; interface Options { castToRender?: boolean; } -export class ExpressionsService { - private filters: CanvasFiltersService; - private notify: CanvasNotifyService; +class ExpressionsService { + private notifyService; + private filtersService; - constructor( - private readonly expressions: ExpressionsServiceStart, - { filters, notify }: CanvasExpressionsServiceRequiredServices - ) { - this.filters = filters; - this.notify = notify; + constructor() { + this.notifyService = getCanvasNotifyService(); + this.filtersService = getCanvasFiltersService(); } async interpretAst( @@ -51,7 +46,7 @@ export class ExpressionsService { input: ExpressionValue = null, context?: ExpressionExecutionParams ): Promise { - return await this.expressions + return await expressionsService .execute(ast, input, { ...context, namespace: 'canvas' }) .getData() .pipe(pluck('result')) @@ -92,22 +87,22 @@ export class ExpressionsService { throw new Error(`Ack! I don't know how to render a '${getType(renderable)}'`); } catch (err) { - this.notify.error(err); + this.notifyService.error(err); throw err; } } getRenderer(name: string) { - return this.expressions.getRenderer(name); + return expressionsService.getRenderer(name); } getFunctions() { - return this.expressions.getFunctions(); + return expressionsService.getFunctions(); } private async getFilters() { - const filtersList = this.filters.getFilters(); - const context = this.filters.getFiltersContext(); + const filtersList = this.filtersService.getFilters(); + const context = this.filtersService.getFiltersContext(); const filterExpression = filtersList.join(' | '); const filterAST = fromExpression(filterExpression); return await this.interpretAstWithContext(filterAST, null, context); @@ -122,19 +117,11 @@ export class ExpressionsService { } } -export type CanvasExpressionsService = ExpressionsService; -export interface CanvasExpressionsServiceRequiredServices { - notify: CanvasNotifyService; - filters: CanvasFiltersService; -} - -export type CanvasExpressionsServiceFactory = KibanaPluginServiceFactory< - CanvasExpressionsService, - CanvasStartDeps, - CanvasExpressionsServiceRequiredServices ->; +let canvasExpressionsService: ExpressionsService; -export const expressionsServiceFactory: CanvasExpressionsServiceFactory = ( - { startPlugins }, - requiredServices -) => new ExpressionsService(startPlugins.expressions, requiredServices); +export const getCanvasExpressionService = () => { + if (!canvasExpressionsService) { + canvasExpressionsService = new ExpressionsService(); + } + return canvasExpressionsService; +}; diff --git a/x-pack/plugins/canvas/public/services/kibana/filters.ts b/x-pack/plugins/canvas/public/services/canvas_filters_service.ts similarity index 51% rename from x-pack/plugins/canvas/public/services/kibana/filters.ts rename to x-pack/plugins/canvas/public/services/canvas_filters_service.ts index 793b073aaf231..e678e9b30963f 100644 --- a/x-pack/plugins/canvas/public/services/kibana/filters.ts +++ b/x-pack/plugins/canvas/public/services/canvas_filters_service.ts @@ -5,25 +5,21 @@ * 2.0. */ -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; // @ts-expect-error untyped local -import { getState, getStore } from '../../state/store'; -import { State } from '../../../types'; -import { getGlobalFilters, getWorkpadVariablesAsObject } from '../../state/selectors/workpad'; -import { CanvasStartDeps } from '../../plugin'; +import { getState, getStore } from '../state/store'; +import { State } from '../../types'; +import { getGlobalFilters, getWorkpadVariablesAsObject } from '../state/selectors/workpad'; // @ts-expect-error untyped local -import { setFilter } from '../../state/actions/elements'; - -export class FiltersService { - constructor() {} +import { setFilter } from '../state/actions/filters'; +class FiltersService { getFilters(state: State = getState()) { return getGlobalFilters(state); } updateFilter(filterId: string, filterExpression: string) { const { dispatch } = getStore(); - dispatch(setFilter(filterExpression, filterId, true)); + dispatch(setFilter(filterExpression, filterId)); } getFiltersContext(state: State = getState()) { @@ -32,11 +28,11 @@ export class FiltersService { } } -export type CanvasFiltersService = FiltersService; - -export type CanvasFiltersServiceFactory = KibanaPluginServiceFactory< - CanvasFiltersService, - CanvasStartDeps ->; +let canvasFiltersService: FiltersService; -export const filtersServiceFactory: CanvasFiltersServiceFactory = () => new FiltersService(); +export const getCanvasFiltersService = () => { + if (!canvasFiltersService) { + canvasFiltersService = new FiltersService(); + } + return canvasFiltersService; +}; diff --git a/x-pack/plugins/canvas/public/services/kibana/notify.ts b/x-pack/plugins/canvas/public/services/canvas_notify_service.ts similarity index 71% rename from x-pack/plugins/canvas/public/services/kibana/notify.ts rename to x-pack/plugins/canvas/public/services/canvas_notify_service.ts index 8448a1d515fe4..1f00190f3fff9 100644 --- a/x-pack/plugins/canvas/public/services/kibana/notify.ts +++ b/x-pack/plugins/canvas/public/services/canvas_notify_service.ts @@ -6,17 +6,10 @@ */ import { get } from 'lodash'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; import { ToastInputFields } from '@kbn/core/public'; -import { formatMsg } from '../../lib/format_msg'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasNotifyService } from '../notify'; - -export type CanvasNotifyServiceFactory = KibanaPluginServiceFactory< - CanvasNotifyService, - CanvasStartDeps ->; +import { formatMsg } from '../lib/format_msg'; +import { coreServices } from './kibana_services'; const getToast = (err: Error | string, opts: ToastInputFields = {}) => { const errData = (get(err, 'response') || err) as Error | string; @@ -36,8 +29,15 @@ const getToast = (err: Error | string, opts: ToastInputFields = {}) => { }; }; -export const notifyServiceFactory: CanvasNotifyServiceFactory = ({ coreStart }) => { - const toasts = coreStart.notifications.toasts; +export interface CanvasNotifyService { + error: (err: string | Error, opts?: ToastInputFields) => void; + warning: (err: string | Error, opts?: ToastInputFields) => void; + info: (err: string | Error, opts?: ToastInputFields) => void; + success: (err: string | Error, opts?: ToastInputFields) => void; +} + +export const getCanvasNotifyService = (): CanvasNotifyService => { + const toasts = coreServices.notifications.toasts; return { /* diff --git a/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts b/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts new file mode 100644 index 0000000000000..2672f6ef4a06e --- /dev/null +++ b/x-pack/plugins/canvas/public/services/canvas_workpad_service.ts @@ -0,0 +1,200 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ResolvedSimpleSavedObject, SavedObject } from '@kbn/core/public'; +import { + API_ROUTE_SHAREABLE_ZIP, + API_ROUTE_TEMPLATES, + API_ROUTE_WORKPAD, + API_ROUTE_WORKPAD_ASSETS, + API_ROUTE_WORKPAD_STRUCTURES, + DEFAULT_WORKPAD_CSS, +} from '../../common/lib'; +import type { CanvasRenderedWorkpad } from '../../shareable_runtime/types'; +import { CanvasTemplate, CanvasWorkpad } from '../../types'; +import { coreServices } from './kibana_services'; + +export type FoundWorkpads = Array>; +export type FoundWorkpad = FoundWorkpads[number]; +export interface WorkpadFindResponse { + total: number; + workpads: FoundWorkpads; +} + +export interface TemplateFindResponse { + templates: CanvasTemplate[]; +} + +export interface ResolveWorkpadResponse { + workpad: CanvasWorkpad; + outcome: ResolvedSimpleSavedObject['outcome']; + aliasId?: ResolvedSimpleSavedObject['alias_target_id']; + aliasPurpose?: ResolvedSimpleSavedObject['alias_purpose']; +} + +/* + Remove any top level keys from the workpad which will be rejected by validation +*/ +const validKeys = [ + '@created', + '@timestamp', + 'assets', + 'colors', + 'css', + 'variables', + 'height', + 'id', + 'isWriteable', + 'name', + 'page', + 'pages', + 'width', +]; + +const sanitizeWorkpad = function (workpad: CanvasWorkpad) { + const workpadKeys = Object.keys(workpad); + + for (const key of workpadKeys) { + if (!validKeys.includes(key)) { + delete (workpad as { [key: string]: any })[key]; + } + } + + return workpad; +}; + +class CanvasWorkpadService { + private apiPath = `${API_ROUTE_WORKPAD}`; + + public async get(id: string): Promise { + const workpad = await coreServices.http.get(`${this.apiPath}/${id}`, { version: '1' }); + + return { css: DEFAULT_WORKPAD_CSS, variables: [], ...workpad }; + } + + public async export(id: string) { + const workpad = await coreServices.http.get>( + `${this.apiPath}/export/${id}`, + { version: '1' } + ); + const { attributes } = workpad; + + return { + ...workpad, + attributes: { + ...attributes, + css: attributes.css ?? DEFAULT_WORKPAD_CSS, + variables: attributes.variables ?? [], + }, + }; + } + + public async resolve(id: string): Promise { + const { workpad, ...resolveProps } = await coreServices.http.get( + `${this.apiPath}/resolve/${id}`, + { version: '1' } + ); + + return { + ...resolveProps, + workpad: { + // @ts-ignore: Shimming legacy workpads that might not have CSS + css: DEFAULT_WORKPAD_CSS, + // @ts-ignore: Shimming legacy workpads that might not have variables + variables: [], + ...workpad, + }, + }; + } + + public async create(workpad: CanvasWorkpad): Promise { + return coreServices.http.post(this.apiPath, { + body: JSON.stringify({ + ...sanitizeWorkpad({ ...workpad }), + assets: workpad.assets || {}, + variables: workpad.variables || [], + }), + version: '1', + }); + } + + public async import(workpad: CanvasWorkpad): Promise { + return coreServices.http.post(`${this.apiPath}/import`, { + body: JSON.stringify({ + ...sanitizeWorkpad({ ...workpad }), + assets: workpad.assets || {}, + variables: workpad.variables || [], + }), + version: '1', + }); + } + + public async createFromTemplate(templateId: string): Promise { + return coreServices.http.post(this.apiPath, { + body: JSON.stringify({ templateId }), + version: '1', + }); + } + + public async findTemplates(): Promise { + return coreServices.http.get(API_ROUTE_TEMPLATES, { version: '1' }); + } + + public async find(searchTerm: string): Promise { + // TODO: this shouldn't be necessary. Check for usage. + const validSearchTerm = typeof searchTerm === 'string' && searchTerm.length > 0; + + return coreServices.http.get(`${this.apiPath}/find`, { + query: { + perPage: 10000, + name: validSearchTerm ? searchTerm : '', + }, + version: '1', + }); + } + + public async remove(id: string) { + coreServices.http.delete(`${this.apiPath}/${id}`, { version: '1' }); + } + + public async update(id: string, workpad: CanvasWorkpad) { + coreServices.http.put(`${this.apiPath}/${id}`, { + body: JSON.stringify({ ...sanitizeWorkpad({ ...workpad }) }), + version: '1', + }); + } + + public async updateWorkpad(id: string, workpad: CanvasWorkpad) { + coreServices.http.put(`${API_ROUTE_WORKPAD_STRUCTURES}/${id}`, { + body: JSON.stringify({ ...sanitizeWorkpad({ ...workpad }) }), + version: '1', + }); + } + + public async updateAssets(id: string, assets: CanvasWorkpad['assets']) { + coreServices.http.put(`${API_ROUTE_WORKPAD_ASSETS}/${id}`, { + body: JSON.stringify(assets), + version: '1', + }); + } + + public async getRuntimeZip(workpad: CanvasRenderedWorkpad): Promise { + return coreServices.http.post(API_ROUTE_SHAREABLE_ZIP, { + body: JSON.stringify(workpad), + version: '1', + }); + } +} + +let canvasWorkpadService: CanvasWorkpadService; + +export const getCanvasWorkpadService: () => CanvasWorkpadService = () => { + if (!canvasWorkpadService) { + canvasWorkpadService = new CanvasWorkpadService(); + } + return canvasWorkpadService; +}; diff --git a/x-pack/plugins/canvas/public/services/custom_element.ts b/x-pack/plugins/canvas/public/services/custom_element.ts deleted file mode 100644 index 675a5a2f23c01..0000000000000 --- a/x-pack/plugins/canvas/public/services/custom_element.ts +++ /dev/null @@ -1,21 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CustomElement } from '../../types'; - -export interface CustomElementFindResponse { - total: number; - customElements: CustomElement[]; -} - -export interface CanvasCustomElementService { - create: (customElement: CustomElement) => Promise; - get: (customElementId: string) => Promise; - update: (id: string, element: Partial) => Promise; - remove: (id: string) => Promise; - find: (searchTerm: string) => Promise; -} diff --git a/x-pack/plugins/canvas/public/services/data_views.ts b/x-pack/plugins/canvas/public/services/data_views.ts deleted file mode 100644 index 86faa87bfaa59..0000000000000 --- a/x-pack/plugins/canvas/public/services/data_views.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DataView } from '@kbn/data-views-plugin/common'; - -export interface CanvasDataViewsService { - getFields: (index: string) => Promise; - getDataViews: () => Promise>>; - getDefaultDataView: () => Promise | undefined>; -} diff --git a/x-pack/plugins/canvas/public/services/embeddables.ts b/x-pack/plugins/canvas/public/services/embeddables.ts deleted file mode 100644 index b8f3d7d14b5e5..0000000000000 --- a/x-pack/plugins/canvas/public/services/embeddables.ts +++ /dev/null @@ -1,22 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EmbeddableFactory, - type EmbeddableStateTransfer, - ReactEmbeddableSavedObject, -} from '@kbn/embeddable-plugin/public'; -import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common'; - -export interface CanvasEmbeddablesService { - reactEmbeddableRegistryHasKey: (key: string) => boolean; - getReactEmbeddableSavedObjects: < - TSavedObjectAttributes extends FinderAttributes - >() => IterableIterator<[string, ReactEmbeddableSavedObject]>; - getEmbeddableFactories: () => IterableIterator; - getStateTransfer: () => EmbeddableStateTransfer; -} diff --git a/x-pack/plugins/canvas/public/services/expressions.ts b/x-pack/plugins/canvas/public/services/expressions.ts deleted file mode 100644 index 456a1314bdfff..0000000000000 --- a/x-pack/plugins/canvas/public/services/expressions.ts +++ /dev/null @@ -1,8 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type { CanvasExpressionsService } from './kibana/expressions'; diff --git a/x-pack/plugins/canvas/public/services/filters.ts b/x-pack/plugins/canvas/public/services/filters.ts deleted file mode 100644 index 1ced3d15f6e10..0000000000000 --- a/x-pack/plugins/canvas/public/services/filters.ts +++ /dev/null @@ -1,8 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type { CanvasFiltersService } from './kibana/filters'; diff --git a/x-pack/plugins/canvas/public/services/index.ts b/x-pack/plugins/canvas/public/services/index.ts index dd035fcd3b1ad..92b5f0ef3936a 100644 --- a/x-pack/plugins/canvas/public/services/index.ts +++ b/x-pack/plugins/canvas/public/services/index.ts @@ -6,55 +6,11 @@ */ export * from './legacy'; +import { useMemo } from 'react'; -import { PluginServices } from '@kbn/presentation-util-plugin/public'; +import { getCanvasNotifyService } from './canvas_notify_service'; -import { CanvasCustomElementService } from './custom_element'; -import { CanvasDataViewsService } from './data_views'; -import { CanvasEmbeddablesService } from './embeddables'; -import { CanvasExpressionsService } from './expressions'; -import { CanvasFiltersService } from './filters'; -import { CanvasLabsService } from './labs'; -import { CanvasNavLinkService } from './nav_link'; -import { CanvasNotifyService } from './notify'; -import { CanvasPlatformService } from './platform'; -import { CanvasReportingService } from './reporting'; -import { CanvasVisualizationsService } from './visualizations'; -import { CanvasWorkpadService } from './workpad'; -import { CanvasUiActionsService } from './ui_actions'; - -export interface CanvasPluginServices { - customElement: CanvasCustomElementService; - dataViews: CanvasDataViewsService; - embeddables: CanvasEmbeddablesService; - expressions: CanvasExpressionsService; - filters: CanvasFiltersService; - labs: CanvasLabsService; - navLink: CanvasNavLinkService; - notify: CanvasNotifyService; - platform: CanvasPlatformService; - reporting: CanvasReportingService; - visualizations: CanvasVisualizationsService; - workpad: CanvasWorkpadService; - uiActions: CanvasUiActionsService; -} - -export const pluginServices = new PluginServices(); - -export const useCustomElementService = () => - (() => pluginServices.getHooks().customElement.useService())(); -export const useDataViewsService = () => (() => pluginServices.getHooks().dataViews.useService())(); -export const useEmbeddablesService = () => - (() => pluginServices.getHooks().embeddables.useService())(); -export const useExpressionsService = () => - (() => pluginServices.getHooks().expressions.useService())(); -export const useFiltersService = () => (() => pluginServices.getHooks().filters.useService())(); -export const useLabsService = () => (() => pluginServices.getHooks().labs.useService())(); -export const useNavLinkService = () => (() => pluginServices.getHooks().navLink.useService())(); -export const useNotifyService = () => (() => pluginServices.getHooks().notify.useService())(); -export const usePlatformService = () => (() => pluginServices.getHooks().platform.useService())(); -export const useReportingService = () => (() => pluginServices.getHooks().reporting.useService())(); -export const useVisualizationsService = () => - (() => pluginServices.getHooks().visualizations.useService())(); -export const useWorkpadService = () => (() => pluginServices.getHooks().workpad.useService())(); -export const useUiActionsService = () => (() => pluginServices.getHooks().uiActions.useService())(); +export const useNotifyService = () => { + const canvasNotifyService = useMemo(() => getCanvasNotifyService(), []); + return canvasNotifyService; +}; diff --git a/x-pack/plugins/canvas/public/services/kibana/custom_element.ts b/x-pack/plugins/canvas/public/services/kibana/custom_element.ts deleted file mode 100644 index a548ccdc23b2f..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/custom_element.ts +++ /dev/null @@ -1,44 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { API_ROUTE_CUSTOM_ELEMENT } from '../../../common/lib/constants'; -import { CustomElement } from '../../../types'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasCustomElementService } from '../custom_element'; - -export type CanvasCustomElementServiceFactory = KibanaPluginServiceFactory< - CanvasCustomElementService, - CanvasStartDeps ->; - -export const customElementServiceFactory: CanvasCustomElementServiceFactory = ({ coreStart }) => { - const { http } = coreStart; - const apiPath = `${API_ROUTE_CUSTOM_ELEMENT}`; - - return { - create: (customElement) => - http.post(apiPath, { body: JSON.stringify(customElement), version: '1' }), - get: (customElementId) => - http - .get<{ data: CustomElement }>(`${apiPath}/${customElementId}`, { version: '1' }) - .then(({ data: element }) => element), - update: (id, element) => - http.put(`${apiPath}/${id}`, { body: JSON.stringify(element), version: '1' }), - remove: (id) => http.delete(`${apiPath}/${id}`, { version: '1' }), - find: async (name) => { - return http.get(`${apiPath}/find`, { - query: { - name, - perPage: 10000, - }, - version: '1', - }); - }, - }; -}; diff --git a/x-pack/plugins/canvas/public/services/kibana/data_views.ts b/x-pack/plugins/canvas/public/services/kibana/data_views.ts deleted file mode 100644 index 27ec0bb1c5fc6..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/data_views.ts +++ /dev/null @@ -1,50 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DataView } from '@kbn/data-views-plugin/public'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { ErrorStrings } from '../../../i18n'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasDataViewsService } from '../data_views'; -import { CanvasNotifyService } from '../notify'; - -const { esService: strings } = ErrorStrings; - -export type DataViewsServiceFactory = KibanaPluginServiceFactory< - CanvasDataViewsService, - CanvasStartDeps, - { - notify: CanvasNotifyService; - } ->; - -export const dataViewsServiceFactory: DataViewsServiceFactory = ({ startPlugins }, { notify }) => ({ - getDataViews: async () => { - try { - const dataViews = await startPlugins.dataViews.getIdsWithTitle(); - return dataViews.map(({ id, name, title }) => ({ id, name, title } as DataView)); - } catch (e) { - notify.error(e, { title: strings.getIndicesFetchErrorMessage() }); - } - - return []; - }, - getFields: async (dataViewTitle: string) => { - const dataView = await startPlugins.dataViews.create({ title: dataViewTitle }); - - return dataView.fields - .filter((field) => !field.name.startsWith('_')) - .map((field) => field.name); - }, - getDefaultDataView: async () => { - const dataView = await startPlugins.dataViews.getDefaultDataView(); - - return dataView - ? { id: dataView.id, name: dataView.name, title: dataView.getIndexPattern() } - : undefined; - }, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts b/x-pack/plugins/canvas/public/services/kibana/embeddables.ts deleted file mode 100644 index 20f6f3feec8a4..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/embeddables.ts +++ /dev/null @@ -1,22 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasEmbeddablesService } from '../embeddables'; - -export type EmbeddablesServiceFactory = KibanaPluginServiceFactory< - CanvasEmbeddablesService, - CanvasStartDeps ->; - -export const embeddablesServiceFactory: EmbeddablesServiceFactory = ({ startPlugins }) => ({ - reactEmbeddableRegistryHasKey: startPlugins.embeddable.reactEmbeddableRegistryHasKey, - getReactEmbeddableSavedObjects: startPlugins.embeddable.getReactEmbeddableSavedObjects, - getEmbeddableFactories: startPlugins.embeddable.getEmbeddableFactories, - getStateTransfer: startPlugins.embeddable.getStateTransfer, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/index.ts b/x-pack/plugins/canvas/public/services/kibana/index.ts deleted file mode 100644 index cab569133f70f..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/index.ts +++ /dev/null @@ -1,66 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - PluginServiceProviders, - PluginServiceProvider, - PluginServiceRegistry, - KibanaPluginServiceParams, -} from '@kbn/presentation-util-plugin/public'; - -import { CanvasPluginServices } from '..'; -import { CanvasStartDeps } from '../../plugin'; -import { customElementServiceFactory } from './custom_element'; -import { dataViewsServiceFactory } from './data_views'; -import { embeddablesServiceFactory } from './embeddables'; -import { expressionsServiceFactory } from './expressions'; -import { labsServiceFactory } from './labs'; -import { navLinkServiceFactory } from './nav_link'; -import { notifyServiceFactory } from './notify'; -import { platformServiceFactory } from './platform'; -import { reportingServiceFactory } from './reporting'; -import { visualizationsServiceFactory } from './visualizations'; -import { workpadServiceFactory } from './workpad'; -import { filtersServiceFactory } from './filters'; -import { uiActionsServiceFactory } from './ui_actions'; - -export { customElementServiceFactory } from './custom_element'; -export { dataViewsServiceFactory } from './data_views'; -export { embeddablesServiceFactory } from './embeddables'; -export { expressionsServiceFactory } from './expressions'; -export { filtersServiceFactory } from './filters'; -export { labsServiceFactory } from './labs'; -export { notifyServiceFactory } from './notify'; -export { platformServiceFactory } from './platform'; -export { reportingServiceFactory } from './reporting'; -export { visualizationsServiceFactory } from './visualizations'; -export { workpadServiceFactory } from './workpad'; -export { uiActionsServiceFactory } from './ui_actions'; - -export const pluginServiceProviders: PluginServiceProviders< - CanvasPluginServices, - KibanaPluginServiceParams -> = { - customElement: new PluginServiceProvider(customElementServiceFactory), - dataViews: new PluginServiceProvider(dataViewsServiceFactory, ['notify']), - embeddables: new PluginServiceProvider(embeddablesServiceFactory), - expressions: new PluginServiceProvider(expressionsServiceFactory, ['filters', 'notify']), - filters: new PluginServiceProvider(filtersServiceFactory), - labs: new PluginServiceProvider(labsServiceFactory), - navLink: new PluginServiceProvider(navLinkServiceFactory), - notify: new PluginServiceProvider(notifyServiceFactory), - platform: new PluginServiceProvider(platformServiceFactory), - reporting: new PluginServiceProvider(reportingServiceFactory), - visualizations: new PluginServiceProvider(visualizationsServiceFactory), - workpad: new PluginServiceProvider(workpadServiceFactory), - uiActions: new PluginServiceProvider(uiActionsServiceFactory), -}; - -export const pluginServiceRegistry = new PluginServiceRegistry< - CanvasPluginServices, - KibanaPluginServiceParams ->(pluginServiceProviders); diff --git a/x-pack/plugins/canvas/public/services/kibana/labs.ts b/x-pack/plugins/canvas/public/services/kibana/labs.ts deleted file mode 100644 index 69613ae67fd85..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/labs.ts +++ /dev/null @@ -1,23 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { projectIDs } from '@kbn/presentation-util-plugin/common'; -import { UI_SETTINGS } from '../../../common'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasLabsService } from '../labs'; - -export type CanvasLabsServiceFactory = KibanaPluginServiceFactory< - CanvasLabsService, - CanvasStartDeps ->; - -export const labsServiceFactory: CanvasLabsServiceFactory = ({ startPlugins, coreStart }) => ({ - projectIDs, - isLabsEnabled: () => coreStart.uiSettings.get(UI_SETTINGS.ENABLE_LABS_UI), - ...startPlugins.presentationUtil.labsService, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/nav_link.ts b/x-pack/plugins/canvas/public/services/kibana/nav_link.ts deleted file mode 100644 index 8470c688f5b2b..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/nav_link.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { SESSIONSTORAGE_LASTPATH } from '../../../common/lib/constants'; -import { getSessionStorage } from '../../lib/storage'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasNavLinkService } from '../nav_link'; - -export type CanvasNavLinkServiceFactory = KibanaPluginServiceFactory< - CanvasNavLinkService, - CanvasStartDeps ->; - -export const navLinkServiceFactory: CanvasNavLinkServiceFactory = ({ coreStart, appUpdater }) => ({ - updatePath: (path: string) => { - appUpdater?.next(() => ({ - defaultPath: `${path}`, - })); - - getSessionStorage().set(`${SESSIONSTORAGE_LASTPATH}:${coreStart.http.basePath.get()}`, path); - }, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/platform.ts b/x-pack/plugins/canvas/public/services/kibana/platform.ts deleted file mode 100644 index 1518280ab0688..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/platform.ts +++ /dev/null @@ -1,46 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasStartDeps } from '../../plugin'; -import { CanvasPlatformService } from '../platform'; - -export type CanvaPlatformServiceFactory = KibanaPluginServiceFactory< - CanvasPlatformService, - CanvasStartDeps ->; - -export const platformServiceFactory: CanvaPlatformServiceFactory = ({ - coreStart, - initContext, - startPlugins, -}) => { - if (!initContext) { - throw new Error('Canvas platform service requires init context'); - } - - return { - getBasePath: coreStart.http.basePath.get, - getBasePathInterface: () => coreStart.http.basePath, - getElasticWebsiteUrl: () => coreStart.docLinks.ELASTIC_WEBSITE_URL, - getDocLinkVersion: () => coreStart.docLinks.DOC_LINK_VERSION, - getKibanaVersion: () => initContext.env.packageInfo.version, - // TODO: is there a better type for this? The capabilities type allows for a Record, - // though we don't do this. So this cast may be the best option. - getHasWriteAccess: () => coreStart.application.capabilities.canvas.save as boolean, - getUISetting: coreStart.uiSettings.get.bind(coreStart.uiSettings), - hasHeaderBanner$: coreStart.chrome.hasHeaderBanner$, - setBreadcrumbs: coreStart.chrome.setBreadcrumbs, - setRecentlyAccessed: coreStart.chrome.recentlyAccessed.add, - setFullscreen: coreStart.chrome.setIsVisible, - redirectLegacyUrl: startPlugins.spaces?.ui.redirectLegacyUrl, - getLegacyUrlConflict: startPlugins.spaces?.ui.components.getLegacyUrlConflict, - getUISettings: () => coreStart.uiSettings, - getHttp: () => coreStart.http, - getContentManagement: () => startPlugins.contentManagement, - }; -}; diff --git a/x-pack/plugins/canvas/public/services/kibana/reporting.ts b/x-pack/plugins/canvas/public/services/kibana/reporting.ts deleted file mode 100644 index 56b9b91e45fc6..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/reporting.ts +++ /dev/null @@ -1,45 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasStartDeps } from '../../plugin'; -import { CanvasReportingService } from '../reporting'; - -export type CanvasReportingServiceFactory = KibanaPluginServiceFactory< - CanvasReportingService, - CanvasStartDeps ->; - -export const reportingServiceFactory: CanvasReportingServiceFactory = ({ - startPlugins, - coreStart, -}) => { - const { reporting } = startPlugins; - - const reportingEnabled = () => ({ - getReportingPanelPDFComponent: () => reporting?.components.ReportingPanelPDFV2 || null, - }); - const reportingDisabled = () => ({ getReportingPanelPDFComponent: () => null }); - - if (!reporting) { - // Reporting is not enabled - return reportingDisabled(); - } - - if (reporting.usesUiCapabilities()) { - if (coreStart.application.capabilities.canvas?.generatePdf === true) { - // Canvas has declared Reporting as a subfeature with the `generatePdf` UI Capability - return reportingEnabled(); - } else { - return reportingDisabled(); - } - } - - // Legacy/Deprecated: Reporting is enabled as an Elasticsearch feature - return reportingEnabled(); -}; diff --git a/x-pack/plugins/canvas/public/services/kibana/ui_actions.ts b/x-pack/plugins/canvas/public/services/kibana/ui_actions.ts deleted file mode 100644 index bb621206082d1..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/ui_actions.ts +++ /dev/null @@ -1,19 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasUiActionsService } from '../ui_actions'; - -export type UiActionsServiceFactory = KibanaPluginServiceFactory< - CanvasUiActionsService, - CanvasStartDeps ->; - -export const uiActionsServiceFactory: UiActionsServiceFactory = ({ startPlugins }) => ({ - getTriggerCompatibleActions: startPlugins.uiActions.getTriggerCompatibleActions, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/visualizations.ts b/x-pack/plugins/canvas/public/services/kibana/visualizations.ts deleted file mode 100644 index 6f1728953ee8e..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/visualizations.ts +++ /dev/null @@ -1,21 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasStartDeps } from '../../plugin'; -import { CanvasVisualizationsService } from '../visualizations'; - -export type VisualizationsServiceFactory = KibanaPluginServiceFactory< - CanvasVisualizationsService, - CanvasStartDeps ->; - -export const visualizationsServiceFactory: VisualizationsServiceFactory = ({ startPlugins }) => ({ - showNewVisModal: startPlugins.visualizations.showNewVisModal, - getByGroup: startPlugins.visualizations.getByGroup, - getAliases: startPlugins.visualizations.getAliases, -}); diff --git a/x-pack/plugins/canvas/public/services/kibana/workpad.ts b/x-pack/plugins/canvas/public/services/kibana/workpad.ts deleted file mode 100644 index 3b70244440cc8..0000000000000 --- a/x-pack/plugins/canvas/public/services/kibana/workpad.ts +++ /dev/null @@ -1,170 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SavedObject } from '@kbn/core/public'; -import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasStartDeps } from '../../plugin'; -import { CanvasWorkpadService, ResolveWorkpadResponse } from '../workpad'; - -import { - API_ROUTE_WORKPAD, - DEFAULT_WORKPAD_CSS, - API_ROUTE_TEMPLATES, - API_ROUTE_WORKPAD_ASSETS, - API_ROUTE_WORKPAD_STRUCTURES, - API_ROUTE_SHAREABLE_ZIP, -} from '../../../common/lib/constants'; -import { CanvasWorkpad } from '../../../types'; - -export type CanvasWorkpadServiceFactory = KibanaPluginServiceFactory< - CanvasWorkpadService, - CanvasStartDeps ->; - -/* - Remove any top level keys from the workpad which will be rejected by validation -*/ -const validKeys = [ - '@created', - '@timestamp', - 'assets', - 'colors', - 'css', - 'variables', - 'height', - 'id', - 'isWriteable', - 'name', - 'page', - 'pages', - 'width', -]; - -const sanitizeWorkpad = function (workpad: CanvasWorkpad) { - const workpadKeys = Object.keys(workpad); - - for (const key of workpadKeys) { - if (!validKeys.includes(key)) { - delete (workpad as { [key: string]: any })[key]; - } - } - - return workpad; -}; - -export const workpadServiceFactory: CanvasWorkpadServiceFactory = ({ coreStart, startPlugins }) => { - const getApiPath = function () { - return `${API_ROUTE_WORKPAD}`; - }; - - return { - get: async (id: string) => { - const workpad = await coreStart.http.get(`${getApiPath()}/${id}`, { version: '1' }); - - return { css: DEFAULT_WORKPAD_CSS, variables: [], ...workpad }; - }, - export: async (id: string) => { - const workpad = await coreStart.http.get>( - `${getApiPath()}/export/${id}`, - { version: '1' } - ); - const { attributes } = workpad; - - return { - ...workpad, - attributes: { - ...attributes, - css: attributes.css ?? DEFAULT_WORKPAD_CSS, - variables: attributes.variables ?? [], - }, - }; - }, - resolve: async (id: string) => { - const { workpad, ...resolveProps } = await coreStart.http.get( - `${getApiPath()}/resolve/${id}`, - { version: '1' } - ); - - return { - ...resolveProps, - workpad: { - // @ts-ignore: Shimming legacy workpads that might not have CSS - css: DEFAULT_WORKPAD_CSS, - // @ts-ignore: Shimming legacy workpads that might not have variables - variables: [], - ...workpad, - }, - }; - }, - create: (workpad: CanvasWorkpad) => { - return coreStart.http.post(getApiPath(), { - body: JSON.stringify({ - ...sanitizeWorkpad({ ...workpad }), - assets: workpad.assets || {}, - variables: workpad.variables || [], - }), - version: '1', - }); - }, - import: (workpad: CanvasWorkpad) => - coreStart.http.post(`${getApiPath()}/import`, { - body: JSON.stringify({ - ...sanitizeWorkpad({ ...workpad }), - assets: workpad.assets || {}, - variables: workpad.variables || [], - }), - version: '1', - }), - createFromTemplate: (templateId: string) => { - return coreStart.http.post(getApiPath(), { - body: JSON.stringify({ templateId }), - version: '1', - }); - }, - findTemplates: async () => coreStart.http.get(API_ROUTE_TEMPLATES, { version: '1' }), - find: (searchTerm: string) => { - // TODO: this shouldn't be necessary. Check for usage. - const validSearchTerm = typeof searchTerm === 'string' && searchTerm.length > 0; - - return coreStart.http.get(`${getApiPath()}/find`, { - query: { - perPage: 10000, - name: validSearchTerm ? searchTerm : '', - }, - version: '1', - }); - }, - remove: (id: string) => { - return coreStart.http.delete(`${getApiPath()}/${id}`, { version: '1' }); - }, - update: (id, workpad) => { - return coreStart.http.put(`${getApiPath()}/${id}`, { - body: JSON.stringify({ ...sanitizeWorkpad({ ...workpad }) }), - version: '1', - }); - }, - updateWorkpad: (id, workpad) => { - return coreStart.http.put(`${API_ROUTE_WORKPAD_STRUCTURES}/${id}`, { - body: JSON.stringify({ ...sanitizeWorkpad({ ...workpad }) }), - version: '1', - }); - }, - updateAssets: (id, assets) => { - return coreStart.http.put(`${API_ROUTE_WORKPAD_ASSETS}/${id}`, { - body: JSON.stringify(assets), - version: '1', - }); - }, - getRuntimeZip: (workpad) => { - return coreStart.http.post(API_ROUTE_SHAREABLE_ZIP, { - body: JSON.stringify(workpad), - version: '1', - }); - }, - }; -}; diff --git a/x-pack/plugins/canvas/public/services/kibana_services.ts b/x-pack/plugins/canvas/public/services/kibana_services.ts new file mode 100644 index 0000000000000..2b966e698a874 --- /dev/null +++ b/x-pack/plugins/canvas/public/services/kibana_services.ts @@ -0,0 +1,76 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BehaviorSubject } from 'rxjs'; + +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import type { CoreStart, PluginInitializerContext } from '@kbn/core/public'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { EmbeddableStart } from '@kbn/embeddable-plugin/public/plugin'; +import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; +import type { ReportingStart } from '@kbn/reporting-plugin/public'; +import type { SpacesApi } from '@kbn/spaces-plugin/public'; +import type { UiActionsPublicStart } from '@kbn/ui-actions-plugin/public/plugin'; +import type { VisualizationsStart } from '@kbn/visualizations-plugin/public'; + +import type { CanvasStartDeps } from '../plugin'; + +export let kibanaVersion: string; + +export let coreServices: CoreStart; +export let contentManagementService: ContentManagementPublicStart; +export let dataService: DataPublicPluginStart; +export let dataViewsService: DataViewsPublicPluginStart; +export let embeddableService: EmbeddableStart; +export let expressionsService: ExpressionsStart; +export let presentationUtilService: PresentationUtilPluginStart; +export let reportingService: ReportingStart | undefined; +export let spacesService: SpacesApi | undefined; +export let uiActionsService: UiActionsPublicStart; +export let visualizationsService: VisualizationsStart; + +const servicesReady$ = new BehaviorSubject(false); + +export const setKibanaServices = ( + kibanaCore: CoreStart, + deps: CanvasStartDeps, + initContext: PluginInitializerContext +) => { + kibanaVersion = initContext.env.packageInfo.version; + + coreServices = kibanaCore; + contentManagementService = deps.contentManagement; + dataService = deps.data; + dataViewsService = deps.dataViews; + embeddableService = deps.embeddable; + expressionsService = deps.expressions; + presentationUtilService = deps.presentationUtil; + reportingService = Boolean( + deps.reporting?.usesUiCapabilities() && !kibanaCore.application.capabilities.canvas?.generatePdf + ) + ? undefined + : deps.reporting; + spacesService = deps.spaces; + uiActionsService = deps.uiActions; + visualizationsService = deps.visualizations; + + servicesReady$.next(true); +}; + +export const untilPluginStartServicesReady = () => { + if (servicesReady$.value) return Promise.resolve(); + return new Promise((resolve) => { + const subscription = servicesReady$.subscribe((isInitialized) => { + if (isInitialized) { + subscription.unsubscribe(); + resolve(); + } + }); + }); +}; diff --git a/x-pack/plugins/canvas/public/services/labs.ts b/x-pack/plugins/canvas/public/services/labs.ts deleted file mode 100644 index 0f20e25f31d60..0000000000000 --- a/x-pack/plugins/canvas/public/services/labs.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PresentationLabsService } from '@kbn/presentation-util-plugin/public'; -import { projectIDs } from '@kbn/presentation-util-plugin/common'; - -export interface CanvasLabsService extends PresentationLabsService { - projectIDs: typeof projectIDs; - isLabsEnabled: () => boolean; -} diff --git a/x-pack/plugins/canvas/public/services/legacy/reporting.ts b/x-pack/plugins/canvas/public/services/legacy/reporting.ts deleted file mode 100644 index 411a892baed29..0000000000000 --- a/x-pack/plugins/canvas/public/services/legacy/reporting.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReportingStart } from '@kbn/reporting-plugin/public'; -import { CanvasServiceFactory } from '.'; - -export interface ReportingService { - start?: ReportingStart; -} - -export const reportingServiceFactory: CanvasServiceFactory = ( - _coreSetup, - coreStart, - _setupPlugins, - startPlugins -): ReportingService => { - const { reporting } = startPlugins; - - const reportingEnabled = () => ({ start: reporting }); - const reportingDisabled = () => ({ start: undefined }); - - if (!reporting) { - // Reporting is not enabled - return reportingDisabled(); - } - - if (reporting.usesUiCapabilities()) { - if (coreStart.application.capabilities.canvas?.generatePdf === true) { - // Canvas has declared Reporting as a subfeature with the `generatePdf` UI Capability - return reportingEnabled(); - } else { - return reportingDisabled(); - } - } - - // Legacy/Deprecated: Reporting is enabled as an Elasticsearch feature - return reportingEnabled(); -}; diff --git a/x-pack/plugins/canvas/public/services/mocks.ts b/x-pack/plugins/canvas/public/services/mocks.ts new file mode 100644 index 0000000000000..c35d8834253be --- /dev/null +++ b/x-pack/plugins/canvas/public/services/mocks.ts @@ -0,0 +1,125 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment from 'moment'; + +import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; +import { CoreStart } from '@kbn/core/public'; +import { coreMock } from '@kbn/core/public/mocks'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { expressionsPluginMock } from '@kbn/expressions-plugin/public/mocks'; +import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; +import { presentationUtilPluginMock } from '@kbn/presentation-util-plugin/public/mocks'; +import { reportingPluginMock } from '@kbn/reporting-plugin/public/mocks'; +import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; +import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; +import { visualizationsPluginMock } from '@kbn/visualizations-plugin/public/mocks'; + +import { setKibanaServices } from './kibana_services'; +import { getId } from '../lib/get_id'; +// @ts-expect-error +import { getDefaultWorkpad } from '../state/defaults'; + +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: CoreStart = coreMock.createStart(); + + setDefaultPresentationUtilCapabilities(core); + setKibanaServices( + core, + { + charts: chartPluginMock.createStartContract(), + contentManagement: contentManagementMock.createStartContract(), + data: dataPluginMock.createStartContract(), + dataViews: dataViewPluginMocks.createStartContract(), + embeddable: embeddablePluginMock.createStartContract(), + expressions: expressionsPluginMock.createStartContract(), + inspector: inspectorPluginMock.createStartContract(), + presentationUtil: presentationUtilPluginMock.createStartContract(), + reporting: reportingPluginMock.createStartContract(), + spaces: spacesPluginMock.createStartContract(), + uiActions: uiActionsPluginMock.createStartContract(), + visualizations: visualizationsPluginMock.createStartContract(), + }, + coreMock.createPluginInitializerContext() + ); +}; + +const TIMEOUT = 500; + +export const getSomeWorkpads = (count = 3, useStaticData = false) => { + if (useStaticData) { + const DAY = 86400000; + const JAN_1_2000 = 946684800000; + + const workpads = []; + for (let i = 0; i < count; i++) { + workpads[i] = { + ...getDefaultWorkpad(), + name: `Workpad ${i}`, + id: `workpad-${i}`, + '@created': moment(JAN_1_2000 + DAY * i).toDate(), + '@timestamp': moment(JAN_1_2000 + DAY * (i + 1)).toDate(), + }; + } + return workpads; + } else { + return Array.from({ length: count }, () => ({ + '@created': getRandomDate( + moment().subtract(3, 'days').toDate(), + moment().subtract(10, 'days').toDate() + ), + '@timestamp': getRandomDate(), + id: getId('workpad'), + name: getRandomName(), + })); + } +}; + +export const findSomeWorkpads = + (count = 3, useStaticData = false, timeout = TIMEOUT) => + (_term: string) => { + return Promise.resolve() + .then(promiseTimeout(timeout)) + .then(() => ({ + total: count, + workpads: getSomeWorkpads(count, useStaticData), + })); + }; + +const promiseTimeout = (time: number) => () => new Promise((resolve) => setTimeout(resolve, time)); + +const getRandomName = () => { + const lorem = + 'Lorem ipsum dolor sit amet consectetur adipiscing elit Fusce lobortis aliquet arcu ut turpis duis'.split( + ' ' + ); + return [1, 2, 3].map(() => lorem[Math.floor(Math.random() * lorem.length)]).join(' '); +}; + +const getRandomDate = ( + start: Date = moment().toDate(), + end: Date = moment().subtract(7, 'days').toDate() +) => new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toISOString(); diff --git a/x-pack/plugins/canvas/public/services/notify.ts b/x-pack/plugins/canvas/public/services/notify.ts deleted file mode 100644 index 83e7b4e71ee72..0000000000000 --- a/x-pack/plugins/canvas/public/services/notify.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ToastInputFields } from '@kbn/core/public'; - -export interface CanvasNotifyService { - error: (err: string | Error, opts?: ToastInputFields) => void; - warning: (err: string | Error, opts?: ToastInputFields) => void; - info: (err: string | Error, opts?: ToastInputFields) => void; - success: (err: string | Error, opts?: ToastInputFields) => void; -} diff --git a/x-pack/plugins/canvas/public/services/platform.ts b/x-pack/plugins/canvas/public/services/platform.ts deleted file mode 100644 index 555f8643fff9b..0000000000000 --- a/x-pack/plugins/canvas/public/services/platform.ts +++ /dev/null @@ -1,37 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Observable } from 'rxjs'; -import { - IUiSettingsClient, - ChromeBreadcrumb, - IBasePath, - ChromeStart, - HttpStart, -} from '@kbn/core/public'; - -import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; - -export interface CanvasPlatformService { - getBasePath: () => string; - getBasePathInterface: () => IBasePath; - getDocLinkVersion: () => string; - getElasticWebsiteUrl: () => string; - getKibanaVersion: () => string; - getHasWriteAccess: () => boolean; - getUISetting: (key: string, defaultValue?: any) => any; - hasHeaderBanner$: () => Observable; - setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; - setRecentlyAccessed: (link: string, label: string, id: string) => void; - setFullscreen: ChromeStart['setIsVisible']; - redirectLegacyUrl?: SpacesPluginStart['ui']['redirectLegacyUrl']; - getLegacyUrlConflict?: SpacesPluginStart['ui']['components']['getLegacyUrlConflict']; - getUISettings: () => IUiSettingsClient; - getHttp: () => HttpStart; - getContentManagement: () => ContentManagementPublicStart; -} diff --git a/x-pack/plugins/canvas/public/services/reporting.ts b/x-pack/plugins/canvas/public/services/reporting.ts deleted file mode 100644 index 71d90421eafa8..0000000000000 --- a/x-pack/plugins/canvas/public/services/reporting.ts +++ /dev/null @@ -1,13 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReportingStart } from '@kbn/reporting-plugin/public'; - -type ReportingPanelPDFComponent = ReportingStart['components']['ReportingPanelPDFV2']; -export interface CanvasReportingService { - getReportingPanelPDFComponent: () => ReportingPanelPDFComponent | null; -} diff --git a/x-pack/plugins/canvas/public/services/storybook/index.ts b/x-pack/plugins/canvas/public/services/storybook/index.ts deleted file mode 100644 index 52cad460662b2..0000000000000 --- a/x-pack/plugins/canvas/public/services/storybook/index.ts +++ /dev/null @@ -1,60 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - PluginServiceProviders, - PluginServiceProvider, -} from '@kbn/presentation-util-plugin/public'; - -import { CanvasPluginServices } from '..'; -import { pluginServiceProviders as stubProviders } from '../stubs'; -import { workpadServiceFactory } from './workpad'; -import { notifyServiceFactory } from './notify'; - -export interface StorybookParams { - hasTemplates?: boolean; - useStaticData?: boolean; - workpadCount?: number; -} - -export const pluginServiceProviders: PluginServiceProviders = - { - ...stubProviders, - workpad: new PluginServiceProvider(workpadServiceFactory), - notify: new PluginServiceProvider(notifyServiceFactory), - }; - -export const argTypes = { - hasTemplates: { - name: 'Has templates?', - type: { - name: 'boolean', - }, - defaultValue: true, - control: { - type: 'boolean', - }, - }, - useStaticData: { - name: 'Use static data?', - type: { - name: 'boolean', - }, - defaultValue: false, - control: { - type: 'boolean', - }, - }, - workpadCount: { - name: 'Number of workpads', - type: { name: 'number' }, - defaultValue: 5, - control: { - type: 'range', - }, - }, -}; diff --git a/x-pack/plugins/canvas/public/services/storybook/notify.ts b/x-pack/plugins/canvas/public/services/storybook/notify.ts deleted file mode 100644 index f6f97c42a1741..0000000000000 --- a/x-pack/plugins/canvas/public/services/storybook/notify.ts +++ /dev/null @@ -1,22 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { action } from '@storybook/addon-actions'; - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { StorybookParams } from '.'; -import { CanvasNotifyService } from '../notify'; - -type CanvasNotifyServiceFactory = PluginServiceFactory; - -export const notifyServiceFactory: CanvasNotifyServiceFactory = () => ({ - success: (message) => action(`success: ${message}`)(), - error: (message) => action(`error: ${message}`)(), - info: (message) => action(`info: ${message}`)(), - warning: (message) => action(`warning: ${message}`)(), -}); diff --git a/x-pack/plugins/canvas/public/services/storybook/workpad.ts b/x-pack/plugins/canvas/public/services/storybook/workpad.ts deleted file mode 100644 index 9f40ccccafb3d..0000000000000 --- a/x-pack/plugins/canvas/public/services/storybook/workpad.ts +++ /dev/null @@ -1,122 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; - -import { action } from '@storybook/addon-actions'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { getId } from '../../lib/get_id'; -// @ts-expect-error -import { getDefaultWorkpad } from '../../state/defaults'; - -import { StorybookParams } from '.'; -import { CanvasWorkpadService } from '../workpad'; - -import * as stubs from '../stubs/workpad'; - -export { - findNoTemplates, - findNoWorkpads, - findSomeTemplates, - getNoTemplates, - getSomeTemplates, -} from '../stubs/workpad'; - -type CanvasWorkpadServiceFactory = PluginServiceFactory; - -const TIMEOUT = 500; -const promiseTimeout = (time: number) => () => new Promise((resolve) => setTimeout(resolve, time)); - -const { findNoTemplates, findNoWorkpads, findSomeTemplates, importWorkpad } = stubs; - -const getRandomName = () => { - const lorem = - 'Lorem ipsum dolor sit amet consectetur adipiscing elit Fusce lobortis aliquet arcu ut turpis duis'.split( - ' ' - ); - return [1, 2, 3].map(() => lorem[Math.floor(Math.random() * lorem.length)]).join(' '); -}; - -const getRandomDate = ( - start: Date = moment().toDate(), - end: Date = moment().subtract(7, 'days').toDate() -) => new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toISOString(); - -export const getSomeWorkpads = (count = 3) => - Array.from({ length: count }, () => ({ - '@created': getRandomDate( - moment().subtract(3, 'days').toDate(), - moment().subtract(10, 'days').toDate() - ), - '@timestamp': getRandomDate(), - id: getId('workpad'), - name: getRandomName(), - })); - -export const findSomeWorkpads = - (count = 3, useStaticData = false, timeout = TIMEOUT) => - (_term: string) => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => ({ - total: count, - workpads: useStaticData ? stubs.getSomeWorkpads(count) : getSomeWorkpads(count), - })); - }; - -export const workpadServiceFactory: CanvasWorkpadServiceFactory = ({ - workpadCount, - hasTemplates, - useStaticData, -}) => ({ - get: (id: string) => { - action('workpadService.get')(id); - return Promise.resolve({ ...getDefaultWorkpad(), id }); - }, - resolve: (id: string) => { - action('workpadService.resolve')(id); - return Promise.resolve({ outcome: 'exactMatch', workpad: { ...getDefaultWorkpad(), id } }); - }, - findTemplates: () => { - action('workpadService.findTemplates')(); - return (hasTemplates ? findSomeTemplates() : findNoTemplates())(); - }, - import: (workpad) => { - action('workpadService.import')(workpad); - return importWorkpad(workpad); - }, - create: (workpad) => { - action('workpadService.create')(workpad); - return Promise.resolve(workpad); - }, - createFromTemplate: (templateId: string) => { - action('workpadService.createFromTemplate')(templateId); - return Promise.resolve(getDefaultWorkpad()); - }, - find: (term: string) => { - action('workpadService.find')(term); - return (workpadCount ? findSomeWorkpads(workpadCount, useStaticData) : findNoWorkpads())(term); - }, - remove: (id: string) => { - action('workpadService.remove')(id); - return Promise.resolve(); - }, - update: (id, workpad) => { - action('worpadService.update')(workpad, id); - return Promise.resolve(); - }, - updateWorkpad: (id, workpad) => { - action('workpadService.updateWorkpad')(workpad, id); - return Promise.resolve(); - }, - updateAssets: (id, assets) => { - action('workpadService.updateAssets')(assets, id); - return Promise.resolve(); - }, - getRuntimeZip: (workpad) => - Promise.resolve(new Blob([JSON.stringify(workpad)], { type: 'application/json' })), -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/custom_element.ts b/x-pack/plugins/canvas/public/services/stubs/custom_element.ts deleted file mode 100644 index 551c06ef4b65e..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/custom_element.ts +++ /dev/null @@ -1,21 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasCustomElementService } from '../custom_element'; - -type CanvasCustomElementServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const customElementServiceFactory: CanvasCustomElementServiceFactory = () => ({ - create: noop, - find: noop, - get: noop, - remove: noop, - update: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/data_views.ts b/x-pack/plugins/canvas/public/services/stubs/data_views.ts deleted file mode 100644 index 1b1227dba4d3f..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/data_views.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasDataViewsService } from '../data_views'; - -type DataViewsServiceFactory = PluginServiceFactory; - -export const dataViewsServiceFactory: DataViewsServiceFactory = () => ({ - getDataViews: () => - Promise.resolve([ - { id: 'dataview1', title: 'dataview1', name: 'Data view 1' }, - { id: 'dataview2', title: 'dataview2', name: 'Data view 2' }, - ]), - getFields: () => Promise.resolve(['field1', 'field2']), - getDefaultDataView: () => - Promise.resolve({ - id: 'defaultDataViewId', - title: 'defaultDataView', - name: 'Default data view', - }), -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts b/x-pack/plugins/canvas/public/services/stubs/embeddables.ts deleted file mode 100644 index 95131efec2bde..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/embeddables.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasEmbeddablesService } from '../embeddables'; - -type EmbeddablesServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const embeddablesServiceFactory: EmbeddablesServiceFactory = () => ({ - reactEmbeddableRegistryHasKey: noop, - getReactEmbeddableSavedObjects: noop, - getEmbeddableFactories: noop, - getStateTransfer: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/expressions.ts b/x-pack/plugins/canvas/public/services/stubs/expressions.ts deleted file mode 100644 index 177eb1e50d75f..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/expressions.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { AnyExpressionRenderDefinition } from '@kbn/expressions-plugin/common'; -import { plugin } from '@kbn/expressions-plugin/public'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { functions as functionDefinitions } from '../../../canvas_plugin_src/functions/common'; -import { renderFunctions } from '../../../canvas_plugin_src/renderers/core'; -import { - CanvasExpressionsService, - CanvasExpressionsServiceRequiredServices, - ExpressionsService, -} from '../kibana/expressions'; - -type CanvasExpressionsServiceFactory = PluginServiceFactory< - CanvasExpressionsService, - {}, - CanvasExpressionsServiceRequiredServices ->; - -export const expressionsServiceFactory: CanvasExpressionsServiceFactory = ( - params, - requiredServices -) => { - const placeholder = {} as any; - const expressionsPlugin = plugin(placeholder); - const setup = expressionsPlugin.setup(placeholder); - const fork = setup.fork('canvas'); - const expressionsService = fork.setup(); - - functionDefinitions.forEach((fn) => expressionsService.registerFunction(fn)); - renderFunctions.forEach((fn) => { - setup.registerRenderer(fn as unknown as AnyExpressionRenderDefinition); - }); - - return new ExpressionsService(fork.start(), requiredServices); -}; diff --git a/x-pack/plugins/canvas/public/services/stubs/filters.ts b/x-pack/plugins/canvas/public/services/stubs/filters.ts deleted file mode 100644 index 19d237bb9c390..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/filters.ts +++ /dev/null @@ -1,23 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasFiltersService } from '../filters'; - -export type CanvasFiltersServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const filtersServiceFactory: CanvasFiltersServiceFactory = () => ({ - getFilters: () => [ - 'exactly value="machine-learning" column="project1" filterGroup="Group 1"', - 'exactly value="kibana" column="project2" filterGroup="Group 1"', - 'time column="@timestamp1" from="2021-11-02 17:13:18" to="2021-11-09 17:13:18" filterGroup="Some group"', - ], - updateFilter: noop, - getFiltersContext: () => ({ variables: {} }), -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/index.ts b/x-pack/plugins/canvas/public/services/stubs/index.ts deleted file mode 100644 index c129441b07825..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/index.ts +++ /dev/null @@ -1,61 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export * from '../legacy/stubs'; - -import { - PluginServiceProviders, - PluginServiceProvider, - PluginServiceRegistry, -} from '@kbn/presentation-util-plugin/public'; - -import { CanvasPluginServices } from '..'; -import { customElementServiceFactory } from './custom_element'; -import { dataViewsServiceFactory } from './data_views'; -import { embeddablesServiceFactory } from './embeddables'; -import { expressionsServiceFactory } from './expressions'; -import { labsServiceFactory } from './labs'; -import { navLinkServiceFactory } from './nav_link'; -import { notifyServiceFactory } from './notify'; -import { platformServiceFactory } from './platform'; -import { reportingServiceFactory } from './reporting'; -import { visualizationsServiceFactory } from './visualizations'; -import { workpadServiceFactory } from './workpad'; -import { filtersServiceFactory } from './filters'; -import { uiActionsServiceFactory } from './ui_actions'; - -export { customElementServiceFactory } from './custom_element'; -export { dataViewsServiceFactory } from './data_views'; -export { expressionsServiceFactory } from './expressions'; -export { filtersServiceFactory } from './filters'; -export { labsServiceFactory } from './labs'; -export { navLinkServiceFactory } from './nav_link'; -export { notifyServiceFactory } from './notify'; -export { platformServiceFactory } from './platform'; -export { reportingServiceFactory } from './reporting'; -export { visualizationsServiceFactory } from './visualizations'; -export { workpadServiceFactory } from './workpad'; - -export const pluginServiceProviders: PluginServiceProviders = { - customElement: new PluginServiceProvider(customElementServiceFactory), - dataViews: new PluginServiceProvider(dataViewsServiceFactory), - embeddables: new PluginServiceProvider(embeddablesServiceFactory), - expressions: new PluginServiceProvider(expressionsServiceFactory, ['filters', 'notify']), - filters: new PluginServiceProvider(filtersServiceFactory), - labs: new PluginServiceProvider(labsServiceFactory), - navLink: new PluginServiceProvider(navLinkServiceFactory), - notify: new PluginServiceProvider(notifyServiceFactory), - platform: new PluginServiceProvider(platformServiceFactory), - reporting: new PluginServiceProvider(reportingServiceFactory), - visualizations: new PluginServiceProvider(visualizationsServiceFactory), - workpad: new PluginServiceProvider(workpadServiceFactory), - uiActions: new PluginServiceProvider(uiActionsServiceFactory), -}; - -export const pluginServiceRegistry = new PluginServiceRegistry( - pluginServiceProviders -); diff --git a/x-pack/plugins/canvas/public/services/stubs/labs.ts b/x-pack/plugins/canvas/public/services/stubs/labs.ts deleted file mode 100644 index d563126a15da3..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/labs.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { projectIDs } from '@kbn/presentation-util-plugin/common'; -import { CanvasLabsService } from '../labs'; - -type CanvasLabsServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const labsServiceFactory: CanvasLabsServiceFactory = () => ({ - getProject: noop, - getProjects: noop, - getProjectIDs: () => projectIDs, - isProjectEnabled: () => false, - isLabsEnabled: () => true, - projectIDs, - reset: noop, - setProjectStatus: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/nav_link.ts b/x-pack/plugins/canvas/public/services/stubs/nav_link.ts deleted file mode 100644 index becbdebcd6328..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/nav_link.ts +++ /dev/null @@ -1,17 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasNavLinkService } from '../nav_link'; - -type CanvasNavLinkServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const navLinkServiceFactory: CanvasNavLinkServiceFactory = () => ({ - updatePath: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/notify.ts b/x-pack/plugins/canvas/public/services/stubs/notify.ts deleted file mode 100644 index 2406afe3ca8a2..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/notify.ts +++ /dev/null @@ -1,21 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasNotifyService } from '../notify'; - -type CanvasNotifyServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const notifyServiceFactory: CanvasNotifyServiceFactory = () => ({ - error: noop, - info: noop, - success: noop, - warning: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/platform.ts b/x-pack/plugins/canvas/public/services/stubs/platform.ts deleted file mode 100644 index 0726810075251..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/platform.ts +++ /dev/null @@ -1,39 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasPlatformService } from '../platform'; - -type CanvasPlatformServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -const uiSettings: Record = { - dateFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', -}; - -const getUISetting = (setting: string) => uiSettings[setting]; - -export const platformServiceFactory: CanvasPlatformServiceFactory = () => ({ - getBasePath: () => '/base/path', - getBasePathInterface: noop, - getDocLinkVersion: () => 'docLinkVersion', - getElasticWebsiteUrl: () => 'https://elastic.co', - getKibanaVersion: () => 'kibanaVersion', - getHasWriteAccess: () => true, - getUISetting, - hasHeaderBanner$: noop, - setBreadcrumbs: noop, - setRecentlyAccessed: noop, - getUISettings: noop, - setFullscreen: noop, - redirectLegacyUrl: noop, - getLegacyUrlConflict: undefined, - getHttp: noop, - getContentManagement: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/reporting.tsx b/x-pack/plugins/canvas/public/services/stubs/reporting.tsx deleted file mode 100644 index 71c376efbaba9..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/reporting.tsx +++ /dev/null @@ -1,17 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -import { CanvasReportingService } from '../reporting'; - -type CanvasReportingServiceFactory = PluginServiceFactory; - -export const reportingServiceFactory: CanvasReportingServiceFactory = () => ({ - getReportingPanelPDFComponent: () => () =>
Reporting Panel PDF
, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/ui_actions.ts b/x-pack/plugins/canvas/public/services/stubs/ui_actions.ts deleted file mode 100644 index 84039e0888be8..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/ui_actions.ts +++ /dev/null @@ -1,17 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; -import { CanvasUiActionsService } from '../ui_actions'; - -type UiActionsServiceFactory = PluginServiceFactory; - -export const uiActionsServiceFactory: UiActionsServiceFactory = () => { - const pluginMock = uiActionsPluginMock.createStartContract(); - return { getTriggerCompatibleActions: pluginMock.getTriggerCompatibleActions }; -}; diff --git a/x-pack/plugins/canvas/public/services/stubs/visualizations.ts b/x-pack/plugins/canvas/public/services/stubs/visualizations.ts deleted file mode 100644 index 812287bf078fb..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/visualizations.ts +++ /dev/null @@ -1,19 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; -import { CanvasVisualizationsService } from '../visualizations'; - -type VisualizationsServiceFactory = PluginServiceFactory; - -const noop = (..._args: any[]): any => {}; - -export const visualizationsServiceFactory: VisualizationsServiceFactory = () => ({ - showNewVisModal: noop, - getByGroup: noop, - getAliases: noop, -}); diff --git a/x-pack/plugins/canvas/public/services/stubs/workpad.ts b/x-pack/plugins/canvas/public/services/stubs/workpad.ts deleted file mode 100644 index 51be4e150ebe5..0000000000000 --- a/x-pack/plugins/canvas/public/services/stubs/workpad.ts +++ /dev/null @@ -1,115 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; -import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; - -// @ts-expect-error -import { getDefaultWorkpad } from '../../state/defaults'; -import { CanvasWorkpadService } from '../workpad'; -import { CanvasTemplate, CanvasWorkpad } from '../../../types'; - -type CanvasWorkpadServiceFactory = PluginServiceFactory; - -export const TIMEOUT = 500; -export const promiseTimeout = (time: number) => () => - new Promise((resolve) => setTimeout(resolve, time)); - -const DAY = 86400000; -const JAN_1_2000 = 946684800000; - -const getWorkpads = (count = 3) => { - const workpads = []; - for (let i = 0; i < count; i++) { - workpads[i] = { - ...getDefaultWorkpad(), - name: `Workpad ${i}`, - id: `workpad-${i}`, - '@created': moment(JAN_1_2000 + DAY * i).toDate(), - '@timestamp': moment(JAN_1_2000 + DAY * (i + 1)).toDate(), - }; - } - return workpads; -}; - -export const getSomeWorkpads = (count = 3) => getWorkpads(count); - -export const findSomeWorkpads = - (count = 3, timeout = TIMEOUT) => - (_term: string) => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => ({ - total: count, - workpads: getSomeWorkpads(count), - })); - }; - -const templates: CanvasTemplate[] = [ - { - id: 'test1-id', - name: 'test1', - help: 'This is a test template', - tags: ['tag1', 'tag2'], - template_key: 'test1-key', - }, - { - id: 'test2-id', - name: 'test2', - help: 'This is a second test template', - tags: ['tag2', 'tag3'], - template_key: 'test2-key', - }, -]; - -export const findNoWorkpads = - (timeout = TIMEOUT) => - (_term: string) => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => ({ - total: 0, - workpads: [], - })); - }; - -export const findSomeTemplates = - (timeout = TIMEOUT) => - () => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => getSomeTemplates()); - }; - -export const findNoTemplates = - (timeout = TIMEOUT) => - () => { - return Promise.resolve() - .then(promiseTimeout(timeout)) - .then(() => getNoTemplates()); - }; - -export const importWorkpad = (workpad: CanvasWorkpad) => Promise.resolve(workpad); -export const getNoTemplates = () => ({ templates: [] }); -export const getSomeTemplates = () => ({ templates }); - -export const workpadServiceFactory: CanvasWorkpadServiceFactory = () => ({ - get: (id: string) => Promise.resolve({ ...getDefaultWorkpad(), id }), - resolve: (id: string) => - Promise.resolve({ outcome: 'exactMatch', workpad: { ...getDefaultWorkpad(), id } }), - findTemplates: findNoTemplates(), - create: (workpad) => Promise.resolve(workpad), - import: (workpad) => importWorkpad(workpad), - createFromTemplate: (_templateId: string) => Promise.resolve(getDefaultWorkpad()), - find: findNoWorkpads(), - remove: (_id: string) => Promise.resolve(), - update: (id, workpad) => Promise.resolve(), - updateWorkpad: (id, workpad) => Promise.resolve(), - updateAssets: (id, assets) => Promise.resolve(), - getRuntimeZip: (workpad) => - Promise.resolve(new Blob([JSON.stringify(workpad)], { type: 'application/json' })), -}); diff --git a/x-pack/plugins/canvas/public/services/ui_actions.ts b/x-pack/plugins/canvas/public/services/ui_actions.ts deleted file mode 100644 index 62f99facce023..0000000000000 --- a/x-pack/plugins/canvas/public/services/ui_actions.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; - -export interface CanvasUiActionsService { - getTriggerCompatibleActions: UiActionsStart['getTriggerCompatibleActions']; -} diff --git a/x-pack/plugins/canvas/public/services/visualizations.ts b/x-pack/plugins/canvas/public/services/visualizations.ts deleted file mode 100644 index dc816f764e5ec..0000000000000 --- a/x-pack/plugins/canvas/public/services/visualizations.ts +++ /dev/null @@ -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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { VisualizationsStart } from '@kbn/visualizations-plugin/public'; - -export interface CanvasVisualizationsService { - showNewVisModal: VisualizationsStart['showNewVisModal']; - getByGroup: VisualizationsStart['getByGroup']; - getAliases: VisualizationsStart['getAliases']; -} diff --git a/x-pack/plugins/canvas/public/services/workpad.ts b/x-pack/plugins/canvas/public/services/workpad.ts deleted file mode 100644 index 72996f54c158d..0000000000000 --- a/x-pack/plugins/canvas/public/services/workpad.ts +++ /dev/null @@ -1,43 +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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ResolvedSimpleSavedObject } from '@kbn/core/public'; -import { CanvasWorkpad, CanvasTemplate } from '../../types'; -import type { CanvasRenderedWorkpad } from '../../shareable_runtime/types'; - -export type FoundWorkpads = Array>; -export type FoundWorkpad = FoundWorkpads[number]; -export interface WorkpadFindResponse { - total: number; - workpads: FoundWorkpads; -} - -export interface TemplateFindResponse { - templates: CanvasTemplate[]; -} - -export interface ResolveWorkpadResponse { - workpad: CanvasWorkpad; - outcome: ResolvedSimpleSavedObject['outcome']; - aliasId?: ResolvedSimpleSavedObject['alias_target_id']; - aliasPurpose?: ResolvedSimpleSavedObject['alias_purpose']; -} - -export interface CanvasWorkpadService { - get: (id: string) => Promise; - resolve: (id: string) => Promise; - create: (workpad: CanvasWorkpad) => Promise; - import: (workpad: CanvasWorkpad) => Promise; - createFromTemplate: (templateId: string) => Promise; - find: (term: string) => Promise; - remove: (id: string) => Promise; - findTemplates: () => Promise; - update: (id: string, workpad: CanvasWorkpad) => Promise; - updateWorkpad: (id: string, workpad: CanvasWorkpad) => Promise; - updateAssets: (id: string, assets: CanvasWorkpad['assets']) => Promise; - getRuntimeZip: (workpad: CanvasRenderedWorkpad) => Promise; -} diff --git a/x-pack/plugins/canvas/public/state/actions/elements.js b/x-pack/plugins/canvas/public/state/actions/elements.js index b94a198ee4be9..57b7da1ce1fef 100644 --- a/x-pack/plugins/canvas/public/state/actions/elements.js +++ b/x-pack/plugins/canvas/public/state/actions/elements.js @@ -23,9 +23,11 @@ import { getValue as getResolvedArgsValue } from '../selectors/resolved_args'; import { getDefaultElement } from '../defaults'; import { ErrorStrings } from '../../../i18n'; import { subMultitree } from '../../lib/aeroelastic/functional'; -import { pluginServices } from '../../services'; +import { getCanvasExpressionService } from '../../services/canvas_expressions_service'; +import { getCanvasNotifyService } from '../../services/canvas_notify_service'; import { selectToplevelNodes } from './transient'; import * as args from './resolved_args'; +import { setFilter } from './filters'; const { actionsElements: strings } = ErrorStrings; @@ -101,7 +103,7 @@ const fetchContextFn = ({ dispatch, getState }, index, element, fullRefresh = fa const variables = getWorkpadVariablesAsObject(getState()); - const { expressions } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); const elementWithNewAst = set(element, pathToTarget, astChain); // get context data from a partial AST @@ -129,7 +131,8 @@ const fetchRenderableWithContextFn = ({ dispatch, getState }, element, ast, cont }); const variables = getWorkpadVariablesAsObject(getState()); - const { expressions, notify } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); + const notify = getCanvasNotifyService(); return expressions .runInterpreter(ast, context, variables, { castToRender: true }) @@ -177,7 +180,8 @@ export const fetchAllRenderables = createThunk( const argumentPath = [element.id, 'expressionRenderable']; const variables = getWorkpadVariablesAsObject(getState()); - const { expressions, notify } = pluginServices.getServices(); + const expressions = getCanvasExpressionService(); + const notify = getCanvasNotifyService(); return expressions .runInterpreter(ast, null, variables, { castToRender: true }) @@ -260,18 +264,6 @@ export const removeElements = createThunk( } ); -export const setFilter = createThunk( - 'setFilter', - ({ dispatch }, filter, elementId, doRender = true) => { - const _setFilter = createAction('setFilter'); - dispatch(_setFilter({ filter, elementId })); - - if (doRender === true) { - dispatch(fetchAllRenderables()); - } - } -); - export const setExpression = createThunk('setExpression', setExpressionFn); function setExpressionFn({ dispatch, getState }, expression, elementId, pageId, doRender = true) { // dispatch action to update the element in state @@ -290,7 +282,11 @@ function setExpressionFn({ dispatch, getState }, expression, elementId, pageId, ) ) { const filter = ''; - dispatch(setFilter(filter, elementId, pageId, doRender)); + dispatch(setFilter(filter, elementId, pageId)); + + if (doRender) { + dispatch(fetchAllRenderables(updatedElement)); + } // setFilter will trigger a re-render so we can skip the fetch here } else if (doRender === true) { dispatch(fetchRenderable(updatedElement)); @@ -302,7 +298,7 @@ const setAst = createThunk('setAst', ({ dispatch }, ast, element, pageId, doRend const expression = toExpression(ast); dispatch(setExpression(expression, element.id, pageId, doRender)); } catch (err) { - const notifyService = pluginServices.getServices().notify; + const notifyService = getCanvasNotifyService(); notifyService.error(err); // TODO: remove this, may have been added just to cause a re-render, but why? diff --git a/x-pack/plugins/canvas/public/state/actions/filters.js b/x-pack/plugins/canvas/public/state/actions/filters.js new file mode 100644 index 0000000000000..3347925dc5a15 --- /dev/null +++ b/x-pack/plugins/canvas/public/state/actions/filters.js @@ -0,0 +1,13 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { createAction } from 'redux-actions'; +import { createThunk } from '../../lib/create_thunk'; + +export const setFilter = createThunk('setFilter', ({ dispatch }, filter, elementId) => { + const _setFilter = createAction('setFilter'); + dispatch(_setFilter({ filter, elementId })); +}); diff --git a/x-pack/plugins/canvas/public/state/initial_state.js b/x-pack/plugins/canvas/public/state/initial_state.js index 88330c92d867b..fd509c952ef18 100644 --- a/x-pack/plugins/canvas/public/state/initial_state.js +++ b/x-pack/plugins/canvas/public/state/initial_state.js @@ -6,18 +6,15 @@ */ import { get } from 'lodash'; -import { pluginServices } from '../services'; +import { coreServices } from '../services/kibana_services'; import { getDefaultWorkpad, getDefaultSidebar, getDefaultFlyouts } from './defaults'; export const getInitialState = (path) => { - const platformService = pluginServices.getServices().platform; - const { getHasWriteAccess } = platformService; - const state = { app: {}, // Kibana stuff in here assets: {}, // assets end up here transient: { - canUserWrite: getHasWriteAccess(), + canUserWrite: coreServices.application.capabilities.canvas.save, zoomScale: 1, elementStats: { total: 0, diff --git a/x-pack/plugins/canvas/public/state/reducers/elements.js b/x-pack/plugins/canvas/public/state/reducers/elements.js index 2be1cf519ee13..fdb15a5621222 100644 --- a/x-pack/plugins/canvas/public/state/reducers/elements.js +++ b/x-pack/plugins/canvas/public/state/reducers/elements.js @@ -8,7 +8,6 @@ import { handleActions } from 'redux-actions'; import immutable from 'object-path-immutable'; import { get } from 'lodash'; -import * as actions from '../actions/elements'; const { assign, push, del, set } = immutable; @@ -102,17 +101,16 @@ const getPageWithElementId = (workpad, elementId) => { export const elementsReducer = handleActions( { - // TODO: This takes the entire element, which is not necessary, it could just take the id. - [actions.setExpression]: (workpadState, { payload }) => { + ['setExpression']: (workpadState, { payload }) => { const { expression, pageId, elementId } = payload; return assignNodeProperties(workpadState, pageId, elementId, { expression }); }, - [actions.setFilter]: (workpadState, { payload }) => { + ['setFilter']: (workpadState, { payload }) => { const { filter, elementId } = payload; const pageId = getPageWithElementId(workpadState, elementId); return assignNodeProperties(workpadState, pageId, elementId, { filter }); }, - [actions.setMultiplePositions]: (workpadState, { payload }) => + ['setMultiplePositions']: (workpadState, { payload }) => payload.repositionedElements.reduce( (previousWorkpadState, { position, pageId, elementId }) => assignNodeProperties(previousWorkpadState, pageId, elementId, { @@ -120,11 +118,11 @@ export const elementsReducer = handleActions( }), workpadState ), - [actions.elementLayer]: (workpadState, { payload: { pageId, elementId, movement } }) => { + ['elementLayer']: (workpadState, { payload: { pageId, elementId, movement } }) => { const location = getLocationFromIds(workpadState, pageId, elementId); return moveNodeLayer(workpadState, pageId, elementId, movement, location); }, - [actions.addElement]: (workpadState, { payload: { pageId, element } }) => { + ['addElement']: (workpadState, { payload: { pageId, element } }) => { const pageIndex = getPageIndexById(workpadState, pageId); if (pageIndex < 0) { return workpadState; @@ -143,7 +141,7 @@ export const elementsReducer = handleActions( trimElement(element) ); }, - [actions.insertNodes]: (workpadState, { payload: { pageId, elements } }) => { + ['insertNodes']: (workpadState, { payload: { pageId, elements } }) => { const pageIndex = getPageIndexById(workpadState, pageId); if (pageIndex < 0) { return workpadState; @@ -158,7 +156,7 @@ export const elementsReducer = handleActions( workpadState ); }, - [actions.removeElements]: (workpadState, { payload: { pageId, elementIds } }) => { + ['removeElements']: (workpadState, { payload: { pageId, elementIds } }) => { const pageIndex = getPageIndexById(workpadState, pageId); if (pageIndex < 0) { return workpadState; diff --git a/x-pack/plugins/canvas/public/state/reducers/embeddable.ts b/x-pack/plugins/canvas/public/state/reducers/embeddable.ts index 5b963e2c80c7e..8f79ed529cd96 100644 --- a/x-pack/plugins/canvas/public/state/reducers/embeddable.ts +++ b/x-pack/plugins/canvas/public/state/reducers/embeddable.ts @@ -9,10 +9,7 @@ import { fromExpression, toExpression } from '@kbn/interpreter'; import { handleActions } from 'redux-actions'; import { State } from '../../../types'; -import { - UpdateEmbeddableExpressionActionType, - UpdateEmbeddableExpressionPayload, -} from '../actions/embeddable'; +import { UpdateEmbeddableExpressionPayload } from '../actions/embeddable'; // @ts-expect-error untyped local import { assignNodeProperties } from './elements'; @@ -22,7 +19,7 @@ export const embeddableReducer = handleActions< UpdateEmbeddableExpressionPayload >( { - [UpdateEmbeddableExpressionActionType]: (workpadState, { payload }) => { + ['updateEmbeddableExpression']: (workpadState, { payload }) => { if (!payload) { return workpadState; } diff --git a/x-pack/plugins/canvas/public/state/reducers/resolved_args.js b/x-pack/plugins/canvas/public/state/reducers/resolved_args.js index 3514036cafc0d..3652a8d462fb8 100644 --- a/x-pack/plugins/canvas/public/state/reducers/resolved_args.js +++ b/x-pack/plugins/canvas/public/state/reducers/resolved_args.js @@ -10,8 +10,6 @@ import immutable from 'object-path-immutable'; import { get } from 'lodash'; import { prepend } from '../../lib/modify_path'; import * as actions from '../actions/resolved_args'; -import { flushContext, flushContextAfterIndex } from '../actions/elements'; -import { setWorkpad } from '../actions/workpad'; const { set, del } = immutable; /* @@ -114,14 +112,14 @@ export const resolvedArgsReducer = handleActions( /* * Flush all cached contexts */ - [flushContext]: (transientState, { payload: elementId }) => { + ['flushContext']: (transientState, { payload: elementId }) => { return del(transientState, getFullPath([elementId, 'expressionContext'])); }, /* * Flush cached context indices from the given index to the last */ - [flushContextAfterIndex]: (transientState, { payload }) => { + ['flushContextAfterIndex']: (transientState, { payload }) => { const { elementId, index } = payload; const expressionContext = get(transientState, getFullPath([elementId, 'expressionContext'])); @@ -139,7 +137,7 @@ export const resolvedArgsReducer = handleActions( return state; }, transientState); }, - [setWorkpad]: (transientState, {}) => { + ['setWorkpad']: (transientState, {}) => { return set(transientState, 'resolvedArgs', {}); }, }, diff --git a/x-pack/plugins/canvas/public/state/reducers/transient.js b/x-pack/plugins/canvas/public/state/reducers/transient.js index e41ab5e4822a9..2f0e7bd66126c 100644 --- a/x-pack/plugins/canvas/public/state/reducers/transient.js +++ b/x-pack/plugins/canvas/public/state/reducers/transient.js @@ -7,11 +7,6 @@ import { handleActions } from 'redux-actions'; import immutable from 'object-path-immutable'; -import { restoreHistory } from '../actions/history'; -import * as pageActions from '../actions/pages'; -import * as transientActions from '../actions/transient'; -import { removeElements } from '../actions/elements'; -import { setRefreshInterval, enableAutoplay, setAutoplayInterval } from '../actions/workpad'; const { set, del } = immutable; @@ -19,9 +14,9 @@ export const transientReducer = handleActions( { // clear all the resolved args when restoring the history // TODO: we shouldn't need to reset the resolved args for history - [restoreHistory]: (transientState) => set(transientState, 'resolvedArgs', {}), + ['restoreHistory']: (transientState) => set(transientState, 'resolvedArgs', {}), - [removeElements]: (transientState, { payload: { elementIds } }) => { + ['removeElements']: (transientState, { payload: { elementIds } }) => { const { selectedToplevelNodes } = transientState; return del( { @@ -32,53 +27,53 @@ export const transientReducer = handleActions( ); }, - [transientActions.setFirstLoad]: (transientState, { payload }) => { + ['setFirstLoad']: (transientState, { payload }) => { return set(transientState, 'isFirstLoad', Boolean(payload)); }, - [transientActions.setFullscreen]: (transientState, { payload }) => { + ['setFullscreen']: (transientState, { payload }) => { return set(transientState, 'fullscreen', Boolean(payload)); }, - [transientActions.setElementStats]: (transientState, { payload }) => { + ['setElementStats']: (transientState, { payload }) => { return set(transientState, 'elementStats', payload); }, - [transientActions.selectToplevelNodes]: (transientState, { payload }) => { + ['selectToplevelNodes']: (transientState, { payload }) => { return { ...transientState, selectedToplevelNodes: payload, }; }, - [transientActions.setZoomScale]: (transientState, { payload }) => { + ['setZoomScale']: (transientState, { payload }) => { return { ...transientState, zoomScale: payload || 1, }; }, - [pageActions.setPage]: (transientState) => { + ['setPage']: (transientState) => { return { ...transientState, selectedToplevelNodes: [] }; }, - [pageActions.addPage]: (transientState) => { + ['addPage']: (transientState) => { return { ...transientState, selectedToplevelNodes: [] }; }, - [pageActions.duplicatePage]: (transientState) => { + ['duplicatePage']: (transientState) => { return { ...transientState, selectedToplevelNodes: [] }; }, - [setRefreshInterval]: (transientState, { payload }) => { + ['setRefreshInterval']: (transientState, { payload }) => { return { ...transientState, refresh: { interval: Number(payload) || 0 } }; }, - [enableAutoplay]: (transientState, { payload }) => { + ['enableAutoplay']: (transientState, { payload }) => { return set(transientState, 'autoplay.enabled', Boolean(payload) || false); }, - [setAutoplayInterval]: (transientState, { payload }) => { + ['setAutoplayInterval']: (transientState, { payload }) => { return set(transientState, 'autoplay.interval', Number(payload) || 0); }, }, diff --git a/x-pack/plugins/canvas/public/state/reducers/workpad.js b/x-pack/plugins/canvas/public/state/reducers/workpad.js index ebde0106f9c01..9c337f965ae3a 100644 --- a/x-pack/plugins/canvas/public/state/reducers/workpad.js +++ b/x-pack/plugins/canvas/public/state/reducers/workpad.js @@ -6,66 +6,52 @@ */ import { handleActions } from 'redux-actions'; -import { pluginServices } from '../../services'; +import { coreServices } from '../../services/kibana_services'; import { getDefaultWorkpad } from '../defaults'; -import { - setWorkpad, - sizeWorkpad, - setColors, - setName, - setWriteable, - setWorkpadCSS, - setWorkpadVariables, - resetWorkpad, -} from '../actions/workpad'; import { APP_ROUTE_WORKPAD } from '../../../common/lib/constants'; export const workpadReducer = handleActions( { - [setWorkpad]: (workpadState, { payload }) => { - pluginServices - .getServices() - .platform.setRecentlyAccessed( - `${APP_ROUTE_WORKPAD}/${payload.id}`, - payload.name, - payload.id - ); + ['setWorkpad']: (workpadState, { payload }) => { + coreServices.chrome.recentlyAccessed.add( + `${APP_ROUTE_WORKPAD}/${payload.id}`, + payload.name, + payload.id + ); return payload; }, - [sizeWorkpad]: (workpadState, { payload }) => { + ['sizeWorkpad']: (workpadState, { payload }) => { return { ...workpadState, ...payload }; }, - [setColors]: (workpadState, { payload }) => { + ['setColors']: (workpadState, { payload }) => { return { ...workpadState, colors: payload }; }, - [setName]: (workpadState, { payload }) => { - pluginServices - .getServices() - .platform.setRecentlyAccessed( - `${APP_ROUTE_WORKPAD}/${workpadState.id}`, - payload, - workpadState.id - ); + ['setName']: (workpadState, { payload }) => { + coreServices.chrome.recentlyAccessed.add( + `${APP_ROUTE_WORKPAD}/${workpadState.id}`, + payload, + workpadState.id + ); return { ...workpadState, name: payload }; }, - [setWriteable]: (workpadState, { payload }) => { + ['setWriteable']: (workpadState, { payload }) => { return { ...workpadState, isWriteable: Boolean(payload) }; }, - [setWorkpadCSS]: (workpadState, { payload }) => { + ['setWorkpadCSS']: (workpadState, { payload }) => { return { ...workpadState, css: payload }; }, - [setWorkpadVariables]: (workpadState, { payload }) => { + ['setWorkpadVariables']: (workpadState, { payload }) => { return { ...workpadState, variables: payload }; }, - [resetWorkpad]: () => ({ ...getDefaultWorkpad() }), + ['resetWorkpad']: () => ({ ...getDefaultWorkpad() }), }, {} ); diff --git a/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap b/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap index 010847e63a023..4aa379aa194bc 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap +++ b/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` App renders properly 1`] = `"
markdown mock
markdown mock

Page level controls

My Canvas Workpad

There is a new region landmark with page level controls at the end of the document.

"`; +exports[` App renders properly 1`] = `"
markdown mock
markdown mock

Page level controls

My Canvas Workpad

There is a new region landmark with page level controls at the end of the document.

"`; diff --git a/x-pack/plugins/canvas/shareable_runtime/components/app.test.tsx b/x-pack/plugins/canvas/shareable_runtime/components/app.test.tsx index ec4ea09e8fcc7..30d55c8531b1d 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/app.test.tsx +++ b/x-pack/plugins/canvas/shareable_runtime/components/app.test.tsx @@ -13,6 +13,7 @@ import { mount, ReactWrapper } from 'enzyme'; import React from 'react'; + // import { act } from 'react-dom/test-utils'; import { App } from './app'; import { sharedWorkpads, WorkpadNames, tick } from '../test'; @@ -34,17 +35,14 @@ import { openSettings, selectMenuItem } from '../test/interactions'; // Mock the renderers jest.mock('../supported_renderers'); +// @ts-ignore Importing this to mock +import * as Portal from '@elastic/eui/lib/components/portal/portal'; + // Mock the EuiPortal - `insertAdjacentElement is not supported in // `jsdom` 12. We're just going to render a `div` with the children // so the `enzyme` tests will be accurate. -jest.mock('@elastic/eui/lib/components/portal/portal', () => { - // Local constants are not supported in Jest mocks-- they must be - // imported within the mock. - // eslint-disable-next-line @typescript-eslint/no-shadow - const React = jest.requireActual('react'); - return { - EuiPortal: (props: any) =>
{props.children}
, - }; +jest.spyOn(Portal, 'EuiPortal').mockImplementation((props: any) => { + return
{props.children}
; }); const getWrapper: (name?: WorkpadNames) => ReactWrapper = (name = 'hello') => { diff --git a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap index bf66b5df800ec..cfe41427b1ea1 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap +++ b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap @@ -1,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` can navigate Autoplay Settings 1`] = ` -
+
@@ -94,7 +96,9 @@ exports[` can navigate Autoplay Settings 1`] = ` `; exports[` can navigate Autoplay Settings 2`] = ` -
+
@@ -338,7 +342,9 @@ exports[` can navigate Autoplay Settings 2`] = ` `; exports[` can navigate Toolbar Settings, closes when activated 1`] = ` -
+
@@ -431,7 +437,9 @@ exports[` can navigate Toolbar Settings, closes when activated 1`] = `; exports[` can navigate Toolbar Settings, closes when activated 2`] = ` -
+
@@ -606,7 +614,9 @@ exports[` can navigate Toolbar Settings, closes when activated 2`] = `; exports[` can navigate Toolbar Settings, closes when activated 3`] = ` -
+
diff --git a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/settings.test.tsx b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/settings.test.tsx index cc275dd983e3c..0ab9e13e36765 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/settings.test.tsx +++ b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/settings.test.tsx @@ -21,12 +21,14 @@ import { Settings } from './settings'; jest.mock('../../../supported_renderers'); -jest.mock('@elastic/eui/lib/components/portal/portal', () => { - // eslint-disable-next-line @typescript-eslint/no-shadow - const React = jest.requireActual('react'); - return { - EuiPortal: (props: any) =>
{props.children}
, - }; +// @ts-ignore Importing this to mock +import * as Portal from '@elastic/eui/lib/components/portal/portal'; + +// Mock the EuiPortal - `insertAdjacentElement is not supported in +// `jsdom` 12. We're just going to render a `div` with the children +// so the `enzyme` tests will be accurate. +jest.spyOn(Portal, 'EuiPortal').mockImplementation((props: any) => { + return
{props.children}
; }); describe('', () => { diff --git a/x-pack/plugins/canvas/shareable_runtime/test/selectors.ts b/x-pack/plugins/canvas/shareable_runtime/test/selectors.ts index bcfe94adf94be..f4d4f8ac442d7 100644 --- a/x-pack/plugins/canvas/shareable_runtime/test/selectors.ts +++ b/x-pack/plugins/canvas/shareable_runtime/test/selectors.ts @@ -42,7 +42,7 @@ export const getSettingsTrigger = (wrapper: ReactWrapper) => export const getPopover = (wrapper: ReactWrapper) => wrapper.find('EuiPopover'); -export const getPortal = (wrapper: ReactWrapper) => wrapper.find('EuiPortal'); +export const getPortal = (wrapper: ReactWrapper) => wrapper.find('.mockedEuiPortal'); export const getContextMenu = (wrapper: ReactWrapper) => wrapper.find('EuiContextMenuClass'); diff --git a/x-pack/plugins/canvas/storybook/constants.ts b/x-pack/plugins/canvas/storybook/constants.ts index 711b939179452..4f0ad2a602da0 100644 --- a/x-pack/plugins/canvas/storybook/constants.ts +++ b/x-pack/plugins/canvas/storybook/constants.ts @@ -8,3 +8,34 @@ import path from 'path'; export const KIBANA_ROOT = path.resolve(__dirname, '../../../..'); + +export const argTypes = { + hasTemplates: { + name: 'Has templates?', + type: { + name: 'boolean', + }, + defaultValue: true, + control: { + type: 'boolean', + }, + }, + useStaticData: { + name: 'Use static data?', + type: { + name: 'boolean', + }, + defaultValue: false, + control: { + type: 'boolean', + }, + }, + workpadCount: { + name: 'Number of workpads', + type: { name: 'number' }, + defaultValue: 5, + control: { + type: 'range', + }, + }, +}; diff --git a/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx b/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx index b5bb0710c3de2..c99f5df184cd4 100644 --- a/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx +++ b/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx @@ -10,19 +10,10 @@ import React from 'react'; import { DecoratorFn } from '@storybook/react'; import { I18nProvider } from '@kbn/i18n-react'; -import { PluginServiceRegistry } from '@kbn/presentation-util-plugin/public'; -import { pluginServices, CanvasPluginServices } from '../../public/services'; -import { pluginServiceProviders, StorybookParams } from '../../public/services/storybook'; import { LegacyServicesProvider } from '../../public/services/legacy'; -import { startServices } from '../../public/services/legacy/stubs'; +import { setStubKibanaServices } from '../../public/services/mocks'; export const servicesContextDecorator = (): DecoratorFn => { - const pluginServiceRegistry = new PluginServiceRegistry( - pluginServiceProviders - ); - - pluginServices.setRegistry(pluginServiceRegistry.start({})); - return (story: Function, storybook) => { if (process.env.JEST_WORKER_ID !== undefined) { storybook.args.useStaticData = true; @@ -33,6 +24,7 @@ export const servicesContextDecorator = (): DecoratorFn => { }; export const legacyContextDecorator = () => { - startServices(); + setStubKibanaServices(); + return (story: Function) => {story()}; }; diff --git a/x-pack/plugins/canvas/tsconfig.json b/x-pack/plugins/canvas/tsconfig.json index 85121b72c868c..251deca87c4ee 100644 --- a/x-pack/plugins/canvas/tsconfig.json +++ b/x-pack/plugins/canvas/tsconfig.json @@ -12,6 +12,7 @@ "allowJs": false }, "include": [ + "*.ts", "../../../typings/**/*", "__fixtures__/**/*", "canvas_plugin_src/**/*", @@ -88,9 +89,7 @@ "@kbn/presentation-containers", "@kbn/presentation-publishing", "@kbn/react-kibana-context-render", - "@kbn/search-types", + "@kbn/search-types" ], - "exclude": [ - "target/**/*", - ] + "exclude": ["target/**/*"] }