[Maps] fix data-mapping switch enabled for vector tiles (#116366)
* clean up IField API * disable switch when using MVTs for es docs * clean up interface comment style * implement supportsFieldMetaFromEs and supportsFieldMetaFromLocalData in all Field classes * fix dynamic_color_property test * fix jest tests * mock getRangeFieldMeta instead of passing in VectorLayerMock with MockStyle * review feedback * clean up supportsFieldMetaFromLocalData test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
d284d65ad4
commit
ee61368cff
|
@ -17,25 +17,48 @@ const defaultParams = {
|
|||
origin: FIELD_ORIGIN.SOURCE,
|
||||
};
|
||||
|
||||
describe('supportsFieldMeta', () => {
|
||||
test('Non-counting aggregations should support field meta', () => {
|
||||
describe('supportsFieldMetaFromEs', () => {
|
||||
test('Non-counting aggregations should support field meta from ES', () => {
|
||||
const avgMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.AVG });
|
||||
expect(avgMetric.supportsFieldMeta()).toBe(true);
|
||||
expect(avgMetric.supportsFieldMetaFromEs()).toBe(true);
|
||||
const maxMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.MAX });
|
||||
expect(maxMetric.supportsFieldMeta()).toBe(true);
|
||||
expect(maxMetric.supportsFieldMetaFromEs()).toBe(true);
|
||||
const minMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.MIN });
|
||||
expect(minMetric.supportsFieldMeta()).toBe(true);
|
||||
expect(minMetric.supportsFieldMetaFromEs()).toBe(true);
|
||||
const termsMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.TERMS });
|
||||
expect(termsMetric.supportsFieldMeta()).toBe(true);
|
||||
expect(termsMetric.supportsFieldMetaFromEs()).toBe(true);
|
||||
});
|
||||
|
||||
test('Counting aggregations should not support field meta', () => {
|
||||
test('Counting aggregations should not support field meta from ES', () => {
|
||||
const sumMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.SUM });
|
||||
expect(sumMetric.supportsFieldMeta()).toBe(false);
|
||||
expect(sumMetric.supportsFieldMetaFromEs()).toBe(false);
|
||||
const uniqueCountMetric = new AggField({
|
||||
...defaultParams,
|
||||
aggType: AGG_TYPE.UNIQUE_COUNT,
|
||||
});
|
||||
expect(uniqueCountMetric.supportsFieldMeta()).toBe(false);
|
||||
expect(uniqueCountMetric.supportsFieldMetaFromEs()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('supportsFieldMetaFromLocalData', () => {
|
||||
test('number metrics should support field meta from local', () => {
|
||||
const avgMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.AVG });
|
||||
expect(avgMetric.supportsFieldMetaFromLocalData()).toBe(true);
|
||||
const maxMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.MAX });
|
||||
expect(maxMetric.supportsFieldMetaFromLocalData()).toBe(true);
|
||||
const minMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.MIN });
|
||||
expect(minMetric.supportsFieldMetaFromLocalData()).toBe(true);
|
||||
const sumMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.SUM });
|
||||
expect(sumMetric.supportsFieldMetaFromLocalData()).toBe(true);
|
||||
const uniqueCountMetric = new AggField({
|
||||
...defaultParams,
|
||||
aggType: AGG_TYPE.UNIQUE_COUNT,
|
||||
});
|
||||
expect(uniqueCountMetric.supportsFieldMetaFromLocalData()).toBe(true);
|
||||
});
|
||||
|
||||
test('Non number metrics should not support field meta from local', () => {
|
||||
const termMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.TERMS });
|
||||
expect(termMetric.supportsFieldMetaFromLocalData()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -30,6 +30,16 @@ export class AggField extends CountAggField {
|
|||
this._aggType = params.aggType;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
// count and sum aggregations are not within field bounds so they do not support field meta.
|
||||
return !isMetricCountable(this._getAggType());
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
// Elasticsearch vector tile search API returns meta tiles with numeric aggregation metrics.
|
||||
return this._getDataTypeSynchronous() === 'number';
|
||||
}
|
||||
|
||||
isValid(): boolean {
|
||||
return !!this._esDocField;
|
||||
}
|
||||
|
@ -38,11 +48,6 @@ export class AggField extends CountAggField {
|
|||
return this._source.isMvt() ? this.getName() + '.value' : this.getName();
|
||||
}
|
||||
|
||||
supportsFieldMeta(): boolean {
|
||||
// count and sum aggregations are not within field bounds so they do not support field meta.
|
||||
return !isMetricCountable(this._getAggType());
|
||||
}
|
||||
|
||||
canValueBeFormatted(): boolean {
|
||||
return this._getAggType() !== AGG_TYPE.UNIQUE_COUNT;
|
||||
}
|
||||
|
@ -73,10 +78,14 @@ export class AggField extends CountAggField {
|
|||
);
|
||||
}
|
||||
|
||||
async getDataType(): Promise<string> {
|
||||
_getDataTypeSynchronous(): string {
|
||||
return this._getAggType() === AGG_TYPE.TERMS ? 'string' : 'number';
|
||||
}
|
||||
|
||||
async getDataType(): Promise<string> {
|
||||
return this._getDataTypeSynchronous();
|
||||
}
|
||||
|
||||
getBucketCount(): number {
|
||||
// terms aggregation increases the overall number of buckets per split bucket
|
||||
return this._getAggType() === AGG_TYPE.TERMS ? TERMS_AGG_SHARD_SIZE : 0;
|
||||
|
|
|
@ -19,5 +19,4 @@ export interface CountAggFieldParams {
|
|||
label?: string;
|
||||
source: IESAggSource;
|
||||
origin: FIELD_ORIGIN;
|
||||
canReadFromGeoJson?: boolean;
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ const defaultParams = {
|
|||
origin: FIELD_ORIGIN.SOURCE,
|
||||
};
|
||||
|
||||
describe('supportsFieldMeta', () => {
|
||||
describe('supportsFieldMetaFromEs', () => {
|
||||
test('Counting aggregations should not support field meta', () => {
|
||||
const countMetric = new CountAggField({ ...defaultParams });
|
||||
expect(countMetric.supportsFieldMeta()).toBe(false);
|
||||
expect(countMetric.supportsFieldMetaFromEs()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,13 +18,20 @@ export class CountAggField implements IESAggField {
|
|||
protected readonly _source: IESAggSource;
|
||||
private readonly _origin: FIELD_ORIGIN;
|
||||
protected readonly _label?: string;
|
||||
private readonly _canReadFromGeoJson: boolean;
|
||||
|
||||
constructor({ label, source, origin, canReadFromGeoJson = true }: CountAggFieldParams) {
|
||||
constructor({ label, source, origin }: CountAggFieldParams) {
|
||||
this._source = source;
|
||||
this._origin = origin;
|
||||
this._label = label;
|
||||
this._canReadFromGeoJson = canReadFromGeoJson;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
// Elasticsearch vector tile search API returns meta tiles for aggregation metrics
|
||||
return true;
|
||||
}
|
||||
|
||||
_getAggType(): AGG_TYPE {
|
||||
|
@ -79,10 +86,6 @@ export class CountAggField implements IESAggField {
|
|||
return null;
|
||||
}
|
||||
|
||||
supportsFieldMeta(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getBucketCount() {
|
||||
return 0;
|
||||
}
|
||||
|
@ -103,14 +106,6 @@ export class CountAggField implements IESAggField {
|
|||
return null;
|
||||
}
|
||||
|
||||
supportsAutoDomain(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
canReadFromGeoJson(): boolean {
|
||||
return this._canReadFromGeoJson;
|
||||
}
|
||||
|
||||
isEqual(field: IESAggField) {
|
||||
return field.getName() === this.getName();
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ import { PercentileAggField } from './percentile_agg_field';
|
|||
export function esAggFieldsFactory(
|
||||
aggDescriptor: AggDescriptor,
|
||||
source: IESAggSource,
|
||||
origin: FIELD_ORIGIN,
|
||||
canReadFromGeoJson: boolean = true
|
||||
origin: FIELD_ORIGIN
|
||||
): IESAggField[] {
|
||||
let aggField;
|
||||
if (aggDescriptor.type === AGG_TYPE.COUNT) {
|
||||
|
@ -27,7 +26,6 @@ export function esAggFieldsFactory(
|
|||
label: aggDescriptor.label,
|
||||
source,
|
||||
origin,
|
||||
canReadFromGeoJson,
|
||||
});
|
||||
} else if (aggDescriptor.type === AGG_TYPE.PERCENTILE) {
|
||||
aggField = new PercentileAggField({
|
||||
|
@ -42,7 +40,6 @@ export function esAggFieldsFactory(
|
|||
: DEFAULT_PERCENTILE,
|
||||
source,
|
||||
origin,
|
||||
canReadFromGeoJson,
|
||||
});
|
||||
} else {
|
||||
aggField = new AggField({
|
||||
|
@ -54,14 +51,13 @@ export function esAggFieldsFactory(
|
|||
aggType: aggDescriptor.type,
|
||||
source,
|
||||
origin,
|
||||
canReadFromGeoJson,
|
||||
});
|
||||
}
|
||||
|
||||
const aggFields: IESAggField[] = [aggField];
|
||||
|
||||
if ('field' in aggDescriptor && aggDescriptor.type === AGG_TYPE.TERMS) {
|
||||
aggFields.push(new TopTermPercentageField(aggField, canReadFromGeoJson));
|
||||
aggFields.push(new TopTermPercentageField(aggField));
|
||||
}
|
||||
|
||||
return aggFields;
|
||||
|
|
|
@ -31,7 +31,12 @@ export class PercentileAggField extends AggField implements IESAggField {
|
|||
this._percentile = params.percentile;
|
||||
}
|
||||
|
||||
supportsFieldMeta(): boolean {
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
// Elasticsearch vector tile search API returns meta tiles for aggregation metrics
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,18 @@ import { TOP_TERM_PERCENTAGE_SUFFIX, FIELD_ORIGIN } from '../../../../common/con
|
|||
|
||||
export class TopTermPercentageField implements IESAggField {
|
||||
private readonly _topTermAggField: IESAggField;
|
||||
private readonly _canReadFromGeoJson: boolean;
|
||||
|
||||
constructor(topTermAggField: IESAggField, canReadFromGeoJson: boolean = true) {
|
||||
constructor(topTermAggField: IESAggField) {
|
||||
this._topTermAggField = topTermAggField;
|
||||
this._canReadFromGeoJson = canReadFromGeoJson;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
// Elasticsearch vector tile search API does not support top term metric
|
||||
return false;
|
||||
}
|
||||
|
||||
getSource(): IVectorSource {
|
||||
|
@ -64,15 +71,6 @@ export class TopTermPercentageField implements IESAggField {
|
|||
getBucketCount(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
supportsAutoDomain(): boolean {
|
||||
return this._canReadFromGeoJson;
|
||||
}
|
||||
|
||||
supportsFieldMeta(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
async getExtendedStatsFieldMetaRequest(): Promise<unknown | null> {
|
||||
return null;
|
||||
}
|
||||
|
@ -89,10 +87,6 @@ export class TopTermPercentageField implements IESAggField {
|
|||
return false;
|
||||
}
|
||||
|
||||
canReadFromGeoJson(): boolean {
|
||||
return this._canReadFromGeoJson;
|
||||
}
|
||||
|
||||
isEqual(field: IESAggField) {
|
||||
return field.getName() === this.getName();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,14 @@ export class EMSFileField extends AbstractField implements IField {
|
|||
this._source = source;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
getSource(): IVectorSource {
|
||||
return this._source;
|
||||
}
|
||||
|
|
|
@ -16,22 +16,27 @@ import { IVectorSource } from '../sources/vector_source';
|
|||
|
||||
export class ESDocField extends AbstractField implements IField {
|
||||
private readonly _source: IESSource;
|
||||
private readonly _canReadFromGeoJson: boolean;
|
||||
|
||||
constructor({
|
||||
fieldName,
|
||||
source,
|
||||
origin,
|
||||
canReadFromGeoJson = true,
|
||||
}: {
|
||||
fieldName: string;
|
||||
source: IESSource;
|
||||
origin: FIELD_ORIGIN;
|
||||
canReadFromGeoJson?: boolean;
|
||||
}) {
|
||||
super({ fieldName, origin });
|
||||
this._source = source;
|
||||
this._canReadFromGeoJson = canReadFromGeoJson;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
// Elasticsearch vector tile search API does not return meta tiles for documents
|
||||
return !this.getSource().isMvt();
|
||||
}
|
||||
|
||||
canValueBeFormatted(): boolean {
|
||||
|
@ -73,14 +78,6 @@ export class ESDocField extends AbstractField implements IField {
|
|||
: super.getLabel();
|
||||
}
|
||||
|
||||
supportsFieldMeta(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
canReadFromGeoJson(): boolean {
|
||||
return this._canReadFromGeoJson;
|
||||
}
|
||||
|
||||
async getExtendedStatsFieldMetaRequest(): Promise<unknown | null> {
|
||||
const indexPatternField = await this._getIndexPatternField();
|
||||
|
||||
|
|
|
@ -22,19 +22,22 @@ export interface IField {
|
|||
isValid(): boolean;
|
||||
getExtendedStatsFieldMetaRequest(): Promise<unknown | null>;
|
||||
getPercentilesFieldMetaRequest(percentiles: number[]): Promise<unknown | null>;
|
||||
getCategoricalFieldMetaRequest(size: number): Promise<unknown>;
|
||||
getCategoricalFieldMetaRequest(size: number): Promise<unknown | null>;
|
||||
|
||||
// Whether Maps-app can automatically determine the domain of the field-values
|
||||
// if this is not the case (e.g. for .mvt tiled data),
|
||||
// then styling properties that require the domain to be known cannot use this property.
|
||||
supportsAutoDomain(): boolean;
|
||||
/*
|
||||
* IField.supportsFieldMetaFromLocalData returns boolean indicating whether field value domain
|
||||
* can be determined from local data
|
||||
*/
|
||||
supportsFieldMetaFromLocalData(): boolean;
|
||||
|
||||
// Whether Maps-app can automatically determine the domain of the field-values
|
||||
// _without_ having to retrieve the data as GeoJson
|
||||
// e.g. for ES-sources, this would use the extended_stats API
|
||||
supportsFieldMeta(): boolean;
|
||||
/*
|
||||
* IField.supportsFieldMetaFromEs returns boolean indicating whether field value domain
|
||||
* can be determined from Elasticsearch.
|
||||
* When true, getExtendedStatsFieldMetaRequest, getPercentilesFieldMetaRequest, and getCategoricalFieldMetaRequest
|
||||
* can not return null
|
||||
*/
|
||||
supportsFieldMetaFromEs(): boolean;
|
||||
|
||||
canReadFromGeoJson(): boolean;
|
||||
isEqual(field: IField): boolean;
|
||||
}
|
||||
|
||||
|
@ -47,6 +50,14 @@ export class AbstractField implements IField {
|
|||
this._origin = origin || FIELD_ORIGIN.SOURCE;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
throw new Error('must implement AbstractField#supportsFieldMetaFromEs');
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
throw new Error('must implement AbstractField#supportsFieldMetaFromLocalData');
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this._fieldName;
|
||||
}
|
||||
|
@ -64,7 +75,7 @@ export class AbstractField implements IField {
|
|||
}
|
||||
|
||||
getSource(): IVectorSource {
|
||||
throw new Error('must implement Field#getSource');
|
||||
throw new Error('must implement AbstractField#getSource');
|
||||
}
|
||||
|
||||
isValid(): boolean {
|
||||
|
@ -88,10 +99,6 @@ export class AbstractField implements IField {
|
|||
return this._origin;
|
||||
}
|
||||
|
||||
supportsFieldMeta(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
async getExtendedStatsFieldMetaRequest(): Promise<unknown> {
|
||||
return null;
|
||||
}
|
||||
|
@ -104,14 +111,6 @@ export class AbstractField implements IField {
|
|||
return null;
|
||||
}
|
||||
|
||||
supportsAutoDomain(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
canReadFromGeoJson(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
isEqual(field: IField) {
|
||||
return this._origin === field.getOrigin() && this._fieldName === field.getName();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,14 @@ export class InlineField<T extends IVectorSource> extends AbstractField implemen
|
|||
this._dataType = dataType;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
getSource(): IVectorSource {
|
||||
return this._source;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,14 @@ export class MVTField extends AbstractField implements IField {
|
|||
this._type = type;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getMVTFieldDescriptor(): MVTFieldDescriptor {
|
||||
return {
|
||||
type: this._type,
|
||||
|
@ -54,12 +62,4 @@ export class MVTField extends AbstractField implements IField {
|
|||
async getLabel(): Promise<string> {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
supportsAutoDomain() {
|
||||
return false;
|
||||
}
|
||||
|
||||
canReadFromGeoJson(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ export interface IESAggSource extends IESSource {
|
|||
|
||||
export abstract class AbstractESAggSource extends AbstractESSource implements IESAggSource {
|
||||
private readonly _metricFields: IESAggField[];
|
||||
private readonly _canReadFromGeoJson: boolean;
|
||||
|
||||
static createDescriptor(
|
||||
descriptor: Partial<AbstractESAggSourceDescriptor>
|
||||
|
@ -44,23 +43,13 @@ export abstract class AbstractESAggSource extends AbstractESSource implements IE
|
|||
};
|
||||
}
|
||||
|
||||
constructor(
|
||||
descriptor: AbstractESAggSourceDescriptor,
|
||||
inspectorAdapters?: Adapters,
|
||||
canReadFromGeoJson = true
|
||||
) {
|
||||
constructor(descriptor: AbstractESAggSourceDescriptor, inspectorAdapters?: Adapters) {
|
||||
super(descriptor, inspectorAdapters);
|
||||
this._metricFields = [];
|
||||
this._canReadFromGeoJson = canReadFromGeoJson;
|
||||
if (descriptor.metrics) {
|
||||
descriptor.metrics.forEach((aggDescriptor: AggDescriptor) => {
|
||||
this._metricFields.push(
|
||||
...esAggFieldsFactory(
|
||||
aggDescriptor,
|
||||
this,
|
||||
this.getOriginForField(),
|
||||
this._canReadFromGeoJson
|
||||
)
|
||||
...esAggFieldsFactory(aggDescriptor, this, this.getOriginForField())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -89,12 +78,7 @@ export abstract class AbstractESAggSource extends AbstractESSource implements IE
|
|||
const metrics = this._metricFields.filter((esAggField) => esAggField.isValid());
|
||||
// Handle case where metrics is empty because older saved object state is empty array or there are no valid aggs.
|
||||
return metrics.length === 0
|
||||
? esAggFieldsFactory(
|
||||
{ type: AGG_TYPE.COUNT },
|
||||
this,
|
||||
this.getOriginForField(),
|
||||
this._canReadFromGeoJson
|
||||
)
|
||||
? esAggFieldsFactory({ type: AGG_TYPE.COUNT }, this, this.getOriginForField())
|
||||
: metrics;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,11 +83,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle
|
|||
|
||||
constructor(descriptor: Partial<ESGeoGridSourceDescriptor>, inspectorAdapters?: Adapters) {
|
||||
const sourceDescriptor = ESGeoGridSource.createDescriptor(descriptor);
|
||||
super(
|
||||
sourceDescriptor,
|
||||
inspectorAdapters,
|
||||
descriptor.resolution !== GRID_RESOLUTION.SUPER_FINE
|
||||
);
|
||||
super(sourceDescriptor, inspectorAdapters);
|
||||
this._descriptor = sourceDescriptor;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ export class ESGeoLineSource extends AbstractESAggSource {
|
|||
|
||||
constructor(descriptor: Partial<ESGeoLineSourceDescriptor>, inspectorAdapters?: Adapters) {
|
||||
const sourceDescriptor = ESGeoLineSource.createDescriptor(descriptor);
|
||||
super(sourceDescriptor, inspectorAdapters, true);
|
||||
super(sourceDescriptor, inspectorAdapters);
|
||||
this._descriptor = sourceDescriptor;
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,6 @@ export class ESGeoLineSource extends AbstractESAggSource {
|
|||
fieldName: this._descriptor.splitField,
|
||||
source: this,
|
||||
origin: FIELD_ORIGIN.SOURCE,
|
||||
canReadFromGeoJson: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -152,20 +152,4 @@ describe('ESSearchSource', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFields', () => {
|
||||
it('default', () => {
|
||||
const esSearchSource = new ESSearchSource(mockDescriptor);
|
||||
const docField = esSearchSource.createField({ fieldName: 'prop1' });
|
||||
expect(docField.canReadFromGeoJson()).toBe(true);
|
||||
});
|
||||
it('mvt', () => {
|
||||
const esSearchSource = new ESSearchSource({
|
||||
...mockDescriptor,
|
||||
scalingType: SCALING_TYPES.MVT,
|
||||
});
|
||||
const docField = esSearchSource.createField({ fieldName: 'prop1' });
|
||||
expect(docField.canReadFromGeoJson()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -154,7 +154,6 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye
|
|||
fieldName,
|
||||
source: this,
|
||||
origin: FIELD_ORIGIN.SOURCE,
|
||||
canReadFromGeoJson: this._descriptor.scalingType !== SCALING_TYPES.MVT,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import { FieldMetaOptions } from '../../../../../../common/descriptor_types';
|
|||
interface Props<DynamicOptions> {
|
||||
fieldMetaOptions: FieldMetaOptions;
|
||||
onChange: (updatedOptions: DynamicOptions) => void;
|
||||
supportsFieldMetaFromLocalData: boolean;
|
||||
}
|
||||
|
||||
export function CategoricalDataMappingPopover<DynamicOptions>(props: Props<DynamicOptions>) {
|
||||
|
@ -38,6 +39,7 @@ export function CategoricalDataMappingPopover<DynamicOptions>(props: Props<Dynam
|
|||
})}
|
||||
checked={props.fieldMetaOptions.isEnabled}
|
||||
onChange={onIsEnabledChange}
|
||||
disabled={!props.supportsFieldMetaFromLocalData}
|
||||
compressed
|
||||
/>{' '}
|
||||
<EuiToolTip
|
||||
|
|
|
@ -81,6 +81,7 @@ interface Props<DynamicOptions> {
|
|||
onChange: (updatedOptions: DynamicOptions) => void;
|
||||
dataMappingFunction: DATA_MAPPING_FUNCTION;
|
||||
supportedDataMappingFunctions: DATA_MAPPING_FUNCTION[];
|
||||
supportsFieldMetaFromLocalData: boolean;
|
||||
}
|
||||
|
||||
export function OrdinalDataMappingPopover<DynamicOptions>(props: Props<DynamicOptions>) {
|
||||
|
@ -167,6 +168,7 @@ export function OrdinalDataMappingPopover<DynamicOptions>(props: Props<DynamicOp
|
|||
})}
|
||||
checked={props.fieldMetaOptions.isEnabled}
|
||||
onChange={onIsEnabledChange}
|
||||
disabled={!props.supportsFieldMetaFromLocalData}
|
||||
compressed
|
||||
/>{' '}
|
||||
<EuiToolTip
|
||||
|
|
|
@ -45,7 +45,7 @@ export function DynamicIconForm({
|
|||
{...styleOptions}
|
||||
styleProperty={styleProperty}
|
||||
onChange={onIconMapChange}
|
||||
isCustomOnly={!field.supportsAutoDomain()}
|
||||
isCustomOnly={!field.supportsFieldMetaFromLocalData() && !field.supportsFieldMetaFromEs()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,11 @@ jest.mock('../../../../kibana_services', () => {
|
|||
};
|
||||
});
|
||||
|
||||
class MockField extends AbstractField {}
|
||||
class MockField extends AbstractField {
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function createLayerMock(numFields: number, supportedShapeTypes: VECTOR_SHAPE_TYPE[]) {
|
||||
const fields: IField[] = [];
|
||||
|
|
|
@ -16,6 +16,7 @@ exports[`renderDataMappingPopover Should render OrdinalDataMappingPopover 1`] =
|
|||
"PERCENTILES",
|
||||
]
|
||||
}
|
||||
supportsFieldMetaFromLocalData={true}
|
||||
/>
|
||||
`;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import { Feature, Point } from 'geojson';
|
|||
import { DynamicColorProperty } from './dynamic_color_property';
|
||||
import {
|
||||
COLOR_MAP_TYPE,
|
||||
FIELD_ORIGIN,
|
||||
RawValue,
|
||||
DATA_MAPPING_FUNCTION,
|
||||
VECTOR_STYLES,
|
||||
|
@ -291,17 +292,27 @@ describe('supportsFieldMeta', () => {
|
|||
expect(styleProp.supportsFieldMeta()).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not support fieldMeta when field does not support fieldMeta', () => {
|
||||
const field = Object.create(mockField);
|
||||
field.supportsFieldMeta = function () {
|
||||
return false;
|
||||
test('should not support fieldMeta when field does not support fieldMeta from ES', () => {
|
||||
const field = {
|
||||
supportsFieldMetaFromEs() {
|
||||
return false;
|
||||
},
|
||||
} as unknown as IField;
|
||||
const layer = {} as unknown as IVectorLayer;
|
||||
const options = {
|
||||
type: COLOR_MAP_TYPE.ORDINAL,
|
||||
fieldMetaOptions: { isEnabled: true },
|
||||
};
|
||||
|
||||
const dynamicStyleOptions = {
|
||||
type: COLOR_MAP_TYPE.ORDINAL,
|
||||
fieldMetaOptions,
|
||||
};
|
||||
const styleProp = makeProperty(dynamicStyleOptions, undefined, field);
|
||||
const styleProp = new DynamicColorProperty(
|
||||
options,
|
||||
VECTOR_STYLES.LINE_COLOR,
|
||||
field,
|
||||
layer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
}
|
||||
);
|
||||
|
||||
expect(styleProp.supportsFieldMeta()).toEqual(false);
|
||||
});
|
||||
|
@ -382,12 +393,50 @@ describe('get mapbox color expression (via internal _getMbColor)', () => {
|
|||
expect(colorProperty._getMbColor()).toBeNull();
|
||||
});
|
||||
test('should return mapbox expression for color ramp', async () => {
|
||||
const dynamicStyleOptions = {
|
||||
const field = {
|
||||
getMbFieldName: () => {
|
||||
return 'foobar';
|
||||
},
|
||||
getName: () => {
|
||||
return 'foobar';
|
||||
},
|
||||
getOrigin: () => {
|
||||
return FIELD_ORIGIN.SOURCE;
|
||||
},
|
||||
supportsFieldMetaFromEs: () => {
|
||||
return true;
|
||||
},
|
||||
getSource: () => {
|
||||
return {
|
||||
isMvt: () => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
},
|
||||
} as unknown as IField;
|
||||
const options = {
|
||||
type: COLOR_MAP_TYPE.ORDINAL,
|
||||
color: 'Blues',
|
||||
fieldMetaOptions,
|
||||
fieldMetaOptions: { isEnabled: true },
|
||||
};
|
||||
const colorProperty = makeProperty(dynamicStyleOptions);
|
||||
|
||||
const colorProperty = new DynamicColorProperty(
|
||||
options,
|
||||
VECTOR_STYLES.LINE_COLOR,
|
||||
field,
|
||||
{} as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
}
|
||||
);
|
||||
colorProperty.getRangeFieldMeta = () => {
|
||||
return {
|
||||
min: 0,
|
||||
max: 100,
|
||||
delta: 100,
|
||||
};
|
||||
};
|
||||
|
||||
expect(colorProperty._getMbColor()).toEqual([
|
||||
'interpolate',
|
||||
['linear'],
|
||||
|
@ -445,17 +494,40 @@ describe('get mapbox color expression (via internal _getMbColor)', () => {
|
|||
expect(colorProperty._getMbColor()).toBeNull();
|
||||
});
|
||||
|
||||
test('should use `feature-state` by default', async () => {
|
||||
const dynamicStyleOptions = {
|
||||
test('should use `feature-state` for geojson source', async () => {
|
||||
const field = {
|
||||
getMbFieldName: () => {
|
||||
return 'foobar';
|
||||
},
|
||||
getSource: () => {
|
||||
return {
|
||||
isMvt: () => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
},
|
||||
} as unknown as IField;
|
||||
const layer = {} as unknown as IVectorLayer;
|
||||
const options = {
|
||||
type: COLOR_MAP_TYPE.ORDINAL,
|
||||
useCustomColorRamp: true,
|
||||
customColorRamp: [
|
||||
{ stop: 10, color: '#f7faff' },
|
||||
{ stop: 100, color: '#072f6b' },
|
||||
],
|
||||
fieldMetaOptions,
|
||||
fieldMetaOptions: { isEnabled: true },
|
||||
};
|
||||
const colorProperty = makeProperty(dynamicStyleOptions);
|
||||
|
||||
const colorProperty = new DynamicColorProperty(
|
||||
options,
|
||||
VECTOR_STYLES.LINE_COLOR,
|
||||
field,
|
||||
layer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
}
|
||||
);
|
||||
|
||||
expect(colorProperty._getMbColor()).toEqual([
|
||||
'step',
|
||||
[
|
||||
|
@ -476,21 +548,40 @@ describe('get mapbox color expression (via internal _getMbColor)', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('should use `get` when source cannot return raw geojson', async () => {
|
||||
const field = Object.create(mockField);
|
||||
field.canReadFromGeoJson = function () {
|
||||
return false;
|
||||
};
|
||||
const dynamicStyleOptions = {
|
||||
test('should use `get` for MVT source', async () => {
|
||||
const field = {
|
||||
getMbFieldName: () => {
|
||||
return 'foobar';
|
||||
},
|
||||
getSource: () => {
|
||||
return {
|
||||
isMvt: () => {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
},
|
||||
} as unknown as IField;
|
||||
const layer = {} as unknown as IVectorLayer;
|
||||
const options = {
|
||||
type: COLOR_MAP_TYPE.ORDINAL,
|
||||
useCustomColorRamp: true,
|
||||
customColorRamp: [
|
||||
{ stop: 10, color: '#f7faff' },
|
||||
{ stop: 100, color: '#072f6b' },
|
||||
],
|
||||
fieldMetaOptions,
|
||||
fieldMetaOptions: { isEnabled: true },
|
||||
};
|
||||
const colorProperty = makeProperty(dynamicStyleOptions, undefined, field);
|
||||
|
||||
const colorProperty = new DynamicColorProperty(
|
||||
options,
|
||||
VECTOR_STYLES.LINE_COLOR,
|
||||
field,
|
||||
layer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
}
|
||||
);
|
||||
|
||||
expect(colorProperty._getMbColor()).toEqual([
|
||||
'step',
|
||||
[
|
||||
|
|
|
@ -101,7 +101,7 @@ export class DynamicColorProperty extends DynamicStyleProperty<ColorDynamicOptio
|
|||
}
|
||||
|
||||
supportsFieldMeta() {
|
||||
if (!this.isComplete() || !this._field || !this._field.supportsFieldMeta()) {
|
||||
if (!this.isComplete() || !this._field || !this._field.supportsFieldMetaFromEs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,13 +14,10 @@ jest.mock('../components/vector_style_editor', () => ({
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
// @ts-ignore
|
||||
import { DynamicSizeProperty } from './dynamic_size_property';
|
||||
import { RawValue, VECTOR_STYLES } from '../../../../../common/constants';
|
||||
import { FIELD_ORIGIN, RawValue, VECTOR_STYLES } from '../../../../../common/constants';
|
||||
import { IField } from '../../../fields/field';
|
||||
import type { Map as MbMap } from '@kbn/mapbox-gl';
|
||||
import { SizeDynamicOptions } from '../../../../../common/descriptor_types';
|
||||
import { mockField, MockLayer, MockStyle } from './test_helpers/test_util';
|
||||
import { IVectorLayer } from '../../../layers/vector_layer';
|
||||
|
||||
export class MockMbMap {
|
||||
|
@ -38,31 +35,40 @@ export class MockMbMap {
|
|||
}
|
||||
}
|
||||
|
||||
const makeProperty = (
|
||||
options: SizeDynamicOptions,
|
||||
mockStyle: MockStyle,
|
||||
field: IField = mockField
|
||||
) => {
|
||||
return new DynamicSizeProperty(
|
||||
options,
|
||||
VECTOR_STYLES.ICON_SIZE,
|
||||
field,
|
||||
new MockLayer(mockStyle) as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
},
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
const fieldMetaOptions = { isEnabled: true };
|
||||
|
||||
describe('renderLegendDetailRow', () => {
|
||||
test('Should render as range', async () => {
|
||||
const sizeProp = makeProperty(
|
||||
{ minSize: 0, maxSize: 10, fieldMetaOptions },
|
||||
new MockStyle({ min: 0, max: 100 })
|
||||
const field = {
|
||||
getLabel: async () => {
|
||||
return 'foobar_label';
|
||||
},
|
||||
getName: () => {
|
||||
return 'foodbar';
|
||||
},
|
||||
getOrigin: () => {
|
||||
return FIELD_ORIGIN.SOURCE;
|
||||
},
|
||||
supportsFieldMetaFromEs: () => {
|
||||
return true;
|
||||
},
|
||||
} as unknown as IField;
|
||||
const sizeProp = new DynamicSizeProperty(
|
||||
{ minSize: 0, maxSize: 10, fieldMetaOptions: { isEnabled: true } },
|
||||
VECTOR_STYLES.ICON_SIZE,
|
||||
field,
|
||||
{} as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
},
|
||||
false
|
||||
);
|
||||
sizeProp.getRangeFieldMeta = () => {
|
||||
return {
|
||||
min: 0,
|
||||
max: 100,
|
||||
delta: 100,
|
||||
};
|
||||
};
|
||||
|
||||
const legendRow = sizeProp.renderLegendDetailRow();
|
||||
const component = shallow(legendRow);
|
||||
|
||||
|
@ -76,10 +82,47 @@ describe('renderLegendDetailRow', () => {
|
|||
|
||||
describe('syncSize', () => {
|
||||
test('Should sync with circle-radius prop', async () => {
|
||||
const sizeProp = makeProperty(
|
||||
{ minSize: 8, maxSize: 32, fieldMetaOptions },
|
||||
new MockStyle({ min: 0, max: 100 })
|
||||
const field = {
|
||||
isValid: () => {
|
||||
return true;
|
||||
},
|
||||
getName: () => {
|
||||
return 'foodbar';
|
||||
},
|
||||
getMbFieldName: () => {
|
||||
return 'foobar';
|
||||
},
|
||||
getOrigin: () => {
|
||||
return FIELD_ORIGIN.SOURCE;
|
||||
},
|
||||
getSource: () => {
|
||||
return {
|
||||
isMvt: () => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
},
|
||||
supportsFieldMetaFromEs: () => {
|
||||
return true;
|
||||
},
|
||||
} as unknown as IField;
|
||||
const sizeProp = new DynamicSizeProperty(
|
||||
{ minSize: 8, maxSize: 32, fieldMetaOptions: { isEnabled: true } },
|
||||
VECTOR_STYLES.ICON_SIZE,
|
||||
field,
|
||||
{} as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
},
|
||||
false
|
||||
);
|
||||
sizeProp.getRangeFieldMeta = () => {
|
||||
return {
|
||||
min: 0,
|
||||
max: 100,
|
||||
delta: 100,
|
||||
};
|
||||
};
|
||||
const mockMbMap = new MockMbMap() as unknown as MbMap;
|
||||
|
||||
sizeProp.syncCircleRadiusWithMb('foobar', mockMbMap);
|
||||
|
@ -112,10 +155,47 @@ describe('syncSize', () => {
|
|||
});
|
||||
|
||||
test('Should truncate interpolate expression to max when no delta', async () => {
|
||||
const sizeProp = makeProperty(
|
||||
{ minSize: 8, maxSize: 32, fieldMetaOptions },
|
||||
new MockStyle({ min: 100, max: 100 })
|
||||
const field = {
|
||||
isValid: () => {
|
||||
return true;
|
||||
},
|
||||
getName: () => {
|
||||
return 'foobar';
|
||||
},
|
||||
getMbFieldName: () => {
|
||||
return 'foobar';
|
||||
},
|
||||
getOrigin: () => {
|
||||
return FIELD_ORIGIN.SOURCE;
|
||||
},
|
||||
getSource: () => {
|
||||
return {
|
||||
isMvt: () => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
},
|
||||
supportsFieldMetaFromEs: () => {
|
||||
return true;
|
||||
},
|
||||
} as unknown as IField;
|
||||
const sizeProp = new DynamicSizeProperty(
|
||||
{ minSize: 8, maxSize: 32, fieldMetaOptions: { isEnabled: true } },
|
||||
VECTOR_STYLES.ICON_SIZE,
|
||||
field,
|
||||
{} as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
},
|
||||
false
|
||||
);
|
||||
sizeProp.getRangeFieldMeta = () => {
|
||||
return {
|
||||
min: 100,
|
||||
max: 100,
|
||||
delta: 0,
|
||||
};
|
||||
};
|
||||
const mockMbMap = new MockMbMap() as unknown as MbMap;
|
||||
|
||||
sizeProp.syncCircleRadiusWithMb('foobar', mockMbMap);
|
||||
|
|
|
@ -260,7 +260,7 @@ export class DynamicStyleProperty<T>
|
|||
}
|
||||
|
||||
supportsFieldMeta() {
|
||||
return this.isComplete() && !!this._field && this._field.supportsFieldMeta();
|
||||
return this.isComplete() && !!this._field && this._field.supportsFieldMetaFromEs();
|
||||
}
|
||||
|
||||
async getFieldMetaRequest() {
|
||||
|
@ -287,7 +287,7 @@ export class DynamicStyleProperty<T>
|
|||
}
|
||||
|
||||
supportsMbFeatureState() {
|
||||
return !!this._field && this._field.canReadFromGeoJson();
|
||||
return !!this._field && !this._field.getSource().isMvt();
|
||||
}
|
||||
|
||||
getMbLookupFunction(): MB_LOOKUP_FUNCTION {
|
||||
|
@ -466,13 +466,14 @@ export class DynamicStyleProperty<T>
|
|||
}
|
||||
|
||||
renderDataMappingPopover(onChange: (updatedOptions: Partial<T>) => void) {
|
||||
if (!this.supportsFieldMeta()) {
|
||||
if (!this._field || !this.supportsFieldMeta()) {
|
||||
return null;
|
||||
}
|
||||
return this.isCategorical() ? (
|
||||
<CategoricalDataMappingPopover<T>
|
||||
fieldMetaOptions={this.getFieldMetaOptions()}
|
||||
onChange={onChange}
|
||||
supportsFieldMetaFromLocalData={this._field.supportsFieldMetaFromLocalData()}
|
||||
/>
|
||||
) : (
|
||||
<OrdinalDataMappingPopover<T>
|
||||
|
@ -481,6 +482,7 @@ export class DynamicStyleProperty<T>
|
|||
onChange={onChange}
|
||||
dataMappingFunction={this.getDataMappingFunction()}
|
||||
supportedDataMappingFunctions={this._getSupportedDataMappingFunctions()}
|
||||
supportsFieldMetaFromLocalData={this._field.supportsFieldMetaFromLocalData()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -502,7 +504,7 @@ export class DynamicStyleProperty<T>
|
|||
// They just re-use the original property-name
|
||||
targetName = this._field.getName();
|
||||
} else {
|
||||
if (this._field.canReadFromGeoJson() && this._field.supportsAutoDomain()) {
|
||||
if (!this._field.getSource().isMvt() && this._field.supportsFieldMetaFromLocalData()) {
|
||||
// Geojson-sources can support rewrite
|
||||
// e.g. field-formatters will create duplicate field
|
||||
targetName = getComputedFieldName(this.getStyleName(), this._field.getName());
|
||||
|
|
|
@ -18,7 +18,7 @@ import { DynamicTextProperty } from './dynamic_text_property';
|
|||
import { RawValue, VECTOR_STYLES } from '../../../../../common/constants';
|
||||
import { IField } from '../../../fields/field';
|
||||
import type { Map as MbMap } from '@kbn/mapbox-gl';
|
||||
import { mockField, MockLayer, MockStyle } from './test_helpers/test_util';
|
||||
import { MockLayer, MockStyle } from './test_helpers/test_util';
|
||||
import { IVectorLayer } from '../../../layers/vector_layer';
|
||||
|
||||
export class MockMbMap {
|
||||
|
@ -49,22 +49,37 @@ export class MockMbMap {
|
|||
}
|
||||
}
|
||||
|
||||
const makeProperty = (mockStyle: MockStyle, field: IField | null) => {
|
||||
return new DynamicTextProperty(
|
||||
{},
|
||||
VECTOR_STYLES.LABEL_TEXT,
|
||||
field,
|
||||
new MockLayer(mockStyle) as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
describe('syncTextFieldWithMb', () => {
|
||||
describe('with field', () => {
|
||||
test('Should set', async () => {
|
||||
const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), mockField);
|
||||
test('Should set text-field', async () => {
|
||||
const field = {
|
||||
isValid: () => {
|
||||
return true;
|
||||
},
|
||||
getName: () => {
|
||||
return 'foobar';
|
||||
},
|
||||
getSource: () => {
|
||||
return {
|
||||
isMvt: () => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
},
|
||||
supportsFieldMetaFromLocalData: () => {
|
||||
return true;
|
||||
},
|
||||
} as unknown as IField;
|
||||
const dynamicTextProperty = new DynamicTextProperty(
|
||||
{},
|
||||
VECTOR_STYLES.LABEL_TEXT,
|
||||
field,
|
||||
new MockLayer(new MockStyle({ min: 0, max: 100 })) as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
}
|
||||
);
|
||||
|
||||
const mockMbMap = new MockMbMap() as unknown as MbMap;
|
||||
|
||||
dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap);
|
||||
|
@ -77,8 +92,17 @@ describe('syncTextFieldWithMb', () => {
|
|||
});
|
||||
|
||||
describe('without field', () => {
|
||||
test('Should clear', async () => {
|
||||
const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), null);
|
||||
test('Should clear text-field', async () => {
|
||||
const dynamicTextProperty = new DynamicTextProperty(
|
||||
{},
|
||||
VECTOR_STYLES.LABEL_TEXT,
|
||||
null,
|
||||
new MockLayer(new MockStyle({ min: 0, max: 100 })) as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
}
|
||||
);
|
||||
|
||||
const mockMbMap = new MockMbMap([
|
||||
'foobar',
|
||||
['coalesce', ['get', '__kbn__dynamic__foobar__labelText'], ''],
|
||||
|
@ -90,14 +114,22 @@ describe('syncTextFieldWithMb', () => {
|
|||
expect(mockMbMap.getPaintPropertyCalls()).toEqual([['foobar', undefined]]);
|
||||
});
|
||||
|
||||
test('Should not clear when already cleared', async () => {
|
||||
test('Should not set or clear text-field', async () => {
|
||||
// This verifies a weird edge-case in mapbox-gl, where setting the `text-field` layout-property to null causes tiles to be invalidated.
|
||||
// This triggers a refetch of the tile during panning and zooming
|
||||
// This affects vector-tile rendering in tiled_vector_layers with custom vector_styles
|
||||
// It does _not_ affect EMS, since that does not have a code-path where a `text-field` need to be resynced.
|
||||
// Do not remove this logic without verifying that mapbox-gl does not re-issue tile-requests for previously requested tiles
|
||||
|
||||
const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), null);
|
||||
const dynamicTextProperty = new DynamicTextProperty(
|
||||
{},
|
||||
VECTOR_STYLES.LABEL_TEXT,
|
||||
null,
|
||||
new MockLayer(new MockStyle({ min: 0, max: 100 })) as unknown as IVectorLayer,
|
||||
() => {
|
||||
return (value: RawValue) => value + '_format';
|
||||
}
|
||||
);
|
||||
const mockMbMap = new MockMbMap(undefined) as unknown as MbMap;
|
||||
|
||||
dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap);
|
||||
|
|
|
@ -19,22 +19,22 @@ import { IStyle } from '../../../style';
|
|||
|
||||
export class MockField extends AbstractField {
|
||||
private readonly _dataType: string;
|
||||
private readonly _supportsAutoDomain: boolean;
|
||||
private readonly _supportsFieldMetaFromLocalData: boolean;
|
||||
|
||||
constructor({
|
||||
fieldName,
|
||||
origin = FIELD_ORIGIN.SOURCE,
|
||||
dataType = 'string',
|
||||
supportsAutoDomain = true,
|
||||
supportsFieldMetaFromLocalData = true,
|
||||
}: {
|
||||
fieldName: string;
|
||||
origin?: FIELD_ORIGIN;
|
||||
dataType?: string;
|
||||
supportsAutoDomain?: boolean;
|
||||
supportsFieldMetaFromLocalData?: boolean;
|
||||
}) {
|
||||
super({ fieldName, origin });
|
||||
this._dataType = dataType;
|
||||
this._supportsAutoDomain = supportsAutoDomain;
|
||||
this._supportsFieldMetaFromLocalData = supportsFieldMetaFromLocalData;
|
||||
}
|
||||
|
||||
async getLabel(): Promise<string> {
|
||||
|
@ -45,11 +45,11 @@ export class MockField extends AbstractField {
|
|||
return this._dataType;
|
||||
}
|
||||
|
||||
supportsAutoDomain(): boolean {
|
||||
return this._supportsAutoDomain;
|
||||
supportsFieldMetaFromLocalData(): boolean {
|
||||
return this._supportsFieldMetaFromLocalData;
|
||||
}
|
||||
|
||||
supportsFieldMeta(): boolean {
|
||||
supportsFieldMetaFromEs(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,45 +7,76 @@
|
|||
|
||||
import { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../common/constants';
|
||||
import { createStyleFieldsHelper, StyleFieldsHelper } from './style_fields_helper';
|
||||
import { AbstractField, IField } from '../../fields/field';
|
||||
|
||||
class MockField extends AbstractField {
|
||||
private readonly _dataType: string;
|
||||
private readonly _supportsAutoDomain: boolean;
|
||||
constructor({ dataType, supportsAutoDomain }: { dataType: string; supportsAutoDomain: boolean }) {
|
||||
super({ fieldName: 'foobar_' + dataType, origin: FIELD_ORIGIN.SOURCE });
|
||||
this._dataType = dataType;
|
||||
this._supportsAutoDomain = supportsAutoDomain;
|
||||
}
|
||||
async getDataType() {
|
||||
return this._dataType;
|
||||
}
|
||||
|
||||
supportsAutoDomain(): boolean {
|
||||
return this._supportsAutoDomain;
|
||||
}
|
||||
}
|
||||
import { IField } from '../../fields/field';
|
||||
|
||||
describe('StyleFieldHelper', () => {
|
||||
describe('isFieldDataTypeCompatibleWithStyleType', () => {
|
||||
async function createHelper(supportsAutoDomain: boolean): Promise<{
|
||||
async function createHelper(supportsFieldMetaFromLocalData: boolean): Promise<{
|
||||
styleFieldHelper: StyleFieldsHelper;
|
||||
stringField: IField;
|
||||
numberField: IField;
|
||||
dateField: IField;
|
||||
}> {
|
||||
const stringField = new MockField({
|
||||
dataType: 'string',
|
||||
supportsAutoDomain,
|
||||
});
|
||||
const numberField = new MockField({
|
||||
dataType: 'number',
|
||||
supportsAutoDomain,
|
||||
});
|
||||
const dateField = new MockField({
|
||||
dataType: 'date',
|
||||
supportsAutoDomain,
|
||||
});
|
||||
const stringField = {
|
||||
getDataType: async () => {
|
||||
return 'string';
|
||||
},
|
||||
getLabel: async () => {
|
||||
return 'foobar_string_label';
|
||||
},
|
||||
getName: () => {
|
||||
return 'foobar_string';
|
||||
},
|
||||
getOrigin: () => {
|
||||
return FIELD_ORIGIN.SOURCE;
|
||||
},
|
||||
supportsFieldMetaFromLocalData: () => {
|
||||
return supportsFieldMetaFromLocalData;
|
||||
},
|
||||
supportsFieldMetaFromEs: () => {
|
||||
return false;
|
||||
},
|
||||
} as unknown as IField;
|
||||
const numberField = {
|
||||
getDataType: async () => {
|
||||
return 'number';
|
||||
},
|
||||
getLabel: async () => {
|
||||
return 'foobar_number_label';
|
||||
},
|
||||
getName: () => {
|
||||
return 'foobar_number';
|
||||
},
|
||||
getOrigin: () => {
|
||||
return FIELD_ORIGIN.SOURCE;
|
||||
},
|
||||
supportsFieldMetaFromLocalData: () => {
|
||||
return supportsFieldMetaFromLocalData;
|
||||
},
|
||||
supportsFieldMetaFromEs: () => {
|
||||
return false;
|
||||
},
|
||||
} as unknown as IField;
|
||||
const dateField = {
|
||||
getDataType: async () => {
|
||||
return 'date';
|
||||
},
|
||||
getLabel: async () => {
|
||||
return 'foobar_date_label';
|
||||
},
|
||||
getName: () => {
|
||||
return 'foobar_date';
|
||||
},
|
||||
getOrigin: () => {
|
||||
return FIELD_ORIGIN.SOURCE;
|
||||
},
|
||||
supportsFieldMetaFromLocalData: () => {
|
||||
return supportsFieldMetaFromLocalData;
|
||||
},
|
||||
supportsFieldMetaFromEs: () => {
|
||||
return false;
|
||||
},
|
||||
} as unknown as IField;
|
||||
return {
|
||||
styleFieldHelper: await createStyleFieldsHelper([stringField, numberField, dateField]),
|
||||
stringField,
|
||||
|
|
|
@ -28,7 +28,7 @@ export async function createStyleFieldsHelper(fields: IField[]): Promise<StyleFi
|
|||
name: field.getName(),
|
||||
origin: field.getOrigin(),
|
||||
type: await field.getDataType(),
|
||||
supportsAutoDomain: field.supportsAutoDomain(),
|
||||
supportsAutoDomain: field.supportsFieldMetaFromLocalData() || field.supportsFieldMetaFromEs(),
|
||||
};
|
||||
});
|
||||
const styleFields = await Promise.all(promises);
|
||||
|
|
|
@ -107,11 +107,27 @@ describe('getDescriptorWithUpdatedStyleProps', () => {
|
|||
const vectorStyle = new VectorStyle({ properties }, new MockSource());
|
||||
|
||||
const nextFields = [
|
||||
new MockField({
|
||||
fieldName: previousFieldName,
|
||||
dataType: 'number',
|
||||
supportsAutoDomain: false,
|
||||
}),
|
||||
{
|
||||
getDataType: async () => {
|
||||
return 'number';
|
||||
},
|
||||
getLabel: async () => {
|
||||
return previousFieldName + '_label';
|
||||
},
|
||||
getName: () => {
|
||||
return previousFieldName;
|
||||
},
|
||||
getOrigin: () => {
|
||||
return FIELD_ORIGIN.SOURCE;
|
||||
},
|
||||
// ordinal field must support auto domain
|
||||
supportsFieldMetaFromLocalData: () => {
|
||||
return false;
|
||||
},
|
||||
supportsFieldMetaFromEs: () => {
|
||||
return false;
|
||||
},
|
||||
},
|
||||
];
|
||||
const { hasChanges, nextStyleDescriptor } =
|
||||
await vectorStyle.getDescriptorWithUpdatedStyleProps(nextFields, previousFields, mapColors);
|
||||
|
|
Loading…
Reference in a new issue