kibana/x-pack/plugins/lens/public/app_plugin/mounter.tsx

238 lines
8.1 KiB
TypeScript
Raw Normal View History

2020-05-01 12:57:29 +02:00
/*
* 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.
2020-05-01 12:57:29 +02:00
*/
import React, { FC, useCallback } from 'react';
2020-05-01 12:57:29 +02:00
import { AppMountParameters, CoreSetup } from 'kibana/public';
import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
import { HashRouter, Route, RouteComponentProps, Switch } from 'react-router-dom';
import { History } from 'history';
2020-05-01 12:57:29 +02:00
import { render, unmountComponentAtNode } from 'react-dom';
import { i18n } from '@kbn/i18n';
import { DashboardFeatureFlagConfig } from 'src/plugins/dashboard/public';
import { Storage } from '../../../../../src/plugins/kibana_utils/public';
2020-05-01 12:57:29 +02:00
import { LensReportManager, setReportManager, trackUiEvent } from '../lens_ui_telemetry';
import { App } from './app';
import { EditorFrameStart } from '../types';
import { addHelpMenuToAppChrome } from '../help_menu_util';
import { LensPluginStartDependencies } from '../plugin';
import { LENS_EMBEDDABLE_TYPE, LENS_EDIT_BY_VALUE, APP_ID } from '../../common';
import {
LensEmbeddableInput,
LensByReferenceInput,
LensByValueInput,
} from '../editor_frame_service/embeddable/embeddable';
import { ACTION_VISUALIZE_LENS_FIELD } from '../../../../../src/plugins/ui_actions/public';
import { LensAttributeService } from '../lens_attribute_service';
import { LensAppServices, RedirectToOriginProps, HistoryLocationState } from './types';
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
2020-05-01 12:57:29 +02:00
export async function mountApp(
core: CoreSetup<LensPluginStartDependencies, void>,
params: AppMountParameters,
mountProps: {
createEditorFrame: EditorFrameStart['createInstance'];
getByValueFeatureFlag: () => Promise<DashboardFeatureFlagConfig>;
attributeService: () => Promise<LensAttributeService>;
getPresentationUtilContext: () => Promise<FC>;
}
2020-05-01 12:57:29 +02:00
) {
const {
createEditorFrame,
getByValueFeatureFlag,
attributeService,
getPresentationUtilContext,
} = mountProps;
2020-05-01 12:57:29 +02:00
const [coreStart, startDependencies] = await core.getStartServices();
SavedObjects tagging MVP (#79096) * create xpack plugin skeleton, start to implement management section * add tag creation modal * first implementation of the tags table * use InMemoryTable * add edit modal and delete action * update plugin list * add tag list, fix types * add capabilities check on client-side * add tag combo box component * add missing i18n keys * fix privilege FTR tests * add base structure for FTR tests * fix feature ftr test * use string literals for i18n * create savedObjectsTaggingOss plugin, move API types to oss plugin, start to wire to SO management page. * update plugin list * fix types * allow to use `_find` with multiple references * add FTR test for _find API on references fields * add _find integration tests * update generated doc * start to implement tag filtering on SO management section * update generated docs * wire tagging API to dashboard listing page * fix i18n namespace * fix type & tests * update dashboard listing snapshots * adapt FTR listingTable service to search for parsable queries * wite tagging API to visualize listing * update tagging plugin limits * add server-side and client-side validation for tag create/edit * rename title field to name * fix types * fix types bis * add removeReferencesTo API to SOR/SOC * update generated doc * add server-side unit test for `savedObjectsTagging` plugin * move tagging API types to its own file * add savedObjectsTaggingOss mock * add tags_cache tests * add tests for client-side tag client * extract uiApi to distinct files * various API improvements * add more tests * add link between tag and so management sections + add connection counts * add base functional test suite for tagging * add more FTR tests * improve feature control func test * update codeowners * update generated doc * fix access to proxy modal * adapt SO save modal to allow to add tag field * add SO decorator registry and tag implementation * add unit tests for SO tag decorator * add functional tests for visualize integration * add tag SO read permission for vis/dash feature * add RBAC api integ tests * add API integration tests * add test for getTagConnectionsUrl * add SOM test suite * add dashboard integration suite * remove test line * add missing unit tests * improve API types doc * fix create modal save button label * remove console.log * improve doc * self review * add refresh interval for tag cache * improve page object doc * minor cleanup * address review comments * small layout fixes * add initial focus * use lazy accessor for tag request handler context * adapt SOM export and export route to handle references * remove icon from feature config due to master changes * fix SO table tests * update generated docs * sort tags by name in filter dropdown and listing component * wire SO tagging to dashboard save modal * fix types * - add 'create tag' action in tag selector - add notifications on update/create/delete from management - delete modal wording * add description max length validation * remove real-time validation * fix i18n bundle id * update expected size of savedObjectsTagging plugin * use own useIfMounted * update limit again, contract components cannot be lazy loaded atm. * math is hard * remove single usage of lodash for bundle size * add async imports for create/edit modal * add FTR test for 'create tag' action from tag selector * allow 'create new' option to prepopulate name field * extract savedObjectToTag * add advancedSettings read user for security api_integ suite * add audit login for security client wrapper * use import type when possible * wire SO tagging to lens visualization * fix lens jest test * Fix `create tag` option being selected when closing the selector dropdown * add sorting to tag column from getTableColumnDef * address some of restrry comments * rename tag selector's setSelected option to onTagsSelected * fix audit logging even type for saved_object_remove_references * update plugin size limit to current size * adapt maxlength validation wording * remove selection column until we have batch action menu * remove connections link when user lack read privilege to savedObjectManagement * forbid registering multiple SO decorators with the same priority * add so decorator test * extract getTagFindReferences and create API mock * update audit-logging ascidoc * doc nit * throw conflict error if update returns any failure * use refresh=true as default * wording nits * export: rename `references` to `hasReference` * update generated doc * set description max length to 100 * do not initialize tag cache on anonymous pages * split fetchObjectsToExport into two distinct functions * change tag client `delete` call order * tsdoc nits * more nits * add README for oss plugin * add oss plugin start tests * SavedObject.find: rename `references` to `hasReference` * change section description label * remove url prefix constants * last nits and comments * update generated doc
2020-11-03 10:33:18 +01:00
const { data, navigation, embeddable, savedObjectsTagging } = startDependencies;
const instance = await createEditorFrame();
const storage = new Storage(localStorage);
const stateTransfer = embeddable?.getStateTransfer();
const historyLocationState = params.history.location.state as HistoryLocationState;
const embeddableEditorIncomingState = stateTransfer?.getIncomingEditorState(APP_ID);
const lensServices: LensAppServices = {
data,
storage,
navigation,
stateTransfer,
SavedObjects tagging MVP (#79096) * create xpack plugin skeleton, start to implement management section * add tag creation modal * first implementation of the tags table * use InMemoryTable * add edit modal and delete action * update plugin list * add tag list, fix types * add capabilities check on client-side * add tag combo box component * add missing i18n keys * fix privilege FTR tests * add base structure for FTR tests * fix feature ftr test * use string literals for i18n * create savedObjectsTaggingOss plugin, move API types to oss plugin, start to wire to SO management page. * update plugin list * fix types * allow to use `_find` with multiple references * add FTR test for _find API on references fields * add _find integration tests * update generated doc * start to implement tag filtering on SO management section * update generated docs * wire tagging API to dashboard listing page * fix i18n namespace * fix type & tests * update dashboard listing snapshots * adapt FTR listingTable service to search for parsable queries * wite tagging API to visualize listing * update tagging plugin limits * add server-side and client-side validation for tag create/edit * rename title field to name * fix types * fix types bis * add removeReferencesTo API to SOR/SOC * update generated doc * add server-side unit test for `savedObjectsTagging` plugin * move tagging API types to its own file * add savedObjectsTaggingOss mock * add tags_cache tests * add tests for client-side tag client * extract uiApi to distinct files * various API improvements * add more tests * add link between tag and so management sections + add connection counts * add base functional test suite for tagging * add more FTR tests * improve feature control func test * update codeowners * update generated doc * fix access to proxy modal * adapt SO save modal to allow to add tag field * add SO decorator registry and tag implementation * add unit tests for SO tag decorator * add functional tests for visualize integration * add tag SO read permission for vis/dash feature * add RBAC api integ tests * add API integration tests * add test for getTagConnectionsUrl * add SOM test suite * add dashboard integration suite * remove test line * add missing unit tests * improve API types doc * fix create modal save button label * remove console.log * improve doc * self review * add refresh interval for tag cache * improve page object doc * minor cleanup * address review comments * small layout fixes * add initial focus * use lazy accessor for tag request handler context * adapt SOM export and export route to handle references * remove icon from feature config due to master changes * fix SO table tests * update generated docs * sort tags by name in filter dropdown and listing component * wire SO tagging to dashboard save modal * fix types * - add 'create tag' action in tag selector - add notifications on update/create/delete from management - delete modal wording * add description max length validation * remove real-time validation * fix i18n bundle id * update expected size of savedObjectsTagging plugin * use own useIfMounted * update limit again, contract components cannot be lazy loaded atm. * math is hard * remove single usage of lodash for bundle size * add async imports for create/edit modal * add FTR test for 'create tag' action from tag selector * allow 'create new' option to prepopulate name field * extract savedObjectToTag * add advancedSettings read user for security api_integ suite * add audit login for security client wrapper * use import type when possible * wire SO tagging to lens visualization * fix lens jest test * Fix `create tag` option being selected when closing the selector dropdown * add sorting to tag column from getTableColumnDef * address some of restrry comments * rename tag selector's setSelected option to onTagsSelected * fix audit logging even type for saved_object_remove_references * update plugin size limit to current size * adapt maxlength validation wording * remove selection column until we have batch action menu * remove connections link when user lack read privilege to savedObjectManagement * forbid registering multiple SO decorators with the same priority * add so decorator test * extract getTagFindReferences and create API mock * update audit-logging ascidoc * doc nit * throw conflict error if update returns any failure * use refresh=true as default * wording nits * export: rename `references` to `hasReference` * update generated doc * set description max length to 100 * do not initialize tag cache on anonymous pages * split fetchObjectsToExport into two distinct functions * change tag client `delete` call order * tsdoc nits * more nits * add README for oss plugin * add oss plugin start tests * SavedObject.find: rename `references` to `hasReference` * change section description label * remove url prefix constants * last nits and comments * update generated doc
2020-11-03 10:33:18 +01:00
savedObjectsTagging,
attributeService: await attributeService(),
http: coreStart.http,
chrome: coreStart.chrome,
overlays: coreStart.overlays,
uiSettings: coreStart.uiSettings,
application: coreStart.application,
notifications: coreStart.notifications,
savedObjectsClient: coreStart.savedObjects.client,
getOriginatingAppName: () => {
return embeddableEditorIncomingState?.originatingApp
? stateTransfer?.getAppNameFromId(embeddableEditorIncomingState.originatingApp)
: undefined;
},
2020-05-01 12:57:29 +02:00
// Temporarily required until the 'by value' paradigm is default.
dashboardFeatureFlag: await getByValueFeatureFlag(),
};
addHelpMenuToAppChrome(coreStart.chrome, coreStart.docLinks);
coreStart.chrome.docTitle.change(
i18n.translate('xpack.lens.pageTitle', { defaultMessage: 'Lens' })
);
2020-05-01 12:57:29 +02:00
setReportManager(
new LensReportManager({
http: core.http,
storage,
2020-05-01 12:57:29 +02:00
})
);
const getInitialInput = (id?: string, editByValue?: boolean): LensEmbeddableInput | undefined => {
if (editByValue) {
return embeddableEditorIncomingState?.valueInput as LensByValueInput;
}
if (id) {
return { savedObjectId: id } as LensByReferenceInput;
}
};
const redirectTo = (history: History<unknown>, savedObjectId?: string) => {
if (!savedObjectId) {
history.push({ pathname: '/', search: history.location.search });
} else {
history.push({
pathname: `/edit/${savedObjectId}`,
search: history.location.search,
});
2020-05-01 12:57:29 +02:00
}
};
const redirectToDashboard = (embeddableInput: LensEmbeddableInput, dashboardId: string) => {
if (!lensServices.dashboardFeatureFlag.allowByValueEmbeddables) {
throw new Error('redirectToDashboard called with by-value embeddables disabled');
}
const state = {
input: embeddableInput,
type: LENS_EMBEDDABLE_TYPE,
};
const path = dashboardId === 'new' ? '#/create' : `#/view/${dashboardId}`;
stateTransfer.navigateToWithEmbeddablePackage('dashboards', {
state,
path,
});
};
const redirectToOrigin = (props?: RedirectToOriginProps) => {
if (!embeddableEditorIncomingState?.originatingApp) {
throw new Error('redirectToOrigin called without an originating app');
}
if (stateTransfer && props?.input) {
const { input, isCopied } = props;
stateTransfer.navigateToWithEmbeddablePackage(embeddableEditorIncomingState?.originatingApp, {
state: {
embeddableId: isCopied ? undefined : embeddableEditorIncomingState.embeddableId,
type: LENS_EMBEDDABLE_TYPE,
input,
},
});
} else {
coreStart.application.navigateToApp(embeddableEditorIncomingState?.originatingApp);
}
};
// const featureFlagConfig = await getByValueFeatureFlag();
const EditorRenderer = React.memo(
(props: { id?: string; history: History<unknown>; editByValue?: boolean }) => {
const redirectCallback = useCallback(
(id?: string) => {
redirectTo(props.history, id);
},
[props.history]
);
trackUiEvent('loaded');
return (
<App
incomingState={embeddableEditorIncomingState}
editorFrame={instance}
initialInput={getInitialInput(props.id, props.editByValue)}
redirectTo={redirectCallback}
redirectToOrigin={redirectToOrigin}
redirectToDashboard={redirectToDashboard}
onAppLeave={params.onAppLeave}
setHeaderActionMenu={params.setHeaderActionMenu}
history={props.history}
initialContext={
historyLocationState && historyLocationState.type === ACTION_VISUALIZE_LENS_FIELD
? historyLocationState.payload
: undefined
}
/>
);
}
);
const EditorRoute = (
routeProps: RouteComponentProps<{ id?: string }> & { editByValue?: boolean }
) => {
2020-05-01 12:57:29 +02:00
return (
<EditorRenderer
id={routeProps.match.params.id}
history={routeProps.history}
editByValue={routeProps.editByValue}
2020-05-01 12:57:29 +02:00
/>
);
};
function NotFound() {
trackUiEvent('loaded_404');
return <FormattedMessage id="xpack.lens.app404" defaultMessage="404 Not Found" />;
}
// dispatch synthetic hash change event to update hash history objects
// this is necessary because hash updates triggered by using popState won't trigger this event naturally.
const unlistenParentHistory = params.history.listen(() => {
window.dispatchEvent(new HashChangeEvent('hashchange'));
});
2020-05-01 12:57:29 +02:00
params.element.classList.add('lnsAppWrapper');
const PresentationUtilContext = await getPresentationUtilContext();
2020-05-01 12:57:29 +02:00
render(
<I18nProvider>
<KibanaContextProvider services={lensServices}>
<PresentationUtilContext>
<HashRouter>
<Switch>
<Route exact path="/edit/:id" component={EditorRoute} />
<Route
exact
path={`/${LENS_EDIT_BY_VALUE}`}
render={(routeProps) => <EditorRoute {...routeProps} editByValue />}
/>
<Route exact path="/" component={EditorRoute} />
<Route path="/" component={NotFound} />
</Switch>
</HashRouter>
</PresentationUtilContext>
</KibanaContextProvider>
2020-05-01 12:57:29 +02:00
</I18nProvider>,
params.element
);
return () => {
data.search.session.clear();
2020-05-01 12:57:29 +02:00
instance.unmount();
unmountComponentAtNode(params.element);
unlistenParentHistory();
2020-05-01 12:57:29 +02:00
};
}