[maps] fix vector tile layer with joins stuck in loading state when not visible (#170984)

Closes https://github.com/elastic/kibana/issues/170983

### Test instructions
1. Download world countries geojson from
https://maps.elastic.co/v8.12/index.html?locale=en#file/world_countries
2. upload downloaded world countries
3. create new map
4. add "Choropleth" layer
5. Set boundaries source to "Points, lines, and polygons from
elasticsearch". Select world countries data view. Set join field to
"iso2"
6. Set statistics view to kibana sample web logs. Set join field to
"geo.src"
7. minimize layer TOC
8. save map and re-open.
9. Minimized layer legend icon should stop showing loading state once
EMS base map is loaded

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2023-11-10 08:20:25 -07:00 committed by GitHub
parent f7ab883319
commit 3c0ba20369
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 128 additions and 125 deletions

View file

@ -284,6 +284,10 @@ export class LayerGroup implements ILayer {
}
isLayerLoading(zoom: number): boolean {
if (!this.isVisible()) {
return false;
}
return this._children.some((child) => {
return child.isLayerLoading(zoom);
});

View file

@ -75,6 +75,18 @@ describe('isLayerLoading', () => {
});
describe('joins', () => {
test('should return false when layer is not visible', () => {
const layer = new GeoJsonVectorLayer({
customIcons: [],
joins: [mockJoin],
layerDescriptor: {
visible: false,
} as unknown as VectorLayerDescriptor,
source: {} as unknown as IVectorSource,
});
expect(layer.isLayerLoading(1)).toBe(false);
});
describe('source data loaded with no features', () => {
test('should return false when join loading has not started', () => {
const layer = new GeoJsonVectorLayer({

View file

@ -61,6 +61,10 @@ export class GeoJsonVectorLayer extends AbstractVectorLayer {
}
isLayerLoading(zoom: number) {
if (!this.isVisible() || !this.showAtZoomLevel(zoom)) {
return false;
}
const isSourceLoading = super.isLayerLoading(zoom);
if (isSourceLoading) {
return true;

View file

@ -110,139 +110,118 @@ describe('isLayerLoading', () => {
dataRequestMetaAtStart: undefined,
dataRequestToken: undefined,
};
test('should be true when tile loading has not started', () => {
const layer = new MvtVectorLayer({
customIcons: [],
layerDescriptor: {
__dataRequests: [sourceDataRequestDescriptor],
} as unknown as VectorLayerDescriptor,
source: {
getMaxZoom: () => {
return 24;
},
getMinZoom: () => {
return 0;
},
} as unknown as IVectorSource,
const mockSource = {
getMaxZoom: () => {
return 24;
},
getMinZoom: () => {
return 0;
},
} as unknown as IVectorSource;
describe('no joins', () => {
test('should be true when tile loading has not started', () => {
const layer = new MvtVectorLayer({
customIcons: [],
layerDescriptor: {
__dataRequests: [sourceDataRequestDescriptor],
} as unknown as VectorLayerDescriptor,
source: mockSource,
});
expect(layer.isLayerLoading(1)).toBe(true);
});
test('should be true when tiles are loading', () => {
const layer = new MvtVectorLayer({
customIcons: [],
layerDescriptor: {
__areTilesLoaded: false,
__dataRequests: [sourceDataRequestDescriptor],
} as unknown as VectorLayerDescriptor,
source: mockSource,
});
expect(layer.isLayerLoading(1)).toBe(true);
});
test('should be false when tiles are loaded', () => {
const layer = new MvtVectorLayer({
customIcons: [],
layerDescriptor: {
__areTilesLoaded: true,
__dataRequests: [sourceDataRequestDescriptor],
} as unknown as VectorLayerDescriptor,
source: mockSource,
});
expect(layer.isLayerLoading(1)).toBe(false);
});
expect(layer.isLayerLoading(1)).toBe(true);
});
test('should be true when tiles are loading', () => {
const layer = new MvtVectorLayer({
customIcons: [],
layerDescriptor: {
__areTilesLoaded: false,
__dataRequests: [sourceDataRequestDescriptor],
} as unknown as VectorLayerDescriptor,
source: {
getMaxZoom: () => {
return 24;
},
getMinZoom: () => {
return 0;
},
} as unknown as IVectorSource,
});
expect(layer.isLayerLoading(1)).toBe(true);
});
describe('joins', () => {
const joinDataRequestId = 'join_source_a0b0da65-5e1a-4967-9dbe-74f24391afe2';
const mockJoin = {
hasCompleteConfig: () => {
return true;
},
getSourceDataRequestId: () => {
return joinDataRequestId;
},
getRightJoinSource: () => {
return {} as unknown as IJoinSource;
},
} as unknown as InnerJoin;
test('should be false when tiles are loaded', () => {
const layer = new MvtVectorLayer({
customIcons: [],
layerDescriptor: {
__areTilesLoaded: true,
__dataRequests: [sourceDataRequestDescriptor],
} as unknown as VectorLayerDescriptor,
source: {
getMaxZoom: () => {
return 24;
},
getMinZoom: () => {
return 0;
},
} as unknown as IVectorSource,
test('should be false when layer is not visible', () => {
const layer = new MvtVectorLayer({
customIcons: [],
joins: [mockJoin],
layerDescriptor: {
visible: false,
} as unknown as VectorLayerDescriptor,
source: mockSource,
});
expect(layer.isLayerLoading(1)).toBe(false);
});
expect(layer.isLayerLoading(1)).toBe(false);
});
test('should be true when tiles are loaded but join is loading', () => {
const layer = new MvtVectorLayer({
customIcons: [],
joins: [
{
hasCompleteConfig: () => {
return true;
},
getSourceDataRequestId: () => {
return 'join_source_a0b0da65-5e1a-4967-9dbe-74f24391afe2';
},
getRightJoinSource: () => {
return {} as unknown as IJoinSource;
},
} as unknown as InnerJoin,
],
layerDescriptor: {
__areTilesLoaded: true,
__dataRequests: [
sourceDataRequestDescriptor,
{
dataId: 'join_source_a0b0da65-5e1a-4967-9dbe-74f24391afe2',
dataRequestMetaAtStart: {},
dataRequestToken: Symbol('join request'),
},
],
} as unknown as VectorLayerDescriptor,
source: {
getMaxZoom: () => {
return 24;
},
getMinZoom: () => {
return 0;
},
} as unknown as IVectorSource,
test('should be true when tiles are loaded but join is loading', () => {
const layer = new MvtVectorLayer({
customIcons: [],
joins: [mockJoin],
layerDescriptor: {
__areTilesLoaded: true,
__dataRequests: [
sourceDataRequestDescriptor,
{
dataId: joinDataRequestId,
dataRequestMetaAtStart: {},
dataRequestToken: Symbol('join request'),
},
],
} as unknown as VectorLayerDescriptor,
source: mockSource,
});
expect(layer.isLayerLoading(1)).toBe(true);
});
expect(layer.isLayerLoading(1)).toBe(true);
});
test('should be false when tiles are loaded and joins are loaded', () => {
const layer = new MvtVectorLayer({
customIcons: [],
joins: [
{
hasCompleteConfig: () => {
return true;
},
getSourceDataRequestId: () => {
return 'join_source_a0b0da65-5e1a-4967-9dbe-74f24391afe2';
},
getRightJoinSource: () => {
return {} as unknown as IJoinSource;
},
} as unknown as InnerJoin,
],
layerDescriptor: {
__areTilesLoaded: true,
__dataRequests: [
sourceDataRequestDescriptor,
{
data: {},
dataId: 'join_source_a0b0da65-5e1a-4967-9dbe-74f24391afe2',
dataRequestMeta: {},
dataRequestMetaAtStart: undefined,
dataRequestToken: undefined,
},
],
} as unknown as VectorLayerDescriptor,
source: {
getMaxZoom: () => {
return 24;
},
getMinZoom: () => {
return 0;
},
} as unknown as IVectorSource,
test('should be false when tiles are loaded and joins are loaded', () => {
const layer = new MvtVectorLayer({
customIcons: [],
joins: [mockJoin],
layerDescriptor: {
__areTilesLoaded: true,
__dataRequests: [
sourceDataRequestDescriptor,
{
data: {},
dataId: joinDataRequestId,
dataRequestMeta: {},
dataRequestMetaAtStart: undefined,
dataRequestToken: undefined,
},
],
} as unknown as VectorLayerDescriptor,
source: mockSource,
});
expect(layer.isLayerLoading(1)).toBe(false);
});
expect(layer.isLayerLoading(1)).toBe(false);
});
});

View file

@ -75,6 +75,10 @@ export class MvtVectorLayer extends AbstractVectorLayer {
}
isLayerLoading(zoom: number) {
if (!this.isVisible() || !this.showAtZoomLevel(zoom)) {
return false;
}
const isSourceLoading = super.isLayerLoading(zoom);
return isSourceLoading ? true : this._isLoadingJoins();
}