Skip to content

Commit

Permalink
[Lens] visualize in maps button (#98677)
Browse files Browse the repository at this point in the history
* [Lens] visualize in maps button

* clean up dependency injection as suggested

* add custom workspace render for geo fields

* tslint and finish drag and drop for geo field

* convert react class to function component

* prevent page reload when clicking visualize in maps button

* filter allFields instead of using condition to populate fieldTypeNames to fix tslint

* clean up UI

* fix jest test

* globe illustration

* UI cleanup

* functional test

* Update x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.tsx

Co-authored-by: Michael Marcialis <[email protected]>

* Update x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.scss

Co-authored-by: Michael Marcialis <[email protected]>

* Update x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.tsx

Co-authored-by: Michael Marcialis <[email protected]>

* Update x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.scss

Co-authored-by: Michael Marcialis <[email protected]>

* Update x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.scss

Co-authored-by: Michael Marcialis <[email protected]>

* Update x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx

Co-authored-by: Michael Marcialis <[email protected]>

* updated globe svg

* remove unused

* better message for drop zone screen reader

* Update x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel.tsx

Co-authored-by: Michael Marcialis <[email protected]>

* tslint

Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Michael Marcialis <[email protected]>
  • Loading branch information
3 people authored May 12, 2021
1 parent 4b22037 commit b097385
Show file tree
Hide file tree
Showing 24 changed files with 403 additions and 30 deletions.
26 changes: 26 additions & 0 deletions x-pack/plugins/lens/public/assets/globe_illustration.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Action } from './state_management';
import { DragContext, DragDropIdentifier } from '../../drag_drop';
import { StateSetter, FramePublicAPI, DatasourceDataPanelProps, Datasource } from '../../types';
import { Query, Filter } from '../../../../../../src/plugins/data/public';
import { UiActionsStart } from '../../../../../../src/plugins/ui_actions/public';

interface DataPanelWrapperProps {
datasourceState: unknown;
Expand All @@ -29,6 +30,7 @@ interface DataPanelWrapperProps {
filters: Filter[];
dropOntoWorkspace: (field: DragDropIdentifier) => void;
hasSuggestionForField: (field: DragDropIdentifier) => boolean;
plugins: { uiActions: UiActionsStart };
}

export const DataPanelWrapper = memo((props: DataPanelWrapperProps) => {
Expand Down Expand Up @@ -56,6 +58,7 @@ export const DataPanelWrapper = memo((props: DataPanelWrapperProps) => {
showNoDataPopover: props.showNoDataPopover,
dropOntoWorkspace: props.dropOntoWorkspace,
hasSuggestionForField: props.hasSuggestionForField,
uiActions: props.plugins.uiActions,
};

const [showDatasourceSwitcher, setDatasourceSwitcher] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ export function EditorFrame(props: EditorFrameProps) {
showNoDataPopover={props.showNoDataPopover}
dropOntoWorkspace={dropOntoWorkspace}
hasSuggestionForField={hasSuggestionForField}
plugins={props.plugins}
/>
}
configPanel={
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@import '../../../mixins';

.lnsVisualizeGeoFieldWorkspacePanel__dragDrop {
padding: $euiSizeXXL ($euiSizeXL * 2);
border: $euiBorderThin;
border-radius: $euiBorderRadius;

&.lnsDragDrop-isDropTarget {
@include lnsDroppable;
@include lnsDroppableActive;

}

&.lnsDragDrop-isActiveDropTarget {
@include lnsDroppableActiveHover;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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 { EuiPageContentBody, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import {
UiActionsStart,
VISUALIZE_GEO_FIELD_TRIGGER,
} from '../../../../../../../src/plugins/ui_actions/public';
import { getVisualizeGeoFieldMessage } from '../../../utils';
import { DragDrop } from '../../../drag_drop';
import { GlobeIllustration } from '../../../assets/globe_illustration';
import './geo_field_workspace_panel.scss';

interface Props {
fieldType: string;
fieldName: string;
indexPatternId: string;
uiActions: UiActionsStart;
}

const dragDropIdentifier = {
id: 'lnsGeoFieldWorkspace',
humanData: {
label: i18n.translate('xpack.lens.geoFieldWorkspace.dropZoneLabel', {
defaultMessage: 'drop zone to open in maps',
}),
},
};

const dragDropOrder = [1, 0, 0, 0];

export function GeoFieldWorkspacePanel(props: Props) {
function onDrop() {
props.uiActions.getTrigger(VISUALIZE_GEO_FIELD_TRIGGER).exec({
indexPatternId: props.indexPatternId,
fieldName: props.fieldName,
});
}

return (
<EuiPageContentBody className="lnsWorkspacePanelWrapper__pageContentBody">
<EuiText className="lnsWorkspacePanel__emptyContent" textAlign="center" size="s">
<h2>
<strong>{getVisualizeGeoFieldMessage(props.fieldType)}</strong>
</h2>
<GlobeIllustration aria-hidden={true} className="lnsWorkspacePanel__dropIllustration" />
<DragDrop
className="lnsVisualizeGeoFieldWorkspacePanel__dragDrop"
dataTestSubj="lnsGeoFieldWorkspace"
draggable={false}
dropTypes={['field_add']}
order={dragDropOrder}
value={dragDropIdentifier}
onDrop={onDrop}
>
<p>
<strong>
<FormattedMessage
id="xpack.lens.geoFieldWorkspace.dropMessage"
defaultMessage="Drop field here to open in Maps"
/>
</strong>
</p>
</DragDrop>
</EuiText>
</EuiPageContentBody>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -338,17 +338,22 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({
);
};

return (
<WorkspacePanelWrapper
title={title}
framePublicAPI={framePublicAPI}
dispatch={dispatch}
visualizationState={visualizationState}
visualizationId={activeVisualizationId}
datasourceStates={datasourceStates}
datasourceMap={datasourceMap}
visualizationMap={visualizationMap}
>
const dragDropContext = useContext(DragContext);

const renderDragDrop = () => {
const customWorkspaceRenderer =
activeDatasourceId &&
datasourceMap[activeDatasourceId]?.getCustomWorkspaceRenderer &&
dragDropContext.dragging
? datasourceMap[activeDatasourceId].getCustomWorkspaceRenderer!(
datasourceStates[activeDatasourceId].state,
dragDropContext.dragging
)
: undefined;

return customWorkspaceRenderer ? (
customWorkspaceRenderer()
) : (
<DragDrop
className="lnsWorkspacePanel__dragDrop"
dataTestSubj="lnsWorkspace"
Expand All @@ -363,6 +368,21 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({
{Boolean(suggestionForDraggedField) && expression !== null && renderEmptyWorkspace()}
</EuiPageContentBody>
</DragDrop>
);
};

return (
<WorkspacePanelWrapper
title={title}
framePublicAPI={framePublicAPI}
dispatch={dispatch}
visualizationState={visualizationState}
visualizationId={activeVisualizationId}
datasourceStates={datasourceStates}
datasourceMap={datasourceMap}
visualizationMap={visualizationMap}
>
{renderDragDrop()}
</WorkspacePanelWrapper>
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export interface EditorFrameStartPlugins {
embeddable?: EmbeddableStart;
dashboard?: DashboardStart;
expressions: ExpressionsStart;
uiActions?: UiActionsStart;
uiActions: UiActionsStart;
charts: ChartsPluginSetup;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { documentField } from './document_field';
import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks';
import { indexPatternFieldEditorPluginMock } from '../../../../../src/plugins/index_pattern_field_editor/public/mocks';
import { getFieldByNameFactory } from './pure_helpers';
import { uiActionsPluginMock } from '../../../../../src/plugins/ui_actions/public/mocks';

const fieldsOne = [
{
Expand Down Expand Up @@ -267,6 +268,7 @@ describe('IndexPattern Data Panel', () => {
showNoDataPopover: jest.fn(),
dropOntoWorkspace: jest.fn(),
hasSuggestionForField: jest.fn(() => false),
uiActions: uiActionsPluginMock.createStartContract(),
};
});

Expand Down
14 changes: 13 additions & 1 deletion x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { fieldExists } from './pure_helpers';
import { Loader } from '../loader';
import { esQuery, IIndexPattern } from '../../../../../src/plugins/data/public';
import { IndexPatternFieldEditorStart } from '../../../../../src/plugins/index_pattern_field_editor/public';
import { VISUALIZE_GEO_FIELD_TRIGGER } from '../../../../../src/plugins/ui_actions/public';

export type Props = Omit<DatasourceDataPanelProps<IndexPatternPrivateState>, 'core'> & {
data: DataPublicPluginStart;
Expand Down Expand Up @@ -73,6 +74,8 @@ const supportedFieldTypes = new Set([
'ip_range',
'histogram',
'document',
'geo_point',
'geo_shape',
]);

const fieldTypeNames: Record<DataType, string> = {
Expand All @@ -83,6 +86,8 @@ const fieldTypeNames: Record<DataType, string> = {
date: i18n.translate('xpack.lens.datatypes.date', { defaultMessage: 'date' }),
ip: i18n.translate('xpack.lens.datatypes.ipAddress', { defaultMessage: 'IP' }),
histogram: i18n.translate('xpack.lens.datatypes.histogram', { defaultMessage: 'histogram' }),
geo_point: i18n.translate('xpack.lens.datatypes.geoPoint', { defaultMessage: 'geo_point' }),
geo_shape: i18n.translate('xpack.lens.datatypes.geoShape', { defaultMessage: 'geo_shape' }),
};

// Wrapper around esQuery.buildEsQuery, handling errors (e.g. because a query can't be parsed) by
Expand Down Expand Up @@ -121,6 +126,7 @@ export function IndexPatternDataPanel({
showNoDataPopover,
dropOntoWorkspace,
hasSuggestionForField,
uiActions,
}: Props) {
const { indexPatternRefs, indexPatterns, currentIndexPatternId } = state;
const onChangeIndexPattern = useCallback(
Expand Down Expand Up @@ -233,6 +239,7 @@ export function IndexPatternDataPanel({
existenceFetchTimeout={state.existenceFetchTimeout}
dropOntoWorkspace={dropOntoWorkspace}
hasSuggestionForField={hasSuggestionForField}
uiActions={uiActions}
/>
)}
</>
Expand Down Expand Up @@ -286,6 +293,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
charts,
dropOntoWorkspace,
hasSuggestionForField,
uiActions,
}: Omit<DatasourceDataPanelProps, 'state' | 'setState' | 'showNoDataPopover' | 'core'> & {
data: DataPublicPluginStart;
core: CoreStart;
Expand All @@ -310,7 +318,10 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
isMetaAccordionOpen: false,
});
const currentIndexPattern = indexPatterns[currentIndexPatternId];
const allFields = currentIndexPattern.fields;
const visualizeGeoFieldTrigger = uiActions.getTrigger(VISUALIZE_GEO_FIELD_TRIGGER);
const allFields = visualizeGeoFieldTrigger
? currentIndexPattern.fields
: currentIndexPattern.fields.filter(({ type }) => type !== 'geo_point' && type !== 'geo_shape');
const clearLocalState = () => setLocalState((s) => ({ ...s, nameFilter: '', typeFilter: [] }));
const hasSyncedExistingFields = existingFields[currentIndexPattern.title];
const availableFieldTypes = uniq(allFields.map(({ type }) => type)).filter(
Expand Down Expand Up @@ -807,6 +818,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
hasSuggestionForField={hasSuggestionForField}
editField={editField}
removeField={removeField}
uiActions={uiActions}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks';
import { IndexPattern } from './types';
import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks';
import { documentField } from './document_field';
import { uiActionsPluginMock } from '../../../../../src/plugins/ui_actions/public/mocks';

const chartsThemeService = chartPluginMock.createSetupContract().theme;

Expand Down Expand Up @@ -109,6 +110,7 @@ describe('IndexPattern Field Item', () => {
itemIndex: 0,
dropOntoWorkspace: () => {},
hasSuggestionForField: () => false,
uiActions: uiActionsPluginMock.createStartContract(),
};

data.fieldFormats = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ import { BucketedAggregation, FieldStatsResponse } from '../../common';
import { IndexPattern, IndexPatternField, DraggedField } from './types';
import { LensFieldIcon } from './lens_field_icon';
import { trackUiEvent } from '../lens_ui_telemetry';
import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public';
import { VisualizeGeoFieldButton } from './visualize_geo_field_button';
import { getVisualizeGeoFieldMessage } from '../utils';

import { debouncedComponent } from '../debounced_component';

Expand All @@ -75,6 +78,7 @@ export interface FieldItemProps {
editField?: (name: string) => void;
removeField?: (name: string) => void;
hasSuggestionForField: DatasourceDataPanelProps['hasSuggestionForField'];
uiActions: UiActionsStart;
}

interface State {
Expand Down Expand Up @@ -149,7 +153,13 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) {

function fetchData() {
// Range types don't have any useful stats we can show
if (state.isLoading || field.type === 'document' || field.type.includes('range')) {
if (
state.isLoading ||
field.type === 'document' ||
field.type.includes('range') ||
field.type === 'geo_point' ||
field.type === 'geo_shape'
) {
return;
}

Expand Down Expand Up @@ -392,6 +402,7 @@ function FieldItemPopoverContents(props: State & FieldItemProps) {
removeField,
hasSuggestionForField,
hideDetails,
uiActions,
} = props;

const chartTheme = chartsThemeService.useChartsTheme();
Expand Down Expand Up @@ -467,6 +478,21 @@ function FieldItemPopoverContents(props: State & FieldItemProps) {
</EuiText>
</>
);
} else if (field.type === 'geo_point' || field.type === 'geo_shape') {
return (
<>
<EuiPopoverTitle>{panelHeader}</EuiPopoverTitle>

<EuiText size="s">{getVisualizeGeoFieldMessage(field.type)}</EuiText>

<EuiSpacer size="m" />
<VisualizeGeoFieldButton
uiActions={uiActions}
indexPatternId={indexPattern.id}
fieldName={field.name}
/>
</>
);
} else if (
(!props.histogram || props.histogram.buckets.length === 0) &&
(!props.topValues || props.topValues.buckets.length === 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { NoFieldsCallout } from './no_fields_callout';
import { IndexPatternField } from './types';
import { FieldItemSharedProps, FieldsAccordion } from './fields_accordion';
import { DatasourceDataPanelProps } from '../types';
import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public';
const PAGINATION_SIZE = 50;

export type FieldGroups = Record<
Expand Down Expand Up @@ -55,6 +56,7 @@ export const FieldList = React.memo(function FieldList({
hasSuggestionForField,
editField,
removeField,
uiActions,
}: {
exists: (field: IndexPatternField) => boolean;
fieldGroups: FieldGroups;
Expand All @@ -72,6 +74,7 @@ export const FieldList = React.memo(function FieldList({
hasSuggestionForField: DatasourceDataPanelProps['hasSuggestionForField'];
editField?: (name: string) => void;
removeField?: (name: string) => void;
uiActions: UiActionsStart;
}) {
const [pageSize, setPageSize] = useState(PAGINATION_SIZE);
const [scrollContainer, setScrollContainer] = useState<Element | undefined>(undefined);
Expand Down Expand Up @@ -155,6 +158,7 @@ export const FieldList = React.memo(function FieldList({
groupIndex={0}
dropOntoWorkspace={dropOntoWorkspace}
hasSuggestionForField={hasSuggestionForField}
uiActions={uiActions}
/>
))
)}
Expand Down Expand Up @@ -206,6 +210,7 @@ export const FieldList = React.memo(function FieldList({
defaultNoFieldsMessage={fieldGroup.defaultNoFieldsMessage}
/>
}
uiActions={uiActions}
/>
<EuiSpacer size="m" />
</Fragment>
Expand Down
Loading

0 comments on commit b097385

Please sign in to comment.