Skip to content

Commit

Permalink
[Maps] Add telemetry usage tracking for feature edit tools (#108802)
Browse files Browse the repository at this point in the history
* Telemetry usage collection added to maps. Tracking added for feature edit tools

* Swap absolute vs. relative imports

* Review feedback. Pass react component through renderApp function

Co-authored-by: Alejandro Fernández Haro <[email protected]>
  • Loading branch information
Aaron Caldwell and afharo authored Aug 17, 2021
1 parent b607f42 commit d838d76
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 137 deletions.
21 changes: 17 additions & 4 deletions x-pack/plugins/maps/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,27 @@
"dashboard",
"embeddable",
"mapsEms",
"usageCollection",
"savedObjects",
"share",
"presentationUtil"
],
"optionalPlugins": ["home", "savedObjectsTagging", "charts", "security"],
"optionalPlugins": [
"home",
"savedObjectsTagging",
"charts",
"security",
"usageCollection"
],
"ui": true,
"server": true,
"extraPublicDirs": ["common/constants"],
"requiredBundles": ["kibanaReact", "kibanaUtils", "home", "mapsEms"]
"extraPublicDirs": [
"common/constants"
],
"requiredBundles": [
"kibanaReact",
"kibanaUtils",
"usageCollection",
"home",
"mapsEms"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import React from 'react';
import { EuiButtonIcon, EuiPanel } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { TrackApplicationView } from '../../../../../../../../src/plugins/usage_collection/public';
import { DRAW_SHAPE } from '../../../../../common/constants';
import { VectorCircleIcon } from '../../icons/vector_circle_icon';
import { VectorLineIcon } from '../../icons/vector_line_icon';
Expand Down Expand Up @@ -36,108 +37,110 @@ export function FeatureEditTools(props: Props) {
const deleteSelected = props.drawShape === DRAW_SHAPE.DELETE;

return (
<EuiPanel
paddingSize="none"
className="mapToolbarOverlay__buttonGroup mapToolbarOverlay__buttonGroupAnimated"
>
{props.pointsOnly ? null : (
<>
<EuiButtonIcon
key="line"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.LINE)}
iconType={VectorLineIcon}
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawLineLabel', {
defaultMessage: 'Draw line',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawLineTitle', {
defaultMessage: 'Draw line',
})}
aria-pressed={drawLineSelected}
isSelected={drawLineSelected}
display={drawLineSelected ? 'fill' : 'empty'}
/>
<TrackApplicationView viewId="featureEditTools">
<EuiPanel
paddingSize="none"
className="mapToolbarOverlay__buttonGroup mapToolbarOverlay__buttonGroupAnimated"
>
{props.pointsOnly ? null : (
<>
<EuiButtonIcon
key="line"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.LINE)}
iconType={VectorLineIcon}
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawLineLabel', {
defaultMessage: 'Draw line',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawLineTitle', {
defaultMessage: 'Draw line',
})}
aria-pressed={drawLineSelected}
isSelected={drawLineSelected}
display={drawLineSelected ? 'fill' : 'empty'}
/>

<EuiButtonIcon
key="polygon"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.POLYGON)}
iconType="node"
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawPolygonLabel', {
defaultMessage: 'Draw polygon',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawPolygonTitle', {
defaultMessage: 'Draw polygon',
})}
aria-pressed={drawPolygonSelected}
isSelected={drawPolygonSelected}
display={drawPolygonSelected ? 'fill' : 'empty'}
/>
<EuiButtonIcon
key="circle"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.DISTANCE)}
iconType={VectorCircleIcon}
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawCircleLabel', {
defaultMessage: 'Draw circle',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawCircleTitle', {
defaultMessage: 'Draw circle',
})}
aria-pressed={drawCircleSelected}
isSelected={drawCircleSelected}
display={drawCircleSelected ? 'fill' : 'empty'}
/>
<EuiButtonIcon
key="boundingBox"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.BOUNDS)}
iconType={VectorSquareIcon}
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawBBoxLabel', {
defaultMessage: 'Draw bounding box',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawBBoxTitle', {
defaultMessage: 'Draw bounding box',
})}
aria-pressed={drawBBoxSelected}
isSelected={drawBBoxSelected}
display={drawBBoxSelected ? 'fill' : 'empty'}
/>
</>
)}
<EuiButtonIcon
key="point"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.POINT)}
iconType="dot"
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawPointLabel', {
defaultMessage: 'Draw point',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawPointTitle', {
defaultMessage: 'Draw point',
})}
aria-pressed={drawPointSelected}
isSelected={drawPointSelected}
display={drawPointSelected ? 'fill' : 'empty'}
/>
<EuiButtonIcon
key="delete"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.DELETE)}
iconType="trash"
aria-label={i18n.translate(
'xpack.maps.toolbarOverlay.featureDraw.deletePointOrShapeLabel',
{
defaultMessage: 'Delete point or shape',
}
<EuiButtonIcon
key="polygon"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.POLYGON)}
iconType="node"
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawPolygonLabel', {
defaultMessage: 'Draw polygon',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawPolygonTitle', {
defaultMessage: 'Draw polygon',
})}
aria-pressed={drawPolygonSelected}
isSelected={drawPolygonSelected}
display={drawPolygonSelected ? 'fill' : 'empty'}
/>
<EuiButtonIcon
key="circle"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.DISTANCE)}
iconType={VectorCircleIcon}
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawCircleLabel', {
defaultMessage: 'Draw circle',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawCircleTitle', {
defaultMessage: 'Draw circle',
})}
aria-pressed={drawCircleSelected}
isSelected={drawCircleSelected}
display={drawCircleSelected ? 'fill' : 'empty'}
/>
<EuiButtonIcon
key="boundingBox"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.BOUNDS)}
iconType={VectorSquareIcon}
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawBBoxLabel', {
defaultMessage: 'Draw bounding box',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawBBoxTitle', {
defaultMessage: 'Draw bounding box',
})}
aria-pressed={drawBBoxSelected}
isSelected={drawBBoxSelected}
display={drawBBoxSelected ? 'fill' : 'empty'}
/>
</>
)}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.deletePointOrShapeTitle', {
defaultMessage: 'Delete point or shape',
})}
aria-pressed={deleteSelected}
isSelected={deleteSelected}
display={deleteSelected ? 'fill' : 'empty'}
/>
</EuiPanel>
<EuiButtonIcon
key="point"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.POINT)}
iconType="dot"
aria-label={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawPointLabel', {
defaultMessage: 'Draw point',
})}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.drawPointTitle', {
defaultMessage: 'Draw point',
})}
aria-pressed={drawPointSelected}
isSelected={drawPointSelected}
display={drawPointSelected ? 'fill' : 'empty'}
/>
<EuiButtonIcon
key="delete"
size="s"
onClick={() => props.setDrawShape(DRAW_SHAPE.DELETE)}
iconType="trash"
aria-label={i18n.translate(
'xpack.maps.toolbarOverlay.featureDraw.deletePointOrShapeLabel',
{
defaultMessage: 'Delete point or shape',
}
)}
title={i18n.translate('xpack.maps.toolbarOverlay.featureDraw.deletePointOrShapeTitle', {
defaultMessage: 'Delete point or shape',
})}
aria-pressed={deleteSelected}
isSelected={deleteSelected}
display={deleteSelected ? 'fill' : 'empty'}
/>
</EuiPanel>
</TrackApplicationView>
);
}
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/public/lazy_load_bundle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface LazyLoadedMapModules {
) => Embeddable<MapEmbeddableInput, MapEmbeddableOutput>;
getIndexPatternService: () => IndexPatternsContract;
getMapsCapabilities: () => any;
renderApp: (params: AppMountParameters) => Promise<() => void>;
renderApp: (params: AppMountParameters, AppUsageTracker: React.FC) => Promise<() => void>;
createSecurityLayerDescriptors: (
indexPatternId: string,
indexPatternTitle: string
Expand Down
7 changes: 6 additions & 1 deletion x-pack/plugins/maps/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
* 2.0.
*/

import React from 'react';
import type { Setup as InspectorSetupContract } from 'src/plugins/inspector/public';
import type { UiActionsStart } from 'src/plugins/ui_actions/public';
import type { NavigationPublicPluginStart } from 'src/plugins/navigation/public';
import type { Start as InspectorStartContract } from 'src/plugins/inspector/public';
import type { DashboardStart } from 'src/plugins/dashboard/public';
import type { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
import type {
AppMountParameters,
CoreSetup,
Expand Down Expand Up @@ -81,6 +83,7 @@ export interface MapsPluginSetupDependencies {
mapsEms: MapsEmsPluginSetup;
share: SharePluginSetup;
licensing: LicensingPluginSetup;
usageCollection?: UsageCollectionSetup;
}

export interface MapsPluginStartDependencies {
Expand Down Expand Up @@ -168,8 +171,10 @@ export class MapsPlugin
euiIconType: APP_ICON_SOLUTION,
category: DEFAULT_APP_CATEGORIES.kibana,
async mount(params: AppMountParameters) {
const UsageTracker =
plugins.usageCollection?.components.ApplicationUsageTrackingProvider ?? React.Fragment;
const { renderApp } = await lazyLoadMapModules();
return renderApp(params);
return renderApp(params, UsageTracker);
},
});
}
Expand Down
59 changes: 29 additions & 30 deletions x-pack/plugins/maps/public/render_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* 2.0.
*/

import _ from 'lodash';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { Router, Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom';
Expand Down Expand Up @@ -62,12 +61,10 @@ function setAppChrome() {
});
}

export async function renderApp({
element,
history,
onAppLeave,
setHeaderActionMenu,
}: AppMountParameters) {
export async function renderApp(
{ element, history, onAppLeave, setHeaderActionMenu }: AppMountParameters,
AppUsageTracker: React.FC
) {
goToSpecifiedPath = (path) => history.push(path);
kbnUrlStateStorage = createKbnUrlStateStorage({
useHash: false,
Expand Down Expand Up @@ -107,29 +104,31 @@ export async function renderApp({

const I18nContext = getCoreI18n().Context;
render(
<I18nContext>
<Router history={history}>
<Switch>
<Route path={`/map/:savedMapId`} render={renderMapApp} />
<Route exact path={`/map`} render={renderMapApp} />
// Redirect other routes to list, or if hash-containing, their non-hash equivalents
<Route
path={``}
render={({ location: { pathname, hash } }) => {
if (hash) {
// Remove leading hash
const newPath = hash.substr(1);
return <Redirect to={newPath} />;
} else if (pathname === '/' || pathname === '') {
return <ListPage stateTransfer={stateTransfer} />;
} else {
return <Redirect to="/" />;
}
}}
/>
</Switch>
</Router>
</I18nContext>,
<AppUsageTracker>
<I18nContext>
<Router history={history}>
<Switch>
<Route path={`/map/:savedMapId`} render={renderMapApp} />
<Route exact path={`/map`} render={renderMapApp} />
// Redirect other routes to list, or if hash-containing, their non-hash equivalents
<Route
path={``}
render={({ location: { pathname, hash } }) => {
if (hash) {
// Remove leading hash
const newPath = hash.substr(1);
return <Redirect to={newPath} />;
} else if (pathname === '/' || pathname === '') {
return <ListPage stateTransfer={stateTransfer} />;
} else {
return <Redirect to="/" />;
}
}}
/>
</Switch>
</Router>
</I18nContext>
</AppUsageTracker>,
element
);

Expand Down

0 comments on commit d838d76

Please sign in to comment.