Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [CANVAS] Moves notify to a canvas service (#63268) #64666

Merged
merged 2 commits into from
Apr 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion x-pack/legacy/plugins/canvas/public/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import { ACTION_VALUE_CLICK } from '../../../../../src/plugins/data/public/actio
import { init as initStatsReporter } from './lib/ui_metric';

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

import { startServices, stopServices, services } from './services';

const { ReadOnlyBadge: strings } = CapabilitiesStrings;

let restoreAction: ActionByType<any> | undefined;
Expand All @@ -51,8 +54,14 @@ export const renderApp = (
{ element }: AppMountParameters,
canvasStore: Store
) => {
const canvasServices = Object.entries(services).reduce((reduction, [key, provider]) => {
reduction[key] = provider.getService();

return reduction;
}, {} as Record<string, any>);

ReactDOM.render(
<KibanaContextProvider services={{ ...plugins, ...coreStart }}>
<KibanaContextProvider services={{ ...plugins, ...coreStart, canvas: canvasServices }}>
<I18nProvider>
<Provider store={canvasStore}>
<App />
Expand All @@ -71,6 +80,8 @@ export const initializeCanvas = async (
startPlugins: CanvasStartDeps,
registries: SetupRegistries
) => {
startServices(coreSetup, coreStart, setupPlugins, startPlugins);

// Create Store
const canvasStore = await createStore(coreSetup, setupPlugins);

Expand Down Expand Up @@ -130,6 +141,7 @@ export const initializeCanvas = async (
};

export const teardownCanvas = (coreStart: CoreStart, startPlugins: CanvasStartDeps) => {
stopServices();
destroyRegistries();
resetInterpreter();

Expand Down
10 changes: 7 additions & 3 deletions x-pack/legacy/plugins/canvas/public/apps/workpad/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { ErrorStrings } from '../../../i18n';
import * as workpadService from '../../lib/workpad_service';
import { notify } from '../../lib/notify';
import { notifyService } from '../../services';
import { getBaseBreadcrumb, getWorkpadBreadcrumb, setBreadcrumb } from '../../lib/breadcrumbs';
import { getDefaultWorkpad } from '../../state/defaults';
import { setWorkpad } from '../../state/actions/workpad';
Expand All @@ -33,7 +33,9 @@ export const routes = [
dispatch(resetAssets());
router.redirectTo('loadWorkpad', { id: newWorkpad.id, page: 1 });
} catch (err) {
notify.error(err, { title: strings.getCreateFailureErrorMessage() });
notifyService
.getService()
.error(err, { title: strings.getCreateFailureErrorMessage() });
router.redirectTo('home');
}
},
Expand All @@ -59,7 +61,9 @@ export const routes = [
// reset transient properties when changing workpads
dispatch(setZoomScale(1));
} catch (err) {
notify.error(err, { title: strings.getLoadFailureErrorMessage() });
notifyService
.getService()
.error(err, { title: strings.getLoadFailureErrorMessage() });
return router.redirectTo('home');
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { AssetModal } from './asset_modal';

const { AssetManager: strings } = ComponentStrings;

interface Props {
export interface Props {
/** A list of assets, if available */
assetValues: AssetType[];
/** Function to invoke when an asset is selected to be added as an element to the workpad */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,36 @@ import { connect } from 'react-redux';
import { compose, withProps } from 'recompose';
import { set, get } from 'lodash';
import { fromExpression, toExpression } from '@kbn/interpreter/common';
import { notify } from '../../lib/notify';
import { getAssets } from '../../state/selectors/assets';
// @ts-ignore Untyped local
import { removeAsset, createAsset } from '../../state/actions/assets';
// @ts-ignore Untyped local
import { elementsRegistry } from '../../lib/elements_registry';
// @ts-ignore Untyped local
import { addElement } from '../../state/actions/elements';
import { getSelectedPage } from '../../state/selectors/workpad';
import { encode } from '../../../common/lib/dataurl';
import { getId } from '../../lib/get_id';
// @ts-ignore Untyped Local
import { findExistingAsset } from '../../lib/find_existing_asset';
import { VALID_IMAGE_TYPES } from '../../../common/lib/constants';
import { AssetManager as Component } from './asset_manager';
import { withKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { WithKibanaProps } from '../../';
import { AssetManager as Component, Props as AssetManagerProps } from './asset_manager';

const mapStateToProps = state => ({
import { State, ExpressionAstExpression, AssetType } from '../../../types';

const mapStateToProps = (state: State) => ({
assets: getAssets(state),
selectedPage: getSelectedPage(state),
});

const mapDispatchToProps = dispatch => ({
onAddImageElement: pageId => assetId => {
const mapDispatchToProps = (dispatch: (action: any) => void) => ({
onAddImageElement: (pageId: string) => (assetId: string) => {
const imageElement = elementsRegistry.get('image');
const elementAST = fromExpression(imageElement.expression);
const selector = ['chain', '0', 'arguments', 'dataurl'];
const subExp = [
const subExp: ExpressionAstExpression[] = [
{
type: 'expression',
chain: [
Expand All @@ -44,22 +51,26 @@ const mapDispatchToProps = dispatch => ({
],
},
];
const newAST = set(elementAST, selector, subExp);
const newAST = set<ExpressionAstExpression>(elementAST, selector, subExp);
imageElement.expression = toExpression(newAST);
dispatch(addElement(pageId, imageElement));
},
onAssetAdd: (type, content) => {
onAssetAdd: (type: string, content: string) => {
// make the ID here and pass it into the action
const assetId = getId('asset');
dispatch(createAsset(type, content, assetId));

// then return the id, so the caller knows the id that will be created
return assetId;
},
onAssetDelete: assetId => dispatch(removeAsset(assetId)),
onAssetDelete: (assetId: string) => dispatch(removeAsset(assetId)),
});

const mergeProps = (stateProps, dispatchProps, ownProps) => {
const mergeProps = (
stateProps: ReturnType<typeof mapStateToProps>,
dispatchProps: ReturnType<typeof mapDispatchToProps>,
ownProps: AssetManagerProps
) => {
const { assets, selectedPage } = stateProps;
const { onAssetAdd } = dispatchProps;
const assetValues = Object.values(assets); // pull values out of assets object
Expand All @@ -70,16 +81,16 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
onAddImageElement: dispatchProps.onAddImageElement(stateProps.selectedPage),
selectedPage,
assetValues,
onAssetAdd: file => {
onAssetAdd: (file: File) => {
const [type, subtype] = get(file, 'type', '').split('/');
if (type === 'image' && VALID_IMAGE_TYPES.indexOf(subtype) >= 0) {
return encode(file).then(dataurl => {
const type = 'dataurl';
const existingId = findExistingAsset(type, dataurl, assetValues);
const dataurlType = 'dataurl';
const existingId = findExistingAsset(dataurlType, dataurl, assetValues);
if (existingId) {
return existingId;
}
return onAssetAdd(type, dataurl);
return onAssetAdd(dataurlType, dataurl);
});
}

Expand All @@ -88,7 +99,11 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
};
};

export const AssetManager = compose(
export const AssetManager = compose<any, any>(
connect(mapStateToProps, mapDispatchToProps, mergeProps),
withProps({ onAssetCopy: asset => notify.success(`Copied '${asset.id}' to clipboard`) })
withKibana,
withProps(({ kibana }: WithKibanaProps) => ({
onAssetCopy: (asset: AssetType) =>
kibana.services.canvas.notify.success(`Copied '${asset.id}' to clipboard`),
}))
)(Component);
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { compose, withProps, withPropsOnChange } from 'recompose';
import PropTypes from 'prop-types';
import isEqual from 'react-fast-compare';
import { notify } from '../../lib/notify';
import { withKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { RenderWithFn as Component } from './render_with_fn';
import { ElementHandlers } from './lib/handlers';

Expand All @@ -19,9 +19,10 @@ export const RenderWithFn = compose(
handlers: Object.assign(new ElementHandlers(), handlers),
})
),
withProps({
onError: notify.error,
})
withKibana,
withProps(props => ({
onError: props.kibana.services.canvas.notify.error,
}))
)(Component);

RenderWithFn.propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { camelCase } from 'lodash';
// @ts-ignore Untyped local
import { cloneSubgraphs } from '../../lib/clone_subgraphs';
import * as customElementService from '../../lib/custom_element_service';
// @ts-ignore Untyped local
import { notify } from '../../lib/notify';
import { withKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { WithKibanaProps } from '../../';
// @ts-ignore Untyped local
import { selectToplevelNodes } from '../../state/actions/transient';
// @ts-ignore Untyped local
Expand Down Expand Up @@ -64,7 +64,7 @@ const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
const mergeProps = (
stateProps: StateProps,
dispatchProps: DispatchProps,
ownProps: OwnPropsWithState
ownProps: OwnPropsWithState & WithKibanaProps
): ComponentProps => {
const { pageId } = stateProps;
const { onClose, search, setCustomElements } = ownProps;
Expand Down Expand Up @@ -92,7 +92,9 @@ const mergeProps = (
try {
await findCustomElements();
} catch (err) {
notify.error(err, { title: `Couldn't find custom elements` });
ownProps.kibana.services.canvas.notify.error(err, {
title: `Couldn't find custom elements`,
});
}
},
// remove custom element
Expand All @@ -101,7 +103,9 @@ const mergeProps = (
await customElementService.remove(id);
await findCustomElements();
} catch (err) {
notify.error(err, { title: `Couldn't delete custom elements` });
ownProps.kibana.services.canvas.notify.error(err, {
title: `Couldn't delete custom elements`,
});
}
},
// update custom element
Expand All @@ -115,13 +119,16 @@ const mergeProps = (
});
await findCustomElements();
} catch (err) {
notify.error(err, { title: `Couldn't update custom elements` });
ownProps.kibana.services.canvas.notify.error(err, {
title: `Couldn't update custom elements`,
});
}
},
};
};

export const SavedElementsModal = compose<ComponentProps, OwnProps>(
withKibana,
withState('search', 'setSearch', ''),
withState('customElements', 'setCustomElements', []),
connect(mapStateToProps, mapDispatchToProps, mergeProps)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
getRenderedWorkpadExpressions,
} from '../../../../state/selectors/workpad';
// @ts-ignore Untyped local
import { notify } from '../../../../lib/notify';
import {
downloadRenderedWorkpad,
downloadRuntime,
Expand Down Expand Up @@ -70,7 +69,7 @@ export const ShareWebsiteFlyout = compose<ComponentProps, Pick<Props, 'onClose'>
unsupportedRenderers,
onClose,
onCopy: () => {
notify.info(strings.getCopyShareConfigMessage());
kibana.services.canvas.notify.info(strings.getCopyShareConfigMessage());
},
onDownload: type => {
switch (type) {
Expand All @@ -86,7 +85,9 @@ export const ShareWebsiteFlyout = compose<ComponentProps, Pick<Props, 'onClose'>
.post(`${basePath}${API_ROUTE_SHAREABLE_ZIP}`, JSON.stringify(renderedWorkpad))
.then(blob => downloadZippedRuntime(blob.data))
.catch((err: Error) => {
notify.error(err, { title: strings.getShareableZipErrorTitle(workpad.name) });
kibana.services.canvas.notify.error(err, {
title: strings.getShareableZipErrorTitle(workpad.name),
});
});
return;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { connect } from 'react-redux';
import { compose, withProps } from 'recompose';
import { jobCompletionNotifications } from '../../../../../../../plugins/reporting/public';
import { getWorkpad, getPages } from '../../../state/selectors/workpad';
// @ts-ignore Untyped local
import { notify } from '../../../lib/notify';
import { getWindow } from '../../../lib/get_window';
import { downloadWorkpad } from '../../../lib/download_workpad';
import { ShareMenu as Component, Props as ComponentProps } from './share_menu';
Expand Down Expand Up @@ -59,10 +57,10 @@ export const ShareMenu = compose<ComponentProps, {}>(
onCopy: type => {
switch (type) {
case 'pdf':
notify.info(strings.getCopyPDFMessage());
kibana.services.canvas.notify.info(strings.getCopyPDFMessage());
break;
case 'reportingConfig':
notify.info(strings.getCopyReportingConfigMessage());
kibana.services.canvas.notify.info(strings.getCopyReportingConfigMessage());
break;
default:
throw new Error(strings.getUnknownExportErrorMessage(type));
Expand All @@ -73,15 +71,17 @@ export const ShareMenu = compose<ComponentProps, {}>(
case 'pdf':
return createPdf(workpad, { pageCount }, kibana.services.http.basePath)
.then(({ data }: { data: { job: { id: string } } }) => {
notify.info(strings.getExportPDFMessage(), {
kibana.services.canvas.notify.info(strings.getExportPDFMessage(), {
title: strings.getExportPDFTitle(workpad.name),
});

// register the job so a completion notification shows up when it's ready
jobCompletionNotifications.add(data.job.id);
})
.catch((err: Error) => {
notify.error(err, { title: strings.getExportPDFErrorTitle(workpad.name) });
kibana.services.canvas.notify.error(err, {
title: strings.getExportPDFErrorTitle(workpad.name),
});
});
case 'json':
downloadWorkpad(workpad.id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import { compose, withHandlers } from 'recompose';
import { Dispatch } from 'redux';
import { withKibana } from '../../../../../../../../src/plugins/kibana_react/public/';
import { zoomHandlerCreators } from '../../../lib/app_handler_creators';
// @ts-ignore Untyped local
import { notify } from '../../../lib/notify';
import { State, CanvasWorkpadBoundingBox } from '../../../../types';
// @ts-ignore Untyped local
import { fetchAllRenderables } from '../../../state/actions/elements';
Expand Down
Loading