mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Maps] move joins from LayerDescriptor to VectorLayerDescriptor (#112427)
* [Maps] move joins from LayerDescriptor to VectorLayerDescriptor * clean up ISource * export isVectorLayer * tslint * tslint for ml plugin * tslint apm plugin Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
11f1c44bde
commit
15846b27c0
25 changed files with 321 additions and 258 deletions
|
@ -15,6 +15,7 @@ import {
|
||||||
COLOR_MAP_TYPE,
|
COLOR_MAP_TYPE,
|
||||||
FIELD_ORIGIN,
|
FIELD_ORIGIN,
|
||||||
LABEL_BORDER_SIZES,
|
LABEL_BORDER_SIZES,
|
||||||
|
LAYER_TYPE,
|
||||||
SOURCE_TYPES,
|
SOURCE_TYPES,
|
||||||
STYLE_TYPE,
|
STYLE_TYPE,
|
||||||
SYMBOLIZE_AS_TYPES,
|
SYMBOLIZE_AS_TYPES,
|
||||||
|
@ -154,7 +155,7 @@ export function useLayerList() {
|
||||||
maxZoom: 24,
|
maxZoom: 24,
|
||||||
alpha: 0.75,
|
alpha: 0.75,
|
||||||
visible: true,
|
visible: true,
|
||||||
type: 'VECTOR',
|
type: LAYER_TYPE.VECTOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
ES_TERM_SOURCE_REGION.whereQuery = getWhereQuery(serviceName!);
|
ES_TERM_SOURCE_REGION.whereQuery = getWhereQuery(serviceName!);
|
||||||
|
@ -178,7 +179,7 @@ export function useLayerList() {
|
||||||
maxZoom: 24,
|
maxZoom: 24,
|
||||||
alpha: 0.75,
|
alpha: 0.75,
|
||||||
visible: true,
|
visible: true,
|
||||||
type: 'VECTOR',
|
type: LAYER_TYPE.VECTOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n';
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
import {
|
import {
|
||||||
FIELD_ORIGIN,
|
FIELD_ORIGIN,
|
||||||
|
LAYER_TYPE,
|
||||||
SOURCE_TYPES,
|
SOURCE_TYPES,
|
||||||
STYLE_TYPE,
|
STYLE_TYPE,
|
||||||
COLOR_MAP_TYPE,
|
COLOR_MAP_TYPE,
|
||||||
|
@ -85,7 +86,7 @@ export const getChoroplethTopValuesLayer = (
|
||||||
},
|
},
|
||||||
isTimeAware: true,
|
isTimeAware: true,
|
||||||
},
|
},
|
||||||
type: 'VECTOR',
|
type: LAYER_TYPE.VECTOR,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
KBN_IS_TILE_COMPLETE,
|
KBN_IS_TILE_COMPLETE,
|
||||||
KBN_METADATA_FEATURE,
|
KBN_METADATA_FEATURE,
|
||||||
KBN_VECTOR_SHAPE_TYPE_COUNTS,
|
KBN_VECTOR_SHAPE_TYPE_COUNTS,
|
||||||
|
LAYER_TYPE,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
|
|
||||||
export type Attribution = {
|
export type Attribution = {
|
||||||
|
@ -56,7 +57,6 @@ export type LayerDescriptor = {
|
||||||
alpha?: number;
|
alpha?: number;
|
||||||
attribution?: Attribution;
|
attribution?: Attribution;
|
||||||
id: string;
|
id: string;
|
||||||
joins?: JoinDescriptor[];
|
|
||||||
label?: string | null;
|
label?: string | null;
|
||||||
areLabelsOnTop?: boolean;
|
areLabelsOnTop?: boolean;
|
||||||
minZoom?: number;
|
minZoom?: number;
|
||||||
|
@ -70,9 +70,12 @@ export type LayerDescriptor = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VectorLayerDescriptor = LayerDescriptor & {
|
export type VectorLayerDescriptor = LayerDescriptor & {
|
||||||
|
type: LAYER_TYPE.VECTOR | LAYER_TYPE.TILED_VECTOR | LAYER_TYPE.BLENDED_VECTOR;
|
||||||
|
joins?: JoinDescriptor[];
|
||||||
style: VectorStyleDescriptor;
|
style: VectorStyleDescriptor;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HeatmapLayerDescriptor = LayerDescriptor & {
|
export type HeatmapLayerDescriptor = LayerDescriptor & {
|
||||||
|
type: LAYER_TYPE.HEATMAP;
|
||||||
style: HeatmapStyleDescriptor;
|
style: HeatmapStyleDescriptor;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@ export {
|
||||||
FIELD_ORIGIN,
|
FIELD_ORIGIN,
|
||||||
INITIAL_LOCATION,
|
INITIAL_LOCATION,
|
||||||
LABEL_BORDER_SIZES,
|
LABEL_BORDER_SIZES,
|
||||||
|
LAYER_TYPE,
|
||||||
MAP_SAVED_OBJECT_TYPE,
|
MAP_SAVED_OBJECT_TYPE,
|
||||||
SOURCE_TYPES,
|
SOURCE_TYPES,
|
||||||
STYLE_TYPE,
|
STYLE_TYPE,
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MapSavedObjectAttributes } from '../map_saved_object_type';
|
import { MapSavedObjectAttributes } from '../map_saved_object_type';
|
||||||
import { JoinDescriptor, LayerDescriptor } from '../descriptor_types';
|
import { JoinDescriptor, LayerDescriptor, VectorLayerDescriptor } from '../descriptor_types';
|
||||||
import { LAYER_TYPE, SOURCE_TYPES } from '../constants';
|
import { SOURCE_TYPES } from '../constants';
|
||||||
|
|
||||||
// enforce type property on joins. It's possible older saved-objects do not have this correctly filled in
|
// enforce type property on joins. It's possible older saved-objects do not have this correctly filled in
|
||||||
// e.g. sample-data was missing the right.type field.
|
// e.g. sample-data was missing the right.type field.
|
||||||
|
@ -24,14 +24,15 @@ export function addTypeToTermJoin({
|
||||||
const layerList: LayerDescriptor[] = JSON.parse(attributes.layerListJSON);
|
const layerList: LayerDescriptor[] = JSON.parse(attributes.layerListJSON);
|
||||||
|
|
||||||
layerList.forEach((layer: LayerDescriptor) => {
|
layerList.forEach((layer: LayerDescriptor) => {
|
||||||
if (layer.type !== LAYER_TYPE.VECTOR) {
|
if (!('joins' in layer)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!layer.joins) {
|
const vectorLayer = layer as VectorLayerDescriptor;
|
||||||
|
if (!vectorLayer.joins) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
layer.joins.forEach((join: JoinDescriptor) => {
|
vectorLayer.joins.forEach((join: JoinDescriptor) => {
|
||||||
if (!join.right) {
|
if (!join.right) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
import { SavedObjectReference } from '../../../../../src/core/types';
|
import { SavedObjectReference } from '../../../../../src/core/types';
|
||||||
import { MapSavedObjectAttributes } from '../map_saved_object_type';
|
import { MapSavedObjectAttributes } from '../map_saved_object_type';
|
||||||
import { LayerDescriptor } from '../descriptor_types';
|
import { LayerDescriptor, VectorLayerDescriptor } from '../descriptor_types';
|
||||||
|
|
||||||
interface IndexPatternReferenceDescriptor {
|
interface IndexPatternReferenceDescriptor {
|
||||||
indexPatternId?: string;
|
indexPatternId?: string;
|
||||||
|
@ -44,21 +44,24 @@ export function extractReferences({
|
||||||
sourceDescriptor.indexPatternRefName = refName;
|
sourceDescriptor.indexPatternRefName = refName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract index-pattern references from join
|
if ('joins' in layer) {
|
||||||
const joins = layer.joins ? layer.joins : [];
|
// Extract index-pattern references from join
|
||||||
joins.forEach((join, joinIndex) => {
|
const vectorLayer = layer as VectorLayerDescriptor;
|
||||||
if ('indexPatternId' in join.right) {
|
const joins = vectorLayer.joins ? vectorLayer.joins : [];
|
||||||
const sourceDescriptor = join.right as IndexPatternReferenceDescriptor;
|
joins.forEach((join, joinIndex) => {
|
||||||
const refName = `layer_${layerIndex}_join_${joinIndex}_index_pattern`;
|
if ('indexPatternId' in join.right) {
|
||||||
extractedReferences.push({
|
const sourceDescriptor = join.right as IndexPatternReferenceDescriptor;
|
||||||
name: refName,
|
const refName = `layer_${layerIndex}_join_${joinIndex}_index_pattern`;
|
||||||
type: 'index-pattern',
|
extractedReferences.push({
|
||||||
id: sourceDescriptor.indexPatternId!,
|
name: refName,
|
||||||
});
|
type: 'index-pattern',
|
||||||
delete sourceDescriptor.indexPatternId;
|
id: sourceDescriptor.indexPatternId!,
|
||||||
sourceDescriptor.indexPatternRefName = refName;
|
});
|
||||||
}
|
delete sourceDescriptor.indexPatternId;
|
||||||
});
|
sourceDescriptor.indexPatternRefName = refName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -99,16 +102,19 @@ export function injectReferences({
|
||||||
delete sourceDescriptor.indexPatternRefName;
|
delete sourceDescriptor.indexPatternRefName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject index-pattern references into join
|
if ('joins' in layer) {
|
||||||
const joins = layer.joins ? layer.joins : [];
|
// Inject index-pattern references into join
|
||||||
joins.forEach((join) => {
|
const vectorLayer = layer as VectorLayerDescriptor;
|
||||||
if ('indexPatternRefName' in join.right) {
|
const joins = vectorLayer.joins ? vectorLayer.joins : [];
|
||||||
const sourceDescriptor = join.right as IndexPatternReferenceDescriptor;
|
joins.forEach((join) => {
|
||||||
const reference = findReference(sourceDescriptor.indexPatternRefName!, references);
|
if ('indexPatternRefName' in join.right) {
|
||||||
sourceDescriptor.indexPatternId = reference.id;
|
const sourceDescriptor = join.right as IndexPatternReferenceDescriptor;
|
||||||
delete sourceDescriptor.indexPatternRefName;
|
const reference = findReference(sourceDescriptor.indexPatternRefName!, references);
|
||||||
}
|
sourceDescriptor.indexPatternId = reference.id;
|
||||||
});
|
delete sourceDescriptor.indexPatternRefName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -33,7 +33,6 @@ import {
|
||||||
SizeDynamicOptions,
|
SizeDynamicOptions,
|
||||||
DynamicStylePropertyOptions,
|
DynamicStylePropertyOptions,
|
||||||
StylePropertyOptions,
|
StylePropertyOptions,
|
||||||
LayerDescriptor,
|
|
||||||
Timeslice,
|
Timeslice,
|
||||||
VectorLayerDescriptor,
|
VectorLayerDescriptor,
|
||||||
VectorSourceRequestMeta,
|
VectorSourceRequestMeta,
|
||||||
|
@ -179,7 +178,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
|
||||||
mapColors: string[]
|
mapColors: string[]
|
||||||
): VectorLayerDescriptor {
|
): VectorLayerDescriptor {
|
||||||
const layerDescriptor = VectorLayer.createDescriptor(options, mapColors);
|
const layerDescriptor = VectorLayer.createDescriptor(options, mapColors);
|
||||||
layerDescriptor.type = BlendedVectorLayer.type;
|
layerDescriptor.type = LAYER_TYPE.BLENDED_VECTOR;
|
||||||
return layerDescriptor;
|
return layerDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +255,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async cloneDescriptor(): Promise<LayerDescriptor> {
|
async cloneDescriptor(): Promise<VectorLayerDescriptor> {
|
||||||
const clonedDescriptor = await super.cloneDescriptor();
|
const clonedDescriptor = await super.cloneDescriptor();
|
||||||
|
|
||||||
// Use super getDisplayName instead of instance getDisplayName to avoid getting 'Clustered Clone of Clustered'
|
// Use super getDisplayName instead of instance getDisplayName to avoid getting 'Clustered Clone of Clustered'
|
||||||
|
|
|
@ -9,21 +9,6 @@
|
||||||
|
|
||||||
import { AbstractLayer } from './layer';
|
import { AbstractLayer } from './layer';
|
||||||
import { ISource } from '../sources/source';
|
import { ISource } from '../sources/source';
|
||||||
import {
|
|
||||||
AGG_TYPE,
|
|
||||||
FIELD_ORIGIN,
|
|
||||||
LAYER_STYLE_TYPE,
|
|
||||||
SOURCE_TYPES,
|
|
||||||
VECTOR_STYLES,
|
|
||||||
} from '../../../common/constants';
|
|
||||||
import { ESTermSourceDescriptor, VectorStyleDescriptor } from '../../../common/descriptor_types';
|
|
||||||
import { getDefaultDynamicProperties } from '../styles/vector/vector_style_defaults';
|
|
||||||
|
|
||||||
jest.mock('uuid/v4', () => {
|
|
||||||
return function () {
|
|
||||||
return '12345';
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
class MockLayer extends AbstractLayer {}
|
class MockLayer extends AbstractLayer {}
|
||||||
|
|
||||||
|
@ -36,111 +21,11 @@ class MockSource {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
getDisplayName() {
|
|
||||||
return 'mySource';
|
|
||||||
}
|
|
||||||
|
|
||||||
async supportsFitToBounds() {
|
async supportsFitToBounds() {
|
||||||
return this._fitToBounds;
|
return this._fitToBounds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('cloneDescriptor', () => {
|
|
||||||
describe('with joins', () => {
|
|
||||||
const styleDescriptor = {
|
|
||||||
type: LAYER_STYLE_TYPE.VECTOR,
|
|
||||||
properties: {
|
|
||||||
...getDefaultDynamicProperties(),
|
|
||||||
},
|
|
||||||
} as VectorStyleDescriptor;
|
|
||||||
// @ts-expect-error
|
|
||||||
styleDescriptor.properties[VECTOR_STYLES.FILL_COLOR].options.field = {
|
|
||||||
name: '__kbnjoin__count__557d0f15',
|
|
||||||
origin: FIELD_ORIGIN.JOIN,
|
|
||||||
};
|
|
||||||
// @ts-expect-error
|
|
||||||
styleDescriptor.properties[VECTOR_STYLES.LINE_COLOR].options.field = {
|
|
||||||
name: 'bytes',
|
|
||||||
origin: FIELD_ORIGIN.SOURCE,
|
|
||||||
};
|
|
||||||
// @ts-expect-error
|
|
||||||
styleDescriptor.properties[VECTOR_STYLES.LABEL_BORDER_COLOR].options.field = {
|
|
||||||
name: '__kbnjoin__count__6666666666',
|
|
||||||
origin: FIELD_ORIGIN.JOIN,
|
|
||||||
};
|
|
||||||
|
|
||||||
test('Should update data driven styling properties using join fields', async () => {
|
|
||||||
const layerDescriptor = AbstractLayer.createDescriptor({
|
|
||||||
style: styleDescriptor,
|
|
||||||
joins: [
|
|
||||||
{
|
|
||||||
leftField: 'iso2',
|
|
||||||
right: {
|
|
||||||
id: '557d0f15',
|
|
||||||
indexPatternId: 'myIndexPattern',
|
|
||||||
indexPatternTitle: 'logs-*',
|
|
||||||
metrics: [{ type: AGG_TYPE.COUNT }],
|
|
||||||
term: 'myTermField',
|
|
||||||
type: SOURCE_TYPES.ES_TERM_SOURCE,
|
|
||||||
applyGlobalQuery: true,
|
|
||||||
applyGlobalTime: true,
|
|
||||||
applyForceRefresh: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
const layer = new MockLayer({
|
|
||||||
layerDescriptor,
|
|
||||||
source: new MockSource() as unknown as ISource,
|
|
||||||
});
|
|
||||||
const clonedDescriptor = await layer.cloneDescriptor();
|
|
||||||
const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties;
|
|
||||||
// Should update style field belonging to join
|
|
||||||
// @ts-expect-error
|
|
||||||
expect(clonedStyleProps[VECTOR_STYLES.FILL_COLOR].options.field.name).toEqual(
|
|
||||||
'__kbnjoin__count__12345'
|
|
||||||
);
|
|
||||||
// Should not update style field belonging to source
|
|
||||||
// @ts-expect-error
|
|
||||||
expect(clonedStyleProps[VECTOR_STYLES.LINE_COLOR].options.field.name).toEqual('bytes');
|
|
||||||
// Should not update style feild belonging to different join
|
|
||||||
// @ts-expect-error
|
|
||||||
expect(clonedStyleProps[VECTOR_STYLES.LABEL_BORDER_COLOR].options.field.name).toEqual(
|
|
||||||
'__kbnjoin__count__6666666666'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should update data driven styling properties using join fields when metrics are not provided', async () => {
|
|
||||||
const layerDescriptor = AbstractLayer.createDescriptor({
|
|
||||||
style: styleDescriptor,
|
|
||||||
joins: [
|
|
||||||
{
|
|
||||||
leftField: 'iso2',
|
|
||||||
right: {
|
|
||||||
id: '557d0f15',
|
|
||||||
indexPatternId: 'myIndexPattern',
|
|
||||||
indexPatternTitle: 'logs-*',
|
|
||||||
term: 'myTermField',
|
|
||||||
type: 'joinSource',
|
|
||||||
} as unknown as ESTermSourceDescriptor,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
const layer = new MockLayer({
|
|
||||||
layerDescriptor,
|
|
||||||
source: new MockSource() as unknown as ISource,
|
|
||||||
});
|
|
||||||
const clonedDescriptor = await layer.cloneDescriptor();
|
|
||||||
const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties;
|
|
||||||
// Should update style field belonging to join
|
|
||||||
// @ts-expect-error
|
|
||||||
expect(clonedStyleProps[VECTOR_STYLES.FILL_COLOR].options.field.name).toEqual(
|
|
||||||
'__kbnjoin__count__12345'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isFittable', () => {
|
describe('isFittable', () => {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,23 +16,16 @@ import uuid from 'uuid/v4';
|
||||||
import { FeatureCollection } from 'geojson';
|
import { FeatureCollection } from 'geojson';
|
||||||
import { DataRequest } from '../util/data_request';
|
import { DataRequest } from '../util/data_request';
|
||||||
import {
|
import {
|
||||||
AGG_TYPE,
|
|
||||||
FIELD_ORIGIN,
|
|
||||||
LAYER_TYPE,
|
LAYER_TYPE,
|
||||||
MAX_ZOOM,
|
MAX_ZOOM,
|
||||||
MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER,
|
MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER,
|
||||||
MIN_ZOOM,
|
MIN_ZOOM,
|
||||||
SOURCE_BOUNDS_DATA_REQUEST_ID,
|
SOURCE_BOUNDS_DATA_REQUEST_ID,
|
||||||
SOURCE_DATA_REQUEST_ID,
|
SOURCE_DATA_REQUEST_ID,
|
||||||
SOURCE_TYPES,
|
|
||||||
STYLE_TYPE,
|
|
||||||
} from '../../../common/constants';
|
} from '../../../common/constants';
|
||||||
import { copyPersistentState } from '../../reducers/copy_persistent_state';
|
import { copyPersistentState } from '../../reducers/copy_persistent_state';
|
||||||
import {
|
import {
|
||||||
AggDescriptor,
|
|
||||||
Attribution,
|
Attribution,
|
||||||
ESTermSourceDescriptor,
|
|
||||||
JoinDescriptor,
|
|
||||||
LayerDescriptor,
|
LayerDescriptor,
|
||||||
MapExtent,
|
MapExtent,
|
||||||
StyleDescriptor,
|
StyleDescriptor,
|
||||||
|
@ -42,7 +35,6 @@ import {
|
||||||
import { ImmutableSourceProperty, ISource, SourceEditorArgs } from '../sources/source';
|
import { ImmutableSourceProperty, ISource, SourceEditorArgs } from '../sources/source';
|
||||||
import { DataRequestContext } from '../../actions';
|
import { DataRequestContext } from '../../actions';
|
||||||
import { IStyle } from '../styles/style';
|
import { IStyle } from '../styles/style';
|
||||||
import { getJoinAggKey } from '../../../common/get_agg_key';
|
|
||||||
import { LICENSED_FEATURES } from '../../licensed_features';
|
import { LICENSED_FEATURES } from '../../licensed_features';
|
||||||
import { IESSource } from '../sources/es_source';
|
import { IESSource } from '../sources/es_source';
|
||||||
|
|
||||||
|
@ -97,8 +89,6 @@ export interface ILayer {
|
||||||
isPreviewLayer: () => boolean;
|
isPreviewLayer: () => boolean;
|
||||||
areLabelsOnTop: () => boolean;
|
areLabelsOnTop: () => boolean;
|
||||||
supportsLabelsOnTop: () => boolean;
|
supportsLabelsOnTop: () => boolean;
|
||||||
showJoinEditor(): boolean;
|
|
||||||
getJoinsDisabledReason(): string | null;
|
|
||||||
isFittable(): Promise<boolean>;
|
isFittable(): Promise<boolean>;
|
||||||
isIncludeInFitToBounds(): boolean;
|
isIncludeInFitToBounds(): boolean;
|
||||||
getLicensedFeatures(): Promise<LICENSED_FEATURES[]>;
|
getLicensedFeatures(): Promise<LICENSED_FEATURES[]>;
|
||||||
|
@ -177,56 +167,6 @@ export class AbstractLayer implements ILayer {
|
||||||
const displayName = await this.getDisplayName();
|
const displayName = await this.getDisplayName();
|
||||||
clonedDescriptor.label = `Clone of ${displayName}`;
|
clonedDescriptor.label = `Clone of ${displayName}`;
|
||||||
clonedDescriptor.sourceDescriptor = this.getSource().cloneDescriptor();
|
clonedDescriptor.sourceDescriptor = this.getSource().cloneDescriptor();
|
||||||
|
|
||||||
if (clonedDescriptor.joins) {
|
|
||||||
clonedDescriptor.joins.forEach((joinDescriptor: JoinDescriptor) => {
|
|
||||||
if (joinDescriptor.right && joinDescriptor.right.type === SOURCE_TYPES.TABLE_SOURCE) {
|
|
||||||
throw new Error(
|
|
||||||
'Cannot clone table-source. Should only be used in MapEmbeddable, not in UX'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const termSourceDescriptor: ESTermSourceDescriptor =
|
|
||||||
joinDescriptor.right as ESTermSourceDescriptor;
|
|
||||||
|
|
||||||
// todo: must tie this to generic thing
|
|
||||||
const originalJoinId = joinDescriptor.right.id!;
|
|
||||||
|
|
||||||
// right.id is uuid used to track requests in inspector
|
|
||||||
joinDescriptor.right.id = uuid();
|
|
||||||
|
|
||||||
// Update all data driven styling properties using join fields
|
|
||||||
if (clonedDescriptor.style && 'properties' in clonedDescriptor.style) {
|
|
||||||
const metrics =
|
|
||||||
termSourceDescriptor.metrics && termSourceDescriptor.metrics.length
|
|
||||||
? termSourceDescriptor.metrics
|
|
||||||
: [{ type: AGG_TYPE.COUNT }];
|
|
||||||
metrics.forEach((metricsDescriptor: AggDescriptor) => {
|
|
||||||
const originalJoinKey = getJoinAggKey({
|
|
||||||
aggType: metricsDescriptor.type,
|
|
||||||
aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '',
|
|
||||||
rightSourceId: originalJoinId,
|
|
||||||
});
|
|
||||||
const newJoinKey = getJoinAggKey({
|
|
||||||
aggType: metricsDescriptor.type,
|
|
||||||
aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '',
|
|
||||||
rightSourceId: joinDescriptor.right.id!,
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.keys(clonedDescriptor.style.properties).forEach((key) => {
|
|
||||||
const styleProp = clonedDescriptor.style.properties[key];
|
|
||||||
if (
|
|
||||||
styleProp.type === STYLE_TYPE.DYNAMIC &&
|
|
||||||
styleProp.options.field &&
|
|
||||||
styleProp.options.field.origin === FIELD_ORIGIN.JOIN &&
|
|
||||||
styleProp.options.field.name === originalJoinKey
|
|
||||||
) {
|
|
||||||
styleProp.options.field.name = newJoinKey;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return clonedDescriptor;
|
return clonedDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,14 +174,6 @@ export class AbstractLayer implements ILayer {
|
||||||
return `${this.getId()}${MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER}${layerNameSuffix}`;
|
return `${this.getId()}${MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER}${layerNameSuffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
showJoinEditor(): boolean {
|
|
||||||
return this.getSource().showJoinEditor();
|
|
||||||
}
|
|
||||||
|
|
||||||
getJoinsDisabledReason() {
|
|
||||||
return this.getSource().getJoinsDisabledReason();
|
|
||||||
}
|
|
||||||
|
|
||||||
isPreviewLayer(): boolean {
|
isPreviewLayer(): boolean {
|
||||||
return !!this._descriptor.__isPreviewLayer;
|
return !!this._descriptor.__isPreviewLayer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ export class TiledVectorLayer extends VectorLayer {
|
||||||
mapColors?: string[]
|
mapColors?: string[]
|
||||||
): VectorLayerDescriptor {
|
): VectorLayerDescriptor {
|
||||||
const layerDescriptor = super.createDescriptor(descriptor, mapColors);
|
const layerDescriptor = super.createDescriptor(descriptor, mapColors);
|
||||||
layerDescriptor.type = TiledVectorLayer.type;
|
layerDescriptor.type = LAYER_TYPE.TILED_VECTOR;
|
||||||
|
|
||||||
if (!layerDescriptor.style) {
|
if (!layerDescriptor.style) {
|
||||||
const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors ? mapColors : []);
|
const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors ? mapColors : []);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
export { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from './utils';
|
export { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from './utils';
|
||||||
export {
|
export {
|
||||||
|
isVectorLayer,
|
||||||
IVectorLayer,
|
IVectorLayer,
|
||||||
VectorLayer,
|
VectorLayer,
|
||||||
VectorLayerArguments,
|
VectorLayerArguments,
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable max-classes-per-file */
|
||||||
|
|
||||||
|
jest.mock('../../styles/vector/vector_style', () => ({
|
||||||
|
VectorStyle: class MockVectorStyle {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('uuid/v4', () => {
|
||||||
|
return function () {
|
||||||
|
return '12345';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
import {
|
||||||
|
AGG_TYPE,
|
||||||
|
FIELD_ORIGIN,
|
||||||
|
LAYER_STYLE_TYPE,
|
||||||
|
SOURCE_TYPES,
|
||||||
|
VECTOR_STYLES,
|
||||||
|
} from '../../../../common/constants';
|
||||||
|
import { ESTermSourceDescriptor, VectorStyleDescriptor } from '../../../../common/descriptor_types';
|
||||||
|
import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults';
|
||||||
|
import { IVectorSource } from '../../sources/vector_source';
|
||||||
|
import { VectorLayer } from './vector_layer';
|
||||||
|
|
||||||
|
class MockSource {
|
||||||
|
cloneDescriptor() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName() {
|
||||||
|
return 'mySource';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('cloneDescriptor', () => {
|
||||||
|
describe('with joins', () => {
|
||||||
|
const styleDescriptor = {
|
||||||
|
type: LAYER_STYLE_TYPE.VECTOR,
|
||||||
|
properties: {
|
||||||
|
...getDefaultDynamicProperties(),
|
||||||
|
},
|
||||||
|
} as VectorStyleDescriptor;
|
||||||
|
// @ts-expect-error
|
||||||
|
styleDescriptor.properties[VECTOR_STYLES.FILL_COLOR].options.field = {
|
||||||
|
name: '__kbnjoin__count__557d0f15',
|
||||||
|
origin: FIELD_ORIGIN.JOIN,
|
||||||
|
};
|
||||||
|
// @ts-expect-error
|
||||||
|
styleDescriptor.properties[VECTOR_STYLES.LINE_COLOR].options.field = {
|
||||||
|
name: 'bytes',
|
||||||
|
origin: FIELD_ORIGIN.SOURCE,
|
||||||
|
};
|
||||||
|
// @ts-expect-error
|
||||||
|
styleDescriptor.properties[VECTOR_STYLES.LABEL_BORDER_COLOR].options.field = {
|
||||||
|
name: '__kbnjoin__count__6666666666',
|
||||||
|
origin: FIELD_ORIGIN.JOIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
test('Should update data driven styling properties using join fields', async () => {
|
||||||
|
const layerDescriptor = VectorLayer.createDescriptor({
|
||||||
|
style: styleDescriptor,
|
||||||
|
joins: [
|
||||||
|
{
|
||||||
|
leftField: 'iso2',
|
||||||
|
right: {
|
||||||
|
id: '557d0f15',
|
||||||
|
indexPatternId: 'myIndexPattern',
|
||||||
|
indexPatternTitle: 'logs-*',
|
||||||
|
metrics: [{ type: AGG_TYPE.COUNT }],
|
||||||
|
term: 'myTermField',
|
||||||
|
type: SOURCE_TYPES.ES_TERM_SOURCE,
|
||||||
|
applyGlobalQuery: true,
|
||||||
|
applyGlobalTime: true,
|
||||||
|
applyForceRefresh: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const layer = new VectorLayer({
|
||||||
|
layerDescriptor,
|
||||||
|
source: new MockSource() as unknown as IVectorSource,
|
||||||
|
});
|
||||||
|
const clonedDescriptor = await layer.cloneDescriptor();
|
||||||
|
const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties;
|
||||||
|
// Should update style field belonging to join
|
||||||
|
// @ts-expect-error
|
||||||
|
expect(clonedStyleProps[VECTOR_STYLES.FILL_COLOR].options.field.name).toEqual(
|
||||||
|
'__kbnjoin__count__12345'
|
||||||
|
);
|
||||||
|
// Should not update style field belonging to source
|
||||||
|
// @ts-expect-error
|
||||||
|
expect(clonedStyleProps[VECTOR_STYLES.LINE_COLOR].options.field.name).toEqual('bytes');
|
||||||
|
// Should not update style feild belonging to different join
|
||||||
|
// @ts-expect-error
|
||||||
|
expect(clonedStyleProps[VECTOR_STYLES.LABEL_BORDER_COLOR].options.field.name).toEqual(
|
||||||
|
'__kbnjoin__count__6666666666'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should update data driven styling properties using join fields when metrics are not provided', async () => {
|
||||||
|
const layerDescriptor = VectorLayer.createDescriptor({
|
||||||
|
style: styleDescriptor,
|
||||||
|
joins: [
|
||||||
|
{
|
||||||
|
leftField: 'iso2',
|
||||||
|
right: {
|
||||||
|
id: '557d0f15',
|
||||||
|
indexPatternId: 'myIndexPattern',
|
||||||
|
indexPatternTitle: 'logs-*',
|
||||||
|
term: 'myTermField',
|
||||||
|
type: 'joinSource',
|
||||||
|
} as unknown as ESTermSourceDescriptor,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const layer = new VectorLayer({
|
||||||
|
layerDescriptor,
|
||||||
|
source: new MockSource() as unknown as IVectorSource,
|
||||||
|
});
|
||||||
|
const clonedDescriptor = await layer.cloneDescriptor();
|
||||||
|
const clonedStyleProps = (clonedDescriptor.style as VectorStyleDescriptor).properties;
|
||||||
|
// Should update style field belonging to join
|
||||||
|
// @ts-expect-error
|
||||||
|
expect(clonedStyleProps[VECTOR_STYLES.FILL_COLOR].options.field.name).toEqual(
|
||||||
|
'__kbnjoin__count__12345'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import uuid from 'uuid/v4';
|
||||||
import type {
|
import type {
|
||||||
Map as MbMap,
|
Map as MbMap,
|
||||||
AnyLayer as MbLayer,
|
AnyLayer as MbLayer,
|
||||||
|
@ -19,6 +20,7 @@ import { i18n } from '@kbn/i18n';
|
||||||
import { AbstractLayer } from '../layer';
|
import { AbstractLayer } from '../layer';
|
||||||
import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style';
|
import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style';
|
||||||
import {
|
import {
|
||||||
|
AGG_TYPE,
|
||||||
FEATURE_ID_PROPERTY_NAME,
|
FEATURE_ID_PROPERTY_NAME,
|
||||||
SOURCE_META_DATA_REQUEST_ID,
|
SOURCE_META_DATA_REQUEST_ID,
|
||||||
SOURCE_FORMATTERS_DATA_REQUEST_ID,
|
SOURCE_FORMATTERS_DATA_REQUEST_ID,
|
||||||
|
@ -29,8 +31,11 @@ import {
|
||||||
FIELD_ORIGIN,
|
FIELD_ORIGIN,
|
||||||
KBN_TOO_MANY_FEATURES_IMAGE_ID,
|
KBN_TOO_MANY_FEATURES_IMAGE_ID,
|
||||||
FieldFormatter,
|
FieldFormatter,
|
||||||
|
SOURCE_TYPES,
|
||||||
|
STYLE_TYPE,
|
||||||
SUPPORTS_FEATURE_EDITING_REQUEST_ID,
|
SUPPORTS_FEATURE_EDITING_REQUEST_ID,
|
||||||
KBN_IS_TILE_COMPLETE,
|
KBN_IS_TILE_COMPLETE,
|
||||||
|
VECTOR_STYLES,
|
||||||
} from '../../../../common/constants';
|
} from '../../../../common/constants';
|
||||||
import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property';
|
import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property';
|
||||||
import { DataRequestAbortError } from '../../util/data_request';
|
import { DataRequestAbortError } from '../../util/data_request';
|
||||||
|
@ -48,8 +53,11 @@ import {
|
||||||
TimesliceMaskConfig,
|
TimesliceMaskConfig,
|
||||||
} from '../../util/mb_filter_expressions';
|
} from '../../util/mb_filter_expressions';
|
||||||
import {
|
import {
|
||||||
|
AggDescriptor,
|
||||||
DynamicStylePropertyOptions,
|
DynamicStylePropertyOptions,
|
||||||
DataFilters,
|
DataFilters,
|
||||||
|
ESTermSourceDescriptor,
|
||||||
|
JoinDescriptor,
|
||||||
StyleMetaDescriptor,
|
StyleMetaDescriptor,
|
||||||
Timeslice,
|
Timeslice,
|
||||||
VectorLayerDescriptor,
|
VectorLayerDescriptor,
|
||||||
|
@ -71,6 +79,11 @@ import { ITermJoinSource } from '../../sources/term_join_source';
|
||||||
import { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from './utils';
|
import { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from './utils';
|
||||||
import { JoinState, performInnerJoins } from './perform_inner_joins';
|
import { JoinState, performInnerJoins } from './perform_inner_joins';
|
||||||
import { buildVectorRequestMeta } from '../build_vector_request_meta';
|
import { buildVectorRequestMeta } from '../build_vector_request_meta';
|
||||||
|
import { getJoinAggKey } from '../../../../common/get_agg_key';
|
||||||
|
|
||||||
|
export function isVectorLayer(layer: ILayer) {
|
||||||
|
return (layer as IVectorLayer).canShowTooltip !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export interface VectorLayerArguments {
|
export interface VectorLayerArguments {
|
||||||
source: IVectorSource;
|
source: IVectorSource;
|
||||||
|
@ -83,11 +96,13 @@ export interface IVectorLayer extends ILayer {
|
||||||
getFields(): Promise<IField[]>;
|
getFields(): Promise<IField[]>;
|
||||||
getStyleEditorFields(): Promise<IField[]>;
|
getStyleEditorFields(): Promise<IField[]>;
|
||||||
getJoins(): InnerJoin[];
|
getJoins(): InnerJoin[];
|
||||||
|
getJoinsDisabledReason(): string | null;
|
||||||
getValidJoins(): InnerJoin[];
|
getValidJoins(): InnerJoin[];
|
||||||
getSource(): IVectorSource;
|
getSource(): IVectorSource;
|
||||||
getFeatureById(id: string | number): Feature | null;
|
getFeatureById(id: string | number): Feature | null;
|
||||||
getPropertiesForTooltip(properties: GeoJsonProperties): Promise<ITooltipProperty[]>;
|
getPropertiesForTooltip(properties: GeoJsonProperties): Promise<ITooltipProperty[]>;
|
||||||
hasJoins(): boolean;
|
hasJoins(): boolean;
|
||||||
|
showJoinEditor(): boolean;
|
||||||
canShowTooltip(): boolean;
|
canShowTooltip(): boolean;
|
||||||
supportsFeatureEditing(): boolean;
|
supportsFeatureEditing(): boolean;
|
||||||
getLeftJoinFields(): Promise<IField[]>;
|
getLeftJoinFields(): Promise<IField[]>;
|
||||||
|
@ -113,8 +128,8 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
||||||
options: Partial<VectorLayerDescriptor>,
|
options: Partial<VectorLayerDescriptor>,
|
||||||
mapColors?: string[]
|
mapColors?: string[]
|
||||||
): VectorLayerDescriptor {
|
): VectorLayerDescriptor {
|
||||||
const layerDescriptor = super.createDescriptor(options);
|
const layerDescriptor = super.createDescriptor(options) as VectorLayerDescriptor;
|
||||||
layerDescriptor.type = VectorLayer.type;
|
layerDescriptor.type = LAYER_TYPE.VECTOR;
|
||||||
|
|
||||||
if (!options.style) {
|
if (!options.style) {
|
||||||
const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors ? mapColors : []);
|
const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors ? mapColors : []);
|
||||||
|
@ -125,7 +140,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
||||||
layerDescriptor.joins = [];
|
layerDescriptor.joins = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return layerDescriptor as VectorLayerDescriptor;
|
return layerDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
|
@ -147,6 +162,62 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async cloneDescriptor(): Promise<VectorLayerDescriptor> {
|
||||||
|
const clonedDescriptor = (await super.cloneDescriptor()) as VectorLayerDescriptor;
|
||||||
|
if (clonedDescriptor.joins) {
|
||||||
|
clonedDescriptor.joins.forEach((joinDescriptor: JoinDescriptor) => {
|
||||||
|
if (joinDescriptor.right && joinDescriptor.right.type === SOURCE_TYPES.TABLE_SOURCE) {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot clone table-source. Should only be used in MapEmbeddable, not in UX'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const termSourceDescriptor: ESTermSourceDescriptor =
|
||||||
|
joinDescriptor.right as ESTermSourceDescriptor;
|
||||||
|
|
||||||
|
// todo: must tie this to generic thing
|
||||||
|
const originalJoinId = joinDescriptor.right.id!;
|
||||||
|
|
||||||
|
// right.id is uuid used to track requests in inspector
|
||||||
|
joinDescriptor.right.id = uuid();
|
||||||
|
|
||||||
|
// Update all data driven styling properties using join fields
|
||||||
|
if (clonedDescriptor.style && 'properties' in clonedDescriptor.style) {
|
||||||
|
const metrics =
|
||||||
|
termSourceDescriptor.metrics && termSourceDescriptor.metrics.length
|
||||||
|
? termSourceDescriptor.metrics
|
||||||
|
: [{ type: AGG_TYPE.COUNT }];
|
||||||
|
metrics.forEach((metricsDescriptor: AggDescriptor) => {
|
||||||
|
const originalJoinKey = getJoinAggKey({
|
||||||
|
aggType: metricsDescriptor.type,
|
||||||
|
aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '',
|
||||||
|
rightSourceId: originalJoinId,
|
||||||
|
});
|
||||||
|
const newJoinKey = getJoinAggKey({
|
||||||
|
aggType: metricsDescriptor.type,
|
||||||
|
aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '',
|
||||||
|
rightSourceId: joinDescriptor.right.id!,
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(clonedDescriptor.style.properties).forEach((key) => {
|
||||||
|
const styleProp = clonedDescriptor.style.properties[key as VECTOR_STYLES];
|
||||||
|
if ('type' in styleProp && styleProp.type === STYLE_TYPE.DYNAMIC) {
|
||||||
|
const options = styleProp.options as DynamicStylePropertyOptions;
|
||||||
|
if (
|
||||||
|
options.field &&
|
||||||
|
options.field.origin === FIELD_ORIGIN.JOIN &&
|
||||||
|
options.field.name === originalJoinKey
|
||||||
|
) {
|
||||||
|
options.field.name = newJoinKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return clonedDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
getSource(): IVectorSource {
|
getSource(): IVectorSource {
|
||||||
return super.getSource() as IVectorSource;
|
return super.getSource() as IVectorSource;
|
||||||
}
|
}
|
||||||
|
@ -176,6 +247,10 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
||||||
return this._joins.slice();
|
return this._joins.slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getJoinsDisabledReason() {
|
||||||
|
return this.getSource().getJoinsDisabledReason();
|
||||||
|
}
|
||||||
|
|
||||||
getValidJoins() {
|
getValidJoins() {
|
||||||
return this.getJoins().filter((join) => {
|
return this.getJoins().filter((join) => {
|
||||||
return join.hasCompleteConfig();
|
return join.hasCompleteConfig();
|
||||||
|
@ -192,6 +267,10 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
||||||
return this.getValidJoins().length > 0;
|
return this.getValidJoins().length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showJoinEditor(): boolean {
|
||||||
|
return this.getSource().showJoinEditor();
|
||||||
|
}
|
||||||
|
|
||||||
isInitialDataLoadComplete() {
|
isInitialDataLoadComplete() {
|
||||||
const sourceDataRequest = this.getSourceDataRequest();
|
const sourceDataRequest = this.getSourceDataRequest();
|
||||||
if (!sourceDataRequest || !sourceDataRequest.hasData()) {
|
if (!sourceDataRequest || !sourceDataRequest.hasData()) {
|
||||||
|
|
|
@ -243,6 +243,14 @@ export class MVTSingleLayerVectorSource
|
||||||
async getDefaultFields(): Promise<Record<string, Record<string, string>>> {
|
async getDefaultFields(): Promise<Record<string, Record<string, string>>> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showJoinEditor(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getJoinsDisabledReason(): string | null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerSource({
|
registerSource({
|
||||||
|
|
|
@ -53,8 +53,6 @@ export interface ISource {
|
||||||
isESSource(): boolean;
|
isESSource(): boolean;
|
||||||
renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs): ReactElement<any> | null;
|
renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs): ReactElement<any> | null;
|
||||||
supportsFitToBounds(): Promise<boolean>;
|
supportsFitToBounds(): Promise<boolean>;
|
||||||
showJoinEditor(): boolean;
|
|
||||||
getJoinsDisabledReason(): string | null;
|
|
||||||
cloneDescriptor(): AbstractSourceDescriptor;
|
cloneDescriptor(): AbstractSourceDescriptor;
|
||||||
getFieldNames(): string[];
|
getFieldNames(): string[];
|
||||||
getApplyGlobalQuery(): boolean;
|
getApplyGlobalQuery(): boolean;
|
||||||
|
@ -155,14 +153,6 @@ export class AbstractSource implements ISource {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
showJoinEditor(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getJoinsDisabledReason(): string | null {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
isESSource(): boolean {
|
isESSource(): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ export interface IVectorSource extends ISource {
|
||||||
getFields(): Promise<IField[]>;
|
getFields(): Promise<IField[]>;
|
||||||
getFieldByName(fieldName: string): IField | null;
|
getFieldByName(fieldName: string): IField | null;
|
||||||
getLeftJoinFields(): Promise<IField[]>;
|
getLeftJoinFields(): Promise<IField[]>;
|
||||||
|
showJoinEditor(): boolean;
|
||||||
|
getJoinsDisabledReason(): string | null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Vector layer avoids unnecessarily re-fetching source data.
|
* Vector layer avoids unnecessarily re-fetching source data.
|
||||||
|
@ -122,6 +124,10 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getJoinsDisabledReason(): string | null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
async getGeoJsonWithMeta(
|
async getGeoJsonWithMeta(
|
||||||
layerName: string,
|
layerName: string,
|
||||||
searchFilters: VectorSourceRequestMeta,
|
searchFilters: VectorSourceRequestMeta,
|
||||||
|
|
|
@ -93,6 +93,7 @@ exports[`EditLayerPanel is rendered 1`] = `
|
||||||
<LayerSettings
|
<LayerSettings
|
||||||
layer={
|
layer={
|
||||||
Object {
|
Object {
|
||||||
|
"canShowTooltip": [Function],
|
||||||
"getDisplayName": [Function],
|
"getDisplayName": [Function],
|
||||||
"getId": [Function],
|
"getId": [Function],
|
||||||
"getImmutableSourceProperties": [Function],
|
"getImmutableSourceProperties": [Function],
|
||||||
|
@ -113,6 +114,7 @@ exports[`EditLayerPanel is rendered 1`] = `
|
||||||
<JoinEditor
|
<JoinEditor
|
||||||
layer={
|
layer={
|
||||||
Object {
|
Object {
|
||||||
|
"canShowTooltip": [Function],
|
||||||
"getDisplayName": [Function],
|
"getDisplayName": [Function],
|
||||||
"getId": [Function],
|
"getId": [Function],
|
||||||
"getImmutableSourceProperties": [Function],
|
"getImmutableSourceProperties": [Function],
|
||||||
|
|
|
@ -64,6 +64,9 @@ const mockLayer = {
|
||||||
showJoinEditor: () => {
|
showJoinEditor: () => {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
canShowTooltip: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
supportsElasticsearchFilters: () => {
|
supportsElasticsearchFilters: () => {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,7 +33,7 @@ import { Storage } from '../../../../../../src/plugins/kibana_utils/public';
|
||||||
import { LAYER_TYPE } from '../../../common/constants';
|
import { LAYER_TYPE } from '../../../common/constants';
|
||||||
import { getData, getCore } from '../../kibana_services';
|
import { getData, getCore } from '../../kibana_services';
|
||||||
import { ILayer } from '../../classes/layers/layer';
|
import { ILayer } from '../../classes/layers/layer';
|
||||||
import { IVectorLayer } from '../../classes/layers/vector_layer';
|
import { isVectorLayer, IVectorLayer } from '../../classes/layers/vector_layer';
|
||||||
import { ImmutableSourceProperty, OnSourceChangeArgs } from '../../classes/sources/source';
|
import { ImmutableSourceProperty, OnSourceChangeArgs } from '../../classes/sources/source';
|
||||||
import { IField } from '../../classes/fields/field';
|
import { IField } from '../../classes/fields/field';
|
||||||
|
|
||||||
|
@ -111,11 +111,12 @@ export class EditLayerPanel extends Component<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
async _loadLeftJoinFields() {
|
async _loadLeftJoinFields() {
|
||||||
if (
|
if (!this.props.selectedLayer || !isVectorLayer(this.props.selectedLayer)) {
|
||||||
!this.props.selectedLayer ||
|
return;
|
||||||
!this.props.selectedLayer.showJoinEditor() ||
|
}
|
||||||
(this.props.selectedLayer as IVectorLayer).getLeftJoinFields === undefined
|
|
||||||
) {
|
const vectorLayer = this.props.selectedLayer as IVectorLayer;
|
||||||
|
if (!vectorLayer.showJoinEditor() || vectorLayer.getLeftJoinFields === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +183,11 @@ export class EditLayerPanel extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderJoinSection() {
|
_renderJoinSection() {
|
||||||
if (!this.props.selectedLayer || !this.props.selectedLayer.showJoinEditor()) {
|
if (!this.props.selectedLayer || !isVectorLayer(this.props.selectedLayer)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const vectorLayer = this.props.selectedLayer as IVectorLayer;
|
||||||
|
if (!vectorLayer.showJoinEditor()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +195,7 @@ export class EditLayerPanel extends Component<Props, State> {
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<EuiPanel>
|
<EuiPanel>
|
||||||
<JoinEditor
|
<JoinEditor
|
||||||
layer={this.props.selectedLayer}
|
layer={vectorLayer}
|
||||||
leftJoinFields={this.state.leftJoinFields}
|
leftJoinFields={this.state.leftJoinFields}
|
||||||
layerDisplayName={this.state.displayName}
|
layerDisplayName={this.state.displayName}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -13,11 +13,18 @@ import { LAYER_TYPE } from '../../../common/constants';
|
||||||
import { getSelectedLayer } from '../../selectors/map_selectors';
|
import { getSelectedLayer } from '../../selectors/map_selectors';
|
||||||
import { updateSourceProp } from '../../actions';
|
import { updateSourceProp } from '../../actions';
|
||||||
import { MapStoreState } from '../../reducers/store';
|
import { MapStoreState } from '../../reducers/store';
|
||||||
|
import { isVectorLayer, IVectorLayer } from '../../classes/layers/vector_layer';
|
||||||
|
|
||||||
function mapStateToProps(state: MapStoreState) {
|
function mapStateToProps(state: MapStoreState) {
|
||||||
const selectedLayer = getSelectedLayer(state);
|
const selectedLayer = getSelectedLayer(state);
|
||||||
|
let key = 'none';
|
||||||
|
if (selectedLayer) {
|
||||||
|
key = isVectorLayer(selectedLayer)
|
||||||
|
? `${selectedLayer.getId()}${(selectedLayer as IVectorLayer).showJoinEditor()}`
|
||||||
|
: selectedLayer.getId();
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
key: selectedLayer ? `${selectedLayer.getId()}${selectedLayer.showJoinEditor()}` : '',
|
key,
|
||||||
selectedLayer,
|
selectedLayer,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ILayer } from '../../../classes/layers/layer';
|
import { IVectorLayer } from '../../../classes/layers/vector_layer';
|
||||||
import { JoinEditor } from './join_editor';
|
import { JoinEditor } from './join_editor';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { JoinDescriptor } from '../../../../common/descriptor_types';
|
import { JoinDescriptor } from '../../../../common/descriptor_types';
|
||||||
|
@ -48,7 +48,7 @@ const defaultProps = {
|
||||||
|
|
||||||
test('Should render join editor', () => {
|
test('Should render join editor', () => {
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<JoinEditor {...defaultProps} layer={new MockLayer(null) as unknown as ILayer} />
|
<JoinEditor {...defaultProps} layer={new MockLayer(null) as unknown as IVectorLayer} />
|
||||||
);
|
);
|
||||||
expect(component).toMatchSnapshot();
|
expect(component).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -57,7 +57,7 @@ test('Should render callout when joins are disabled', () => {
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<JoinEditor
|
<JoinEditor
|
||||||
{...defaultProps}
|
{...defaultProps}
|
||||||
layer={new MockLayer('Simulated disabled reason') as unknown as ILayer}
|
layer={new MockLayer('Simulated disabled reason') as unknown as IVectorLayer}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(component).toMatchSnapshot();
|
expect(component).toMatchSnapshot();
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { Join } from './resources/join';
|
import { Join } from './resources/join';
|
||||||
import { ILayer } from '../../../classes/layers/layer';
|
import { IVectorLayer } from '../../../classes/layers/vector_layer';
|
||||||
import { JoinDescriptor } from '../../../../common/descriptor_types';
|
import { JoinDescriptor } from '../../../../common/descriptor_types';
|
||||||
import { SOURCE_TYPES } from '../../../../common/constants';
|
import { SOURCE_TYPES } from '../../../../common/constants';
|
||||||
|
|
||||||
|
@ -31,10 +31,10 @@ export interface JoinField {
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
joins: JoinDescriptor[];
|
joins: JoinDescriptor[];
|
||||||
layer: ILayer;
|
layer: IVectorLayer;
|
||||||
layerDisplayName: string;
|
layerDisplayName: string;
|
||||||
leftJoinFields: JoinField[];
|
leftJoinFields: JoinField[];
|
||||||
onChange: (layer: ILayer, joins: JoinDescriptor[]) => void;
|
onChange: (layer: IVectorLayer, joins: JoinDescriptor[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function JoinEditor({ joins, layer, onChange, leftJoinFields, layerDisplayName }: Props) {
|
export function JoinEditor({ joins, layer, onChange, leftJoinFields, layerDisplayName }: Props) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ import { TooltipPopover } from './tooltip_popover';
|
||||||
import { FeatureGeometryFilterForm } from './features_tooltip';
|
import { FeatureGeometryFilterForm } from './features_tooltip';
|
||||||
import { EXCLUDE_TOO_MANY_FEATURES_BOX } from '../../../classes/util/mb_filter_expressions';
|
import { EXCLUDE_TOO_MANY_FEATURES_BOX } from '../../../classes/util/mb_filter_expressions';
|
||||||
import { ILayer } from '../../../classes/layers/layer';
|
import { ILayer } from '../../../classes/layers/layer';
|
||||||
import { IVectorLayer } from '../../../classes/layers/vector_layer';
|
import { IVectorLayer, isVectorLayer } from '../../../classes/layers/vector_layer';
|
||||||
import { RenderToolTipContent } from '../../../classes/tooltips/tooltip_property';
|
import { RenderToolTipContent } from '../../../classes/tooltips/tooltip_property';
|
||||||
|
|
||||||
function justifyAnchorLocation(
|
function justifyAnchorLocation(
|
||||||
|
@ -58,10 +58,6 @@ function justifyAnchorLocation(
|
||||||
return popupAnchorLocation;
|
return popupAnchorLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVectorLayer(layer: ILayer) {
|
|
||||||
return (layer as IVectorLayer).canShowTooltip !== undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
addFilters: ((filters: Filter[], actionId: string) => Promise<void>) | null;
|
addFilters: ((filters: Filter[], actionId: string) => Promise<void>) | null;
|
||||||
closeOnClickTooltip: (tooltipId: string) => void;
|
closeOnClickTooltip: (tooltipId: string) => void;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
ESGeoGridSourceDescriptor,
|
ESGeoGridSourceDescriptor,
|
||||||
ESSearchSourceDescriptor,
|
ESSearchSourceDescriptor,
|
||||||
LayerDescriptor,
|
LayerDescriptor,
|
||||||
|
VectorLayerDescriptor,
|
||||||
} from '../../common/descriptor_types';
|
} from '../../common/descriptor_types';
|
||||||
import {
|
import {
|
||||||
GRID_RESOLUTION,
|
GRID_RESOLUTION,
|
||||||
|
@ -265,8 +266,7 @@ export function getTermJoinsPerCluster(
|
||||||
): TELEMETRY_TERM_JOIN_COUNTS_PER_CLUSTER {
|
): TELEMETRY_TERM_JOIN_COUNTS_PER_CLUSTER {
|
||||||
return getCountsByCluster(layerLists, (layerDescriptor: LayerDescriptor) => {
|
return getCountsByCluster(layerLists, (layerDescriptor: LayerDescriptor) => {
|
||||||
return layerDescriptor.type === LAYER_TYPE.VECTOR &&
|
return layerDescriptor.type === LAYER_TYPE.VECTOR &&
|
||||||
layerDescriptor.joins &&
|
(layerDescriptor as VectorLayerDescriptor)?.joins?.length
|
||||||
layerDescriptor.joins.length
|
|
||||||
? TELEMETRY_TERM_JOIN
|
? TELEMETRY_TERM_JOIN
|
||||||
: null;
|
: null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import {
|
import {
|
||||||
FIELD_ORIGIN,
|
FIELD_ORIGIN,
|
||||||
|
LAYER_TYPE,
|
||||||
SOURCE_TYPES,
|
SOURCE_TYPES,
|
||||||
STYLE_TYPE,
|
STYLE_TYPE,
|
||||||
COLOR_MAP_TYPE,
|
COLOR_MAP_TYPE,
|
||||||
|
@ -125,7 +126,7 @@ export const getChoroplethAnomaliesLayer = (
|
||||||
isTimeAware: true,
|
isTimeAware: true,
|
||||||
},
|
},
|
||||||
visible: false,
|
visible: false,
|
||||||
type: 'VECTOR',
|
type: LAYER_TYPE.VECTOR,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue