mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Maps] convert EMS file source to TS (#65373)
* [Maps] convert EMS file source to TS * ts more ems_file_source * ts lint cleanup * more ts clean up * clean up some ts-ignores * review feedback
This commit is contained in:
parent
552bac5dc7
commit
2eaa074923
24 changed files with 449 additions and 351 deletions
|
@ -28,7 +28,7 @@ export type EMSTMSSourceDescriptor = AbstractSourceDescriptor & {
|
|||
|
||||
export type EMSFileSourceDescriptor = AbstractSourceDescriptor & {
|
||||
// id: EMS file id
|
||||
|
||||
id: string;
|
||||
tooltipProperties: string[];
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@import 'metric_editors';
|
||||
@import './geometry_filter';
|
||||
@import 'tooltip_selector';
|
||||
@import 'tooltip_selector/tooltip_selector';
|
||||
|
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
EuiButtonIcon,
|
||||
EuiDragDropContext,
|
||||
EuiDraggable,
|
||||
EuiDroppable,
|
||||
EuiText,
|
||||
EuiTextAlign,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { AddTooltipFieldPopover } from './add_tooltip_field_popover';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
// TODO import reorder from EUI once its exposed as service
|
||||
// https://github.com/elastic/eui/issues/2372
|
||||
const reorder = (list, startIndex, endIndex) => {
|
||||
const result = Array.from(list);
|
||||
const [removed] = result.splice(startIndex, 1);
|
||||
result.splice(endIndex, 0, removed);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const getProps = async field => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const label = await field.getLabel();
|
||||
const type = await field.getDataType();
|
||||
resolve({
|
||||
label: label,
|
||||
type: type,
|
||||
name: field.getName(),
|
||||
});
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export class TooltipSelector extends Component {
|
||||
state = {
|
||||
fieldProps: [],
|
||||
selectedFieldProps: [],
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._isMounted = false;
|
||||
this._previousFields = null;
|
||||
this._previousSelectedTooltips = null;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
this._loadFieldProps();
|
||||
this._loadTooltipFieldProps();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this._loadTooltipFieldProps();
|
||||
this._loadFieldProps();
|
||||
}
|
||||
|
||||
async _loadTooltipFieldProps() {
|
||||
if (!this.props.tooltipFields || this.props.tooltipFields === this._previousSelectedTooltips) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._previousSelectedTooltips = this.props.tooltipFields;
|
||||
const selectedProps = this.props.tooltipFields.map(getProps);
|
||||
const selectedFieldProps = await Promise.all(selectedProps);
|
||||
if (this._isMounted) {
|
||||
this.setState({ selectedFieldProps });
|
||||
}
|
||||
}
|
||||
|
||||
async _loadFieldProps() {
|
||||
if (!this.props.fields || this.props.fields === this._previousFields) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._previousFields = this.props.fields;
|
||||
const props = this.props.fields.map(getProps);
|
||||
const fieldProps = await Promise.all(props);
|
||||
if (this._isMounted) {
|
||||
this.setState({ fieldProps });
|
||||
}
|
||||
}
|
||||
|
||||
_getPropertyLabel = propertyName => {
|
||||
if (!this.state.fieldProps.length) {
|
||||
return propertyName;
|
||||
}
|
||||
const prop = this.state.fieldProps.find(field => {
|
||||
return field.name === propertyName;
|
||||
});
|
||||
return prop.label ? prop.label : propertyName;
|
||||
};
|
||||
|
||||
_getTooltipProperties() {
|
||||
return this.props.tooltipFields.map(field => field.getName());
|
||||
}
|
||||
|
||||
_onAdd = properties => {
|
||||
if (!this.props.tooltipFields) {
|
||||
this.props.onChange([...properties]);
|
||||
} else {
|
||||
const existingProperties = this._getTooltipProperties();
|
||||
this.props.onChange([...existingProperties, ...properties]);
|
||||
}
|
||||
};
|
||||
|
||||
_removeProperty = index => {
|
||||
if (!this.props.tooltipFields) {
|
||||
this.props.onChange([]);
|
||||
} else {
|
||||
const tooltipProperties = this._getTooltipProperties();
|
||||
tooltipProperties.splice(index, 1);
|
||||
this.props.onChange(tooltipProperties);
|
||||
}
|
||||
};
|
||||
|
||||
_onDragEnd = ({ source, destination }) => {
|
||||
// Dragging item out of EuiDroppable results in destination of null
|
||||
if (!destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onChange(reorder(this._getTooltipProperties(), source.index, destination.index));
|
||||
};
|
||||
|
||||
_renderProperties() {
|
||||
if (!this.state.selectedFieldProps.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiDragDropContext onDragEnd={this._onDragEnd}>
|
||||
<EuiDroppable droppableId="mapLayerTOC" spacing="none">
|
||||
{(provided, snapshot) =>
|
||||
this.state.selectedFieldProps.map((field, idx) => (
|
||||
<EuiDraggable
|
||||
spacing="none"
|
||||
key={field.name}
|
||||
index={idx}
|
||||
draggableId={field.name}
|
||||
customDragHandle={true}
|
||||
disableInteractiveElementBlocking // Allows button to be drag handle
|
||||
>
|
||||
{(provided, state) => (
|
||||
<div
|
||||
className={classNames('mapTooltipSelector__propertyRow', {
|
||||
'mapTooltipSelector__propertyRow-isDragging': state.isDragging,
|
||||
'mapTooltipSelector__propertyRow-isDraggingOver': snapshot.isDraggingOver,
|
||||
})}
|
||||
>
|
||||
<EuiText className="mapTooltipSelector__propertyContent" size="s">
|
||||
{this._getPropertyLabel(field.name)}
|
||||
</EuiText>
|
||||
<div className="mapTooltipSelector__propertyIcons">
|
||||
<EuiButtonIcon
|
||||
iconType="trash"
|
||||
color="danger"
|
||||
onClick={this._removeProperty.bind(null, idx)}
|
||||
title={i18n.translate('xpack.maps.tooltipSelector.trashButtonTitle', {
|
||||
defaultMessage: 'Remove property',
|
||||
})}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.maps.tooltipSelector.trashButtonAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Remove property',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
<EuiButtonIcon
|
||||
className="mapTooltipSelector__grab"
|
||||
iconType="grab"
|
||||
color="subdued"
|
||||
title={i18n.translate('xpack.maps.tooltipSelector.grabButtonTitle', {
|
||||
defaultMessage: 'Reorder property',
|
||||
})}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.maps.tooltipSelector.grabButtonAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Reorder property',
|
||||
}
|
||||
)}
|
||||
{...provided.dragHandleProps}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</EuiDraggable>
|
||||
))
|
||||
}
|
||||
</EuiDroppable>
|
||||
</EuiDragDropContext>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this._renderProperties()}
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<EuiTextAlign textAlign="center">
|
||||
<AddTooltipFieldPopover
|
||||
onAdd={this._onAdd}
|
||||
fields={this.state.fieldProps}
|
||||
selectedFields={this.state.selectedFieldProps}
|
||||
/>
|
||||
</EuiTextAlign>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ exports[`Should remove selected fields from selectable 1`] = `
|
|||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "@timestamp",
|
||||
"label": "@timestamp-label",
|
||||
"prepend": <FieldIcon
|
||||
className="eui-alignMiddle"
|
||||
fill="none"
|
||||
|
@ -100,7 +100,7 @@ exports[`Should render 1`] = `
|
|||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "@timestamp",
|
||||
"label": "@timestamp-label",
|
||||
"prepend": <FieldIcon
|
||||
className="eui-alignMiddle"
|
||||
fill="none"
|
||||
|
@ -118,7 +118,7 @@ exports[`Should render 1`] = `
|
|||
"value": "prop1",
|
||||
},
|
||||
Object {
|
||||
"label": "prop2",
|
||||
"label": "prop2-label",
|
||||
"prepend": <FieldIcon
|
||||
className="eui-alignMiddle"
|
||||
fill="none"
|
|
@ -39,7 +39,7 @@ exports[`TooltipSelector should render component 1`] = `
|
|||
Object {
|
||||
"label": "foobar_label",
|
||||
"name": "iso2",
|
||||
"type": "foobar_type",
|
||||
"type": "string",
|
||||
},
|
||||
]
|
||||
}
|
|
@ -18,15 +18,17 @@ const defaultProps = {
|
|||
},
|
||||
{
|
||||
name: 'prop2',
|
||||
label: 'prop2-label',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: '@timestamp',
|
||||
label: '@timestamp-label',
|
||||
type: 'date',
|
||||
},
|
||||
],
|
||||
selectedFields: [],
|
||||
onSelect: () => {},
|
||||
onAdd: () => {},
|
||||
};
|
||||
|
||||
test('Should render', () => {
|
||||
|
@ -39,7 +41,10 @@ test('Should remove selected fields from selectable', () => {
|
|||
const component = shallow(
|
||||
<AddTooltipFieldPopover
|
||||
{...defaultProps}
|
||||
selectedFields={[{ name: 'prop2' }, { name: 'prop1' }]}
|
||||
selectedFields={[
|
||||
{ name: 'prop2', label: 'prop2-label', type: 'string' },
|
||||
{ name: 'prop1', label: 'prop1-label', type: 'string' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/consistent-type-definitions */
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import {
|
||||
|
@ -11,19 +12,26 @@ import {
|
|||
EuiPopoverTitle,
|
||||
EuiButtonEmpty,
|
||||
EuiSelectable,
|
||||
EuiSelectableOption,
|
||||
EuiButton,
|
||||
EuiSpacer,
|
||||
EuiTextAlign,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FieldIcon } from '../../../../../src/plugins/kibana_react/public';
|
||||
import { FieldIcon } from '../../../../../../src/plugins/kibana_react/public';
|
||||
|
||||
const sortByLabel = (a, b) => {
|
||||
return a.label.localeCompare(b.label);
|
||||
export type FieldProps = {
|
||||
label: string;
|
||||
type: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
function getOptions(fields, selectedFields) {
|
||||
function sortByLabel(a: EuiSelectableOption, b: EuiSelectableOption): number {
|
||||
return a.label.localeCompare(b.label);
|
||||
}
|
||||
|
||||
function getOptions(fields: FieldProps[], selectedFields: FieldProps[]): EuiSelectableOption[] {
|
||||
if (!fields) {
|
||||
return [];
|
||||
}
|
||||
|
@ -43,19 +51,33 @@ function getOptions(fields, selectedFields) {
|
|||
'type' in field ? (
|
||||
<FieldIcon className="eui-alignMiddle" type={field.type} fill="none" />
|
||||
) : null,
|
||||
label: 'label' in field ? field.label : field.name,
|
||||
label: field.label,
|
||||
};
|
||||
})
|
||||
.sort(sortByLabel);
|
||||
}
|
||||
|
||||
export class AddTooltipFieldPopover extends Component {
|
||||
state = {
|
||||
interface Props {
|
||||
onAdd: (checkedFieldNames: string[]) => void;
|
||||
fields: FieldProps[];
|
||||
selectedFields: FieldProps[];
|
||||
}
|
||||
|
||||
interface State {
|
||||
isPopoverOpen: boolean;
|
||||
checkedFields: string[];
|
||||
options?: EuiSelectableOption[];
|
||||
prevFields?: FieldProps[];
|
||||
prevSelectedFields?: FieldProps[];
|
||||
}
|
||||
|
||||
export class AddTooltipFieldPopover extends Component<Props, State> {
|
||||
state: State = {
|
||||
isPopoverOpen: false,
|
||||
checkedFields: [],
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State) {
|
||||
if (
|
||||
nextProps.fields !== prevState.prevFields ||
|
||||
nextProps.selectedFields !== prevState.prevSelectedFields
|
||||
|
@ -83,13 +105,13 @@ export class AddTooltipFieldPopover extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
_onSelect = options => {
|
||||
const checkedFields = options
|
||||
_onSelect = (options: EuiSelectableOption[]) => {
|
||||
const checkedFields: string[] = options
|
||||
.filter(option => {
|
||||
return option.checked === 'on';
|
||||
})
|
||||
.map(option => {
|
||||
return option.value;
|
||||
return option.value as string;
|
||||
});
|
||||
|
||||
this.setState({
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { TooltipSelector } from './tooltip_selector';
|
|
@ -8,25 +8,19 @@ import React from 'react';
|
|||
import { shallow } from 'enzyme';
|
||||
|
||||
import { TooltipSelector } from './tooltip_selector';
|
||||
import { AbstractField } from '../../layers/fields/field';
|
||||
import { FIELD_ORIGIN } from '../../../common/constants';
|
||||
|
||||
class MockField {
|
||||
constructor({ name, label, type }) {
|
||||
this._name = name;
|
||||
class MockField extends AbstractField {
|
||||
private _label?: string;
|
||||
constructor({ name, label }: { name: string; label?: string }) {
|
||||
super({ fieldName: name, origin: FIELD_ORIGIN.SOURCE });
|
||||
this._label = label;
|
||||
this._type = type;
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
async getLabel() {
|
||||
return this._label || 'foobar_label';
|
||||
}
|
||||
|
||||
async getDataType() {
|
||||
return this._type || 'foobar_type';
|
||||
}
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
|
@ -36,11 +30,9 @@ const defaultProps = {
|
|||
new MockField({
|
||||
name: 'iso2',
|
||||
label: 'ISO 3166-1 alpha-2 code',
|
||||
type: 'string',
|
||||
}),
|
||||
new MockField({
|
||||
name: 'iso3',
|
||||
type: 'string',
|
||||
}),
|
||||
],
|
||||
};
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
EuiButtonIcon,
|
||||
EuiDragDropContext,
|
||||
EuiDraggable,
|
||||
EuiDroppable,
|
||||
EuiText,
|
||||
EuiTextAlign,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AddTooltipFieldPopover, FieldProps } from './add_tooltip_field_popover';
|
||||
import { IField } from '../../layers/fields/field';
|
||||
|
||||
// TODO import reorder from EUI once its exposed as service
|
||||
// https://github.com/elastic/eui/issues/2372
|
||||
const reorder = (list: string[], startIndex: number, endIndex: number) => {
|
||||
const result = Array.from(list);
|
||||
const [removed] = result.splice(startIndex, 1);
|
||||
result.splice(endIndex, 0, removed);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
async function getFieldProps(field: IField): Promise<FieldProps> {
|
||||
return {
|
||||
label: await field.getLabel(),
|
||||
type: await field.getDataType(),
|
||||
name: field.getName(),
|
||||
};
|
||||
}
|
||||
|
||||
interface Props {
|
||||
fields: IField[] | null;
|
||||
onChange: (selectedFieldNames: string[]) => void;
|
||||
tooltipFields: IField[];
|
||||
}
|
||||
|
||||
interface State {
|
||||
fieldProps: FieldProps[];
|
||||
selectedFieldProps: FieldProps[];
|
||||
}
|
||||
|
||||
export class TooltipSelector extends Component<Props, State> {
|
||||
private _isMounted: boolean;
|
||||
private _previousFields: IField[] | null;
|
||||
private _previousSelectedTooltips: IField[] | null;
|
||||
|
||||
state = {
|
||||
fieldProps: [],
|
||||
selectedFieldProps: [],
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this._isMounted = false;
|
||||
this._previousFields = null;
|
||||
this._previousSelectedTooltips = null;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
this._loadFieldProps();
|
||||
this._loadTooltipFieldProps();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this._loadTooltipFieldProps();
|
||||
this._loadFieldProps();
|
||||
}
|
||||
|
||||
async _loadTooltipFieldProps() {
|
||||
if (!this.props.tooltipFields || this.props.tooltipFields === this._previousSelectedTooltips) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._previousSelectedTooltips = this.props.tooltipFields;
|
||||
const promises = this.props.tooltipFields.map(getFieldProps);
|
||||
const selectedFieldProps = await Promise.all(promises);
|
||||
if (this._isMounted) {
|
||||
this.setState({ selectedFieldProps });
|
||||
}
|
||||
}
|
||||
|
||||
async _loadFieldProps() {
|
||||
if (!this.props.fields || this.props.fields === this._previousFields) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._previousFields = this.props.fields;
|
||||
const promises = this.props.fields.map(getFieldProps);
|
||||
const fieldProps = await Promise.all(promises);
|
||||
if (this._isMounted) {
|
||||
this.setState({ fieldProps });
|
||||
}
|
||||
}
|
||||
|
||||
_getPropertyLabel = (propertyName: string) => {
|
||||
if (!this.state.fieldProps.length) {
|
||||
return propertyName;
|
||||
}
|
||||
const prop: FieldProps | undefined = this.state.fieldProps.find((field: FieldProps) => {
|
||||
return field.name === propertyName;
|
||||
});
|
||||
return prop ? prop!.label : propertyName;
|
||||
};
|
||||
|
||||
_getTooltipFieldNames(): string[] {
|
||||
return this.props.tooltipFields ? this.props.tooltipFields.map(field => field.getName()) : [];
|
||||
}
|
||||
|
||||
_onAdd = (properties: string[]) => {
|
||||
if (!this.props.tooltipFields) {
|
||||
this.props.onChange([...properties]);
|
||||
} else {
|
||||
const existingProperties = this._getTooltipFieldNames();
|
||||
this.props.onChange([...existingProperties, ...properties]);
|
||||
}
|
||||
};
|
||||
|
||||
_removeProperty = (index: number) => {
|
||||
if (!this.props.tooltipFields) {
|
||||
this.props.onChange([]);
|
||||
} else {
|
||||
const tooltipProperties = this._getTooltipFieldNames();
|
||||
tooltipProperties.splice(index, 1);
|
||||
this.props.onChange(tooltipProperties);
|
||||
}
|
||||
};
|
||||
|
||||
_onDragEnd = ({
|
||||
source,
|
||||
destination,
|
||||
}: {
|
||||
source: { index: number };
|
||||
destination?: { index: number };
|
||||
}) => {
|
||||
// Dragging item out of EuiDroppable results in destination of null
|
||||
if (!destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onChange(reorder(this._getTooltipFieldNames(), source.index, destination.index));
|
||||
};
|
||||
|
||||
_renderProperties() {
|
||||
if (!this.state.selectedFieldProps.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiDragDropContext onDragEnd={this._onDragEnd}>
|
||||
<EuiDroppable droppableId="mapLayerTOC" spacing="none">
|
||||
{(droppableProvided, snapshot) => (
|
||||
<Fragment>
|
||||
{this.state.selectedFieldProps.map((field: FieldProps, idx: number) => (
|
||||
<EuiDraggable
|
||||
spacing="none"
|
||||
key={field.name}
|
||||
index={idx}
|
||||
draggableId={field.name}
|
||||
customDragHandle={true}
|
||||
disableInteractiveElementBlocking // Allows button to be drag handle
|
||||
>
|
||||
{(provided, state) => (
|
||||
<div
|
||||
className={classNames('mapTooltipSelector__propertyRow', {
|
||||
'mapTooltipSelector__propertyRow-isDragging': state.isDragging,
|
||||
'mapTooltipSelector__propertyRow-isDraggingOver': snapshot.isDraggingOver,
|
||||
})}
|
||||
>
|
||||
<EuiText className="mapTooltipSelector__propertyContent" size="s">
|
||||
{this._getPropertyLabel(field.name)}
|
||||
</EuiText>
|
||||
<div className="mapTooltipSelector__propertyIcons">
|
||||
<EuiButtonIcon
|
||||
iconType="trash"
|
||||
color="danger"
|
||||
onClick={this._removeProperty.bind(null, idx)}
|
||||
title={i18n.translate('xpack.maps.tooltipSelector.trashButtonTitle', {
|
||||
defaultMessage: 'Remove property',
|
||||
})}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.maps.tooltipSelector.trashButtonAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Remove property',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
<EuiButtonIcon
|
||||
className="mapTooltipSelector__grab"
|
||||
iconType="grab"
|
||||
color="subdued"
|
||||
title={i18n.translate('xpack.maps.tooltipSelector.grabButtonTitle', {
|
||||
defaultMessage: 'Reorder property',
|
||||
})}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.maps.tooltipSelector.grabButtonAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Reorder property',
|
||||
}
|
||||
)}
|
||||
{...provided.dragHandleProps}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</EuiDraggable>
|
||||
))}
|
||||
</Fragment>
|
||||
)}
|
||||
</EuiDroppable>
|
||||
</EuiDragDropContext>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this._renderProperties()}
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<EuiTextAlign textAlign="center">
|
||||
<AddTooltipFieldPopover
|
||||
onAdd={this._onAdd}
|
||||
fields={this.state.fieldProps}
|
||||
selectedFields={this.state.selectedFieldProps}
|
||||
/>
|
||||
</EuiTextAlign>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
import { FIELD_ORIGIN } from '../../../common/constants';
|
||||
import { IField, AbstractField } from './field';
|
||||
import { IVectorSource } from '../sources/vector_source';
|
||||
import { IEmsFileSource } from '../sources/ems_file_source/ems_file_source';
|
||||
import { IEmsFileSource } from '../sources/ems_file_source';
|
||||
|
||||
export class EMSFileField extends AbstractField implements IField {
|
||||
private readonly _source: IEmsFileSource;
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
MapFilters,
|
||||
StyleDescriptor,
|
||||
} from '../../common/descriptor_types';
|
||||
import { Attribution, ImmutableSourceProperty, ISource } from './sources/source';
|
||||
import { Attribution, ImmutableSourceProperty, ISource, SourceEditorArgs } from './sources/source';
|
||||
import { SyncContext } from '../actions/map_actions';
|
||||
import { IStyle } from './styles/style';
|
||||
|
||||
|
@ -58,7 +58,7 @@ export interface ILayer {
|
|||
getStyleForEditing(): IStyle;
|
||||
getCurrentStyle(): IStyle;
|
||||
getImmutableSourceProperties(): Promise<ImmutableSourceProperty[]>;
|
||||
renderSourceSettingsEditor({ onChange }: { onChange: () => void }): ReactElement<any> | null;
|
||||
renderSourceSettingsEditor({ onChange }: SourceEditorArgs): ReactElement<any> | null;
|
||||
isLayerLoading(): boolean;
|
||||
hasErrors(): boolean;
|
||||
getErrors(): string;
|
||||
|
@ -368,7 +368,7 @@ export class AbstractLayer implements ILayer {
|
|||
return await source.getImmutableProperties();
|
||||
}
|
||||
|
||||
renderSourceSettingsEditor({ onChange }: { onChange: () => void }) {
|
||||
renderSourceSettingsEditor({ onChange }: SourceEditorArgs) {
|
||||
const source = this.getSourceForEditing();
|
||||
return source.renderSourceSettingsEditor({ onChange });
|
||||
}
|
||||
|
|
|
@ -4,31 +4,51 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiComboBox, EuiFormRow } from '@elastic/eui';
|
||||
import React, { Component } from 'react';
|
||||
import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
// @ts-ignore
|
||||
import { getEMSClient } from '../../../meta';
|
||||
import { getEmsUnavailableMessage } from '../ems_unavailable_message';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EMSFileSourceDescriptor } from '../../../../common/descriptor_types';
|
||||
|
||||
interface Props {
|
||||
onSourceConfigChange: (sourceConfig: Partial<EMSFileSourceDescriptor>) => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
hasLoadedOptions: boolean;
|
||||
emsFileOptions: Array<EuiComboBoxOptionOption<string>>;
|
||||
selectedOption: EuiComboBoxOptionOption<string> | null;
|
||||
}
|
||||
|
||||
export class EMSFileCreateSourceEditor extends Component<Props, State> {
|
||||
private _isMounted: boolean = false;
|
||||
|
||||
export class EMSFileCreateSourceEditor extends React.Component {
|
||||
state = {
|
||||
emsFileOptionsRaw: null,
|
||||
hasLoadedOptions: false,
|
||||
emsFileOptions: [],
|
||||
selectedOption: null,
|
||||
};
|
||||
|
||||
_loadFileOptions = async () => {
|
||||
// @ts-ignore
|
||||
const emsClient = getEMSClient();
|
||||
const fileLayers = await emsClient.getFileLayers();
|
||||
// @ts-ignore
|
||||
const fileLayers: unknown[] = await emsClient.getFileLayers();
|
||||
const options = fileLayers.map(fileLayer => {
|
||||
return {
|
||||
id: fileLayer.getId(),
|
||||
name: fileLayer.getDisplayName(),
|
||||
// @ts-ignore
|
||||
value: fileLayer.getId(),
|
||||
// @ts-ignore
|
||||
label: fileLayer.getDisplayName(),
|
||||
};
|
||||
});
|
||||
if (this._isMounted) {
|
||||
this.setState({
|
||||
emsFileOptionsRaw: options,
|
||||
hasLoadedOptions: true,
|
||||
emsFileOptions: options,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -42,7 +62,7 @@ export class EMSFileCreateSourceEditor extends React.Component {
|
|||
this._loadFileOptions();
|
||||
}
|
||||
|
||||
_onChange = selectedOptions => {
|
||||
_onChange = (selectedOptions: Array<EuiComboBoxOptionOption<string>>) => {
|
||||
if (selectedOptions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -54,32 +74,28 @@ export class EMSFileCreateSourceEditor extends React.Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
if (!this.state.emsFileOptionsRaw) {
|
||||
if (!this.state.hasLoadedOptions) {
|
||||
// TODO display loading message
|
||||
return null;
|
||||
}
|
||||
|
||||
const options = this.state.emsFileOptionsRaw.map(({ id, name }) => {
|
||||
return { label: name, value: id };
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.maps.source.emsFile.layerLabel', {
|
||||
defaultMessage: 'Layer',
|
||||
})}
|
||||
helpText={this.state.emsFileOptionsRaw.length === 0 ? getEmsUnavailableMessage() : null}
|
||||
helpText={this.state.emsFileOptions.length === 0 ? getEmsUnavailableMessage() : null}
|
||||
>
|
||||
<EuiComboBox
|
||||
placeholder={i18n.translate('xpack.maps.source.emsFile.selectPlaceholder', {
|
||||
defaultMessage: 'Select EMS vector shapes',
|
||||
})}
|
||||
options={options}
|
||||
selectedOptions={this.state.selectedOption ? [this.state.selectedOption] : []}
|
||||
options={this.state.emsFileOptions}
|
||||
selectedOptions={this.state.selectedOption ? [this.state.selectedOption!] : []}
|
||||
onChange={this._onChange}
|
||||
isClearable={false}
|
||||
singleSelection={true}
|
||||
isDisabled={this.state.emsFileOptionsRaw.length === 0}
|
||||
isDisabled={this.state.emsFileOptions.length === 0}
|
||||
data-test-subj="emsVectorComboBox"
|
||||
/>
|
||||
</EuiFormRow>
|
|
@ -8,10 +8,9 @@ import React from 'react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { VectorLayer } from '../../vector_layer';
|
||||
import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry';
|
||||
// @ts-ignore
|
||||
import { EMSFileCreateSourceEditor } from './create_source_editor';
|
||||
// @ts-ignore
|
||||
import { EMSFileSource, sourceTitle } from './ems_file_source';
|
||||
import { EMSFileSourceDescriptor } from '../../../../common/descriptor_types';
|
||||
// @ts-ignore
|
||||
import { isEmsEnabled } from '../../../meta';
|
||||
|
||||
|
@ -24,8 +23,7 @@ export const emsBoundariesLayerWizardConfig: LayerWizard = {
|
|||
}),
|
||||
icon: 'emsApp',
|
||||
renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => {
|
||||
const onSourceConfigChange = (sourceConfig: unknown) => {
|
||||
// @ts-ignore
|
||||
const onSourceConfigChange = (sourceConfig: Partial<EMSFileSourceDescriptor>) => {
|
||||
const sourceDescriptor = EMSFileSource.createDescriptor(sourceConfig);
|
||||
const layerDescriptor = VectorLayer.createDescriptor({ sourceDescriptor }, mapColors);
|
||||
previewLayer(layerDescriptor);
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { AbstractVectorSource, IVectorSource } from '../vector_source';
|
||||
|
||||
export interface IEmsFileSource extends IVectorSource {
|
||||
getEMSFileLayer(): Promise<unknown>;
|
||||
}
|
||||
|
||||
export class EMSFileSource extends AbstractVectorSource implements IEmsFileSource {
|
||||
getEMSFileLayer(): Promise<unknown>;
|
||||
}
|
|
@ -9,11 +9,9 @@ import { EMSFileSource } from './ems_file_source';
|
|||
jest.mock('ui/new_platform');
|
||||
jest.mock('../../vector_layer', () => {});
|
||||
|
||||
function makeEMSFileSource(tooltipProperties) {
|
||||
const emsFileSource = new EMSFileSource({
|
||||
tooltipProperties: tooltipProperties,
|
||||
});
|
||||
emsFileSource.getEMSFileLayer = () => {
|
||||
function makeEMSFileSource(tooltipProperties: string[]) {
|
||||
const emsFileSource = new EMSFileSource({ tooltipProperties });
|
||||
emsFileSource.getEMSFileLayer = async () => {
|
||||
return {
|
||||
getFieldsInLanguage() {
|
||||
return [
|
|
@ -4,40 +4,56 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { AbstractVectorSource } from '../vector_source';
|
||||
import { VECTOR_SHAPE_TYPES } from '../vector_feature_types';
|
||||
import React from 'react';
|
||||
import { SOURCE_TYPES, FIELD_ORIGIN } from '../../../../common/constants';
|
||||
import { getEMSClient } from '../../../meta';
|
||||
import React, { ReactElement } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Feature } from 'geojson';
|
||||
import { Adapters } from 'src/plugins/inspector/public';
|
||||
import { Attribution, ImmutableSourceProperty, SourceEditorArgs } from '../source';
|
||||
import { AbstractVectorSource, GeoJsonWithMeta, IVectorSource } from '../vector_source';
|
||||
import { VECTOR_SHAPE_TYPES } from '../vector_feature_types';
|
||||
import { SOURCE_TYPES, FIELD_ORIGIN } from '../../../../common/constants';
|
||||
// @ts-ignore
|
||||
import { getEMSClient } from '../../../meta';
|
||||
import { getDataSourceLabel } from '../../../../common/i18n_getters';
|
||||
import { UpdateSourceEditor } from './update_source_editor';
|
||||
import { EMSFileField } from '../../fields/ems_file_field';
|
||||
import { registerSource } from '../source_registry';
|
||||
import { IField } from '../../fields/field';
|
||||
import { EMSFileSourceDescriptor } from '../../../../common/descriptor_types';
|
||||
import { ITooltipProperty } from '../../tooltips/tooltip_property';
|
||||
|
||||
export interface IEmsFileSource extends IVectorSource {
|
||||
getEMSFileLayer(): Promise<unknown>;
|
||||
createField({ fieldName }: { fieldName: string }): IField;
|
||||
}
|
||||
|
||||
export const sourceTitle = i18n.translate('xpack.maps.source.emsFileTitle', {
|
||||
defaultMessage: 'EMS Boundaries',
|
||||
});
|
||||
|
||||
export class EMSFileSource extends AbstractVectorSource {
|
||||
export class EMSFileSource extends AbstractVectorSource implements IEmsFileSource {
|
||||
static type = SOURCE_TYPES.EMS_FILE;
|
||||
|
||||
static createDescriptor({ id, tooltipProperties = [] }) {
|
||||
static createDescriptor({ id, tooltipProperties = [] }: Partial<EMSFileSourceDescriptor>) {
|
||||
return {
|
||||
type: EMSFileSource.type,
|
||||
id,
|
||||
id: id!,
|
||||
tooltipProperties,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(descriptor, inspectorAdapters) {
|
||||
private readonly _tooltipFields: IField[];
|
||||
readonly _descriptor: EMSFileSourceDescriptor;
|
||||
|
||||
constructor(descriptor: Partial<EMSFileSourceDescriptor>, inspectorAdapters?: Adapters) {
|
||||
super(EMSFileSource.createDescriptor(descriptor), inspectorAdapters);
|
||||
this._descriptor = EMSFileSource.createDescriptor(descriptor);
|
||||
this._tooltipFields = this._descriptor.tooltipProperties.map(propertyKey =>
|
||||
this.createField({ fieldName: propertyKey })
|
||||
);
|
||||
}
|
||||
|
||||
createField({ fieldName }) {
|
||||
createField({ fieldName }: { fieldName: string }): IField {
|
||||
return new EMSFileField({
|
||||
fieldName,
|
||||
source: this,
|
||||
|
@ -45,7 +61,7 @@ export class EMSFileSource extends AbstractVectorSource {
|
|||
});
|
||||
}
|
||||
|
||||
renderSourceSettingsEditor({ onChange }) {
|
||||
renderSourceSettingsEditor({ onChange }: SourceEditorArgs): ReactElement<any> | null {
|
||||
return (
|
||||
<UpdateSourceEditor
|
||||
onChange={onChange}
|
||||
|
@ -56,9 +72,12 @@ export class EMSFileSource extends AbstractVectorSource {
|
|||
);
|
||||
}
|
||||
|
||||
async getEMSFileLayer() {
|
||||
async getEMSFileLayer(): Promise<unknown> {
|
||||
// @ts-ignore
|
||||
const emsClient = getEMSClient();
|
||||
// @ts-ignore
|
||||
const emsFileLayers = await emsClient.getFileLayers();
|
||||
// @ts-ignore
|
||||
const emsFileLayer = emsFileLayers.find(fileLayer => fileLayer.getId() === this._descriptor.id);
|
||||
if (!emsFileLayer) {
|
||||
throw new Error(
|
||||
|
@ -73,19 +92,23 @@ export class EMSFileSource extends AbstractVectorSource {
|
|||
return emsFileLayer;
|
||||
}
|
||||
|
||||
async getGeoJsonWithMeta() {
|
||||
async getGeoJsonWithMeta(): Promise<GeoJsonWithMeta> {
|
||||
const emsFileLayer = await this.getEMSFileLayer();
|
||||
// @ts-ignore
|
||||
const featureCollection = await AbstractVectorSource.getGeoJson({
|
||||
// @ts-ignore
|
||||
format: emsFileLayer.getDefaultFormatType(),
|
||||
featureCollectionPath: 'data',
|
||||
// @ts-ignore
|
||||
fetchUrl: emsFileLayer.getDefaultFormatUrl(),
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
const emsIdField = emsFileLayer._config.fields.find(field => {
|
||||
return field.type === 'id';
|
||||
});
|
||||
featureCollection.features.forEach((feature, index) => {
|
||||
feature.id = emsIdField ? feature.properties[emsIdField.id] : index;
|
||||
featureCollection.features.forEach((feature: Feature, index: number) => {
|
||||
feature.id = emsIdField ? feature!.properties![emsIdField.id] : index;
|
||||
});
|
||||
|
||||
return {
|
||||
|
@ -94,10 +117,11 @@ export class EMSFileSource extends AbstractVectorSource {
|
|||
};
|
||||
}
|
||||
|
||||
async getImmutableProperties() {
|
||||
async getImmutableProperties(): Promise<ImmutableSourceProperty[]> {
|
||||
let emsLink;
|
||||
try {
|
||||
const emsFileLayer = await this.getEMSFileLayer();
|
||||
// @ts-ignore
|
||||
emsLink = emsFileLayer.getEMSHotLink();
|
||||
} catch (error) {
|
||||
// ignore error if EMS layer id could not be found
|
||||
|
@ -118,23 +142,27 @@ export class EMSFileSource extends AbstractVectorSource {
|
|||
];
|
||||
}
|
||||
|
||||
async getDisplayName() {
|
||||
async getDisplayName(): Promise<string> {
|
||||
try {
|
||||
const emsFileLayer = await this.getEMSFileLayer();
|
||||
// @ts-ignore
|
||||
return emsFileLayer.getDisplayName();
|
||||
} catch (error) {
|
||||
return this._descriptor.id;
|
||||
}
|
||||
}
|
||||
|
||||
async getAttributions() {
|
||||
async getAttributions(): Promise<Attribution[]> {
|
||||
const emsFileLayer = await this.getEMSFileLayer();
|
||||
// @ts-ignore
|
||||
return emsFileLayer.getAttributions();
|
||||
}
|
||||
|
||||
async getLeftJoinFields() {
|
||||
const emsFileLayer = await this.getEMSFileLayer();
|
||||
// @ts-ignore
|
||||
const fields = emsFileLayer.getFieldsInLanguage();
|
||||
// @ts-ignore
|
||||
return fields.map(f => this.createField({ fieldName: f.name }));
|
||||
}
|
||||
|
||||
|
@ -142,16 +170,17 @@ export class EMSFileSource extends AbstractVectorSource {
|
|||
return this._tooltipFields.length > 0;
|
||||
}
|
||||
|
||||
async filterAndFormatPropertiesToHtml(properties) {
|
||||
const tooltipProperties = this._tooltipFields.map(field => {
|
||||
async filterAndFormatPropertiesToHtml(properties: unknown): Promise<ITooltipProperty[]> {
|
||||
const promises = this._tooltipFields.map(field => {
|
||||
// @ts-ignore
|
||||
const value = properties[field.getName()];
|
||||
return field.createTooltipProperty(value);
|
||||
});
|
||||
|
||||
return Promise.all(tooltipProperties);
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
async getSupportedShapeTypes() {
|
||||
async getSupportedShapeTypes(): Promise<VECTOR_SHAPE_TYPES[]> {
|
||||
return [VECTOR_SHAPE_TYPES.POLYGON];
|
||||
}
|
||||
}
|
|
@ -5,4 +5,4 @@
|
|||
*/
|
||||
|
||||
export { emsBoundariesLayerWizardConfig } from './ems_boundaries_layer_wizard';
|
||||
export { EMSFileSource } from './ems_file_source';
|
||||
export { EMSFileSource, IEmsFileSource } from './ems_file_source';
|
|
@ -5,18 +5,28 @@
|
|||
*/
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { TooltipSelector } from '../../../components/tooltip_selector';
|
||||
import { getEMSClient } from '../../../meta';
|
||||
import { EuiTitle, EuiPanel, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { TooltipSelector } from '../../../components/tooltip_selector';
|
||||
// @ts-ignore
|
||||
import { getEMSClient } from '../../../meta';
|
||||
import { IEmsFileSource } from './ems_file_source';
|
||||
import { IField } from '../../fields/field';
|
||||
import { OnSourceChangeArgs } from '../../../connected_components/layer_panel/view';
|
||||
|
||||
export class UpdateSourceEditor extends Component {
|
||||
static propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
tooltipFields: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
source: PropTypes.object,
|
||||
};
|
||||
interface Props {
|
||||
layerId: string;
|
||||
onChange: (args: OnSourceChangeArgs) => void;
|
||||
source: IEmsFileSource;
|
||||
tooltipFields: IField[];
|
||||
}
|
||||
|
||||
interface State {
|
||||
fields: IField[] | null;
|
||||
}
|
||||
|
||||
export class UpdateSourceEditor extends Component<Props, State> {
|
||||
private _isMounted: boolean = false;
|
||||
|
||||
state = {
|
||||
fields: null,
|
||||
|
@ -34,23 +44,29 @@ export class UpdateSourceEditor extends Component {
|
|||
async loadFields() {
|
||||
let fields;
|
||||
try {
|
||||
// @ts-ignore
|
||||
const emsClient = getEMSClient();
|
||||
// @ts-ignore
|
||||
const emsFiles = await emsClient.getFileLayers();
|
||||
const emsFile = emsFiles.find(emsFile => emsFile.getId() === this.props.layerId);
|
||||
const emsFields = emsFile.getFieldsInLanguage();
|
||||
// @ts-ignore
|
||||
const taregetEmsFile = emsFiles.find(emsFile => emsFile.getId() === this.props.layerId);
|
||||
// @ts-ignore
|
||||
const emsFields = taregetEmsFile.getFieldsInLanguage();
|
||||
// @ts-ignore
|
||||
fields = emsFields.map(field => this.props.source.createField({ fieldName: field.name }));
|
||||
} catch (e) {
|
||||
//swallow this error. when a matching EMS-config cannot be found, the source already will have thrown errors during the data request. This will propagate to the vector-layer and be displayed in the UX
|
||||
// When a matching EMS-config cannot be found, the source already will have thrown errors during the data request.
|
||||
// This will propagate to the vector-layer and be displayed in the UX
|
||||
fields = [];
|
||||
}
|
||||
|
||||
if (this._isMounted) {
|
||||
this.setState({ fields: fields });
|
||||
this.setState({ fields });
|
||||
}
|
||||
}
|
||||
|
||||
_onTooltipPropertiesSelect = propertyNames => {
|
||||
this.props.onChange({ propName: 'tooltipProperties', value: propertyNames });
|
||||
_onTooltipPropertiesSelect = (selectedFieldNames: string[]) => {
|
||||
this.props.onChange({ propName: 'tooltipProperties', value: selectedFieldNames });
|
||||
};
|
||||
|
||||
render() {
|
|
@ -4,10 +4,10 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { getInjectedVarFunc } from '../../kibana_services';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getInjectedVarFunc } from '../../kibana_services';
|
||||
|
||||
export function getEmsUnavailableMessage() {
|
||||
export function getEmsUnavailableMessage(): string {
|
||||
const isEmsEnabled = getInjectedVarFunc()('isEmsEnabled', true);
|
||||
if (isEmsEnabled) {
|
||||
return i18n.translate('xpack.maps.source.ems.noAccessDescription', {
|
|
@ -20,6 +20,7 @@ import {
|
|||
VectorSourceSyncMeta,
|
||||
} from '../../../../common/descriptor_types';
|
||||
import { MVTSingleLayerVectorSourceConfig } from './mvt_single_layer_vector_source_editor';
|
||||
import { ITooltipProperty } from '../../tooltips/tooltip_property';
|
||||
|
||||
export const sourceTitle = i18n.translate(
|
||||
'xpack.maps.source.MVTSingleLayerVectorSource.sourceTitle',
|
||||
|
@ -152,6 +153,10 @@ export class MVTSingleLayerVectorSource extends AbstractSource
|
|||
getApplyGlobalQuery(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
async filterAndFormatPropertiesToHtml(properties: unknown): Promise<ITooltipProperty[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
registerSource({
|
||||
|
|
|
@ -16,10 +16,16 @@ import { copyPersistentState } from '../../reducers/util';
|
|||
import { SourceDescriptor } from '../../../common/descriptor_types';
|
||||
import { IField } from '../fields/field';
|
||||
import { MAX_ZOOM, MIN_ZOOM } from '../../../common/constants';
|
||||
import { OnSourceChangeArgs } from '../../connected_components/layer_panel/view';
|
||||
|
||||
export type SourceEditorArgs = {
|
||||
onChange: (args: OnSourceChangeArgs) => void;
|
||||
};
|
||||
|
||||
export type ImmutableSourceProperty = {
|
||||
label: string;
|
||||
value: string;
|
||||
link?: string;
|
||||
};
|
||||
|
||||
export type Attribution = {
|
||||
|
@ -48,7 +54,7 @@ export interface ISource {
|
|||
getImmutableProperties(): Promise<ImmutableSourceProperty[]>;
|
||||
getAttributions(): Promise<Attribution[]>;
|
||||
isESSource(): boolean;
|
||||
renderSourceSettingsEditor({ onChange }: { onChange: () => void }): ReactElement<any> | null;
|
||||
renderSourceSettingsEditor({ onChange }: SourceEditorArgs): ReactElement<any> | null;
|
||||
supportsFitToBounds(): Promise<boolean>;
|
||||
isJoinable(): boolean;
|
||||
cloneDescriptor(): SourceDescriptor;
|
||||
|
@ -124,7 +130,7 @@ export class AbstractSource implements ISource {
|
|||
return [];
|
||||
}
|
||||
|
||||
renderSourceSettingsEditor() {
|
||||
renderSourceSettingsEditor({ onChange }: SourceEditorArgs): ReactElement<any> | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
VectorSourceSyncMeta,
|
||||
} from '../../../../common/descriptor_types';
|
||||
import { VECTOR_SHAPE_TYPES } from '../vector_feature_types';
|
||||
import { ITooltipProperty } from '../../tooltips/tooltip_property';
|
||||
|
||||
export type GeoJsonFetchMeta = ESSearchSourceResponseMeta;
|
||||
|
||||
|
@ -24,6 +25,7 @@ export type GeoJsonWithMeta = {
|
|||
};
|
||||
|
||||
export interface IVectorSource extends ISource {
|
||||
filterAndFormatPropertiesToHtml(properties: unknown): Promise<ITooltipProperty[]>;
|
||||
getBoundsForFilters(searchFilters: VectorSourceRequestMeta): MapExtent;
|
||||
getGeoJsonWithMeta(
|
||||
layerName: 'string',
|
||||
|
@ -39,6 +41,7 @@ export interface IVectorSource extends ISource {
|
|||
}
|
||||
|
||||
export class AbstractVectorSource extends AbstractSource implements IVectorSource {
|
||||
filterAndFormatPropertiesToHtml(properties: unknown): Promise<ITooltipProperty[]>;
|
||||
getBoundsForFilters(searchFilters: VectorSourceRequestMeta): MapExtent;
|
||||
getGeoJsonWithMeta(
|
||||
layerName: 'string',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue