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

[CANVAS] Moves notify to a canvas service #63268

Merged
merged 7 commits into from
Apr 24, 2020
Merged
Show file tree
Hide file tree
Changes from 5 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 @@ -32,6 +32,9 @@ import { ACTION_VALUE_CLICK } from '../../../../../src/plugins/data/public/actio
/* eslint-enable */

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

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

const { ReadOnlyBadge: strings } = CapabilitiesStrings;

let restoreAction: ActionByType<any> | undefined;
Expand All @@ -50,8 +53,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 @@ -70,6 +79,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 @@ -125,6 +136,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 @@ -22,7 +22,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>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handy

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>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we get types here?

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 @@ -11,11 +11,11 @@ import { camelCase } from 'lodash';
import { cloneSubgraphs } from '../../lib/clone_subgraphs';
import * as customElementService from '../../lib/custom_element_service';
import { elementsRegistry } from '../../lib/elements_registry';
import { notify } from '../../lib/notify';
import { selectToplevelNodes } from '../../state/actions/transient';
import { insertNodes, addElement } from '../../state/actions/elements';
import { getSelectedPage } from '../../state/selectors/workpad';
import { trackCanvasUiMetric, METRIC_TYPE } from '../../lib/ui_metric';
import { withKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { ElementTypes as Component } from './element_types';

const customElementAdded = 'elements-custom-added';
Expand Down Expand Up @@ -59,7 +59,9 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { customElements } = await customElementService.find(text);
setCustomElements(customElements);
} 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 @@ -69,7 +71,9 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { customElements } = await customElementService.find(search);
setCustomElements(customElements);
} 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 @@ -84,7 +88,9 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { customElements } = await customElementService.find(search);
setCustomElements(customElements);
} catch (err) {
notify.error(err, { title: `Couldn't update custom elements` });
ownProps.kibana.services.canvas.notify.error(err, {
title: `Couldn't update custom elements`,
});
}
},
};
Expand All @@ -95,6 +101,7 @@ export const ElementTypes = compose(
withState('customElements', 'setCustomElements', []),
withState('filterTags', 'setFilterTags', []),
withProps(() => ({ elements: elementsRegistry.toJS() })),
withKibana,
connect(mapStateToProps, mapDispatchToProps, mergeProps)
)(Component);

Expand Down
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 @@ -13,8 +13,6 @@ import {
getRenderedWorkpadExpressions,
} from '../../../../state/selectors/workpad';
// @ts-ignore Untyped local
import { notify } from '../../../../lib/notify';
// @ts-ignore Untyped local
import {
downloadRenderedWorkpad,
downloadRuntime,
Expand Down Expand Up @@ -74,7 +72,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 @@ -90,7 +88,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 @@ -9,8 +9,6 @@ import { compose, withProps } from 'recompose';
import { jobCompletionNotifications } from '../../../../../../../plugins/reporting/public';
// @ts-ignore Untyped local
import { getWorkpad, getPages } from '../../../state/selectors/workpad';
// @ts-ignore Untyped local
import { notify } from '../../../lib/notify';
import { getWindow } from '../../../lib/get_window';
// @ts-ignore Untyped local
import {
Expand Down Expand Up @@ -66,10 +64,10 @@ export const WorkpadExport = 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 @@ -80,15 +78,17 @@ export const WorkpadExport = 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
Loading