* Geomap: Require layer to have data for legend (#105580)
(cherry picked from commit 16a6d61ca7)
* Remove test for non-existent function
* Remove unused import
This commit is contained in:
@@ -31,7 +31,7 @@ import { getActions } from './utils/actions';
|
||||
import { getLayersExtent } from './utils/getLayersExtent';
|
||||
import { applyLayerFilter, initLayer } from './utils/layers';
|
||||
import { pointerClickListener, pointerMoveListener, setTooltipListeners } from './utils/tooltip';
|
||||
import { updateMap, getNewOpenLayersMap, notifyPanelEditor } from './utils/utils';
|
||||
import { updateMap, getNewOpenLayersMap, notifyPanelEditor, hasLayerData } from './utils/utils';
|
||||
import { centerPointRegistry, MapCenterID } from './view';
|
||||
|
||||
// Allows multiple panels to share the same view instance
|
||||
@@ -182,6 +182,9 @@ export class GeomapPanel extends Component<Props, State> {
|
||||
this.map.setView(view);
|
||||
}
|
||||
}
|
||||
|
||||
// Update legends when data changes
|
||||
this.setState({ legends: this.getLegends() });
|
||||
}
|
||||
|
||||
initMapRef = async (div: HTMLDivElement) => {
|
||||
@@ -366,7 +369,10 @@ export class GeomapPanel extends Component<Props, State> {
|
||||
const legends: ReactNode[] = [];
|
||||
for (const state of this.layers) {
|
||||
if (state.handler.legend) {
|
||||
legends.push(<div key={state.options.name}>{state.handler.legend}</div>);
|
||||
const hasData = hasLayerData(state.layer);
|
||||
if (hasData) {
|
||||
legends.push(<div key={state.options.name}>{state.handler.legend}</div>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
import Feature from 'ol/Feature';
|
||||
import Point from 'ol/geom/Point';
|
||||
import LayerGroup from 'ol/layer/Group';
|
||||
import TileLayer from 'ol/layer/Tile';
|
||||
import VectorLayer from 'ol/layer/Vector';
|
||||
import WebGLPointsLayer from 'ol/layer/WebGLPoints';
|
||||
import TileSource from 'ol/source/Tile';
|
||||
import VectorSource from 'ol/source/Vector';
|
||||
|
||||
// Mock the config module to avoid undefined panels error
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
getTemplateSrv: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock the dimensions module since it's imported by utils.ts
|
||||
jest.mock('app/features/dimensions', () => ({
|
||||
getColorDimension: jest.fn(),
|
||||
getScalarDimension: jest.fn(),
|
||||
getScaledDimension: jest.fn(),
|
||||
getTextDimension: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock the grafana datasource since it's imported by utils.ts
|
||||
jest.mock('app/plugins/datasource/grafana/datasource', () => ({
|
||||
getGrafanaDatasource: jest.fn(),
|
||||
}));
|
||||
|
||||
import { hasLayerData } from './utils';
|
||||
|
||||
// Test fixtures
|
||||
const createTestFeature = () => new Feature(new Point([0, 0]));
|
||||
|
||||
const createTestVectorSource = (hasFeature = false): VectorSource<Point> => {
|
||||
const source = new VectorSource<Point>();
|
||||
if (hasFeature) {
|
||||
source.addFeature(createTestFeature());
|
||||
}
|
||||
return source;
|
||||
};
|
||||
|
||||
const createTestWebGLStyle = () => ({
|
||||
symbol: {
|
||||
symbolType: 'circle',
|
||||
size: 8,
|
||||
color: '#000000',
|
||||
opacity: 1,
|
||||
},
|
||||
});
|
||||
|
||||
describe('hasLayerData', () => {
|
||||
it('should return false for empty vector layer', () => {
|
||||
const layer = new VectorLayer({
|
||||
source: createTestVectorSource(),
|
||||
});
|
||||
expect(hasLayerData(layer)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for vector layer with features', () => {
|
||||
const layer = new VectorLayer({
|
||||
source: createTestVectorSource(true),
|
||||
});
|
||||
expect(hasLayerData(layer)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for layer group with data', () => {
|
||||
const vectorLayer = new VectorLayer({
|
||||
source: createTestVectorSource(true),
|
||||
});
|
||||
const group = new LayerGroup({
|
||||
layers: [vectorLayer],
|
||||
});
|
||||
expect(hasLayerData(group)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for empty layer group', () => {
|
||||
const group = new LayerGroup({
|
||||
layers: [],
|
||||
});
|
||||
expect(hasLayerData(group)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for tile layer with source', () => {
|
||||
const layer = new TileLayer({
|
||||
source: new TileSource({}),
|
||||
});
|
||||
expect(hasLayerData(layer)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for tile layer without source', () => {
|
||||
const layer = new TileLayer({});
|
||||
expect(hasLayerData(layer)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for WebGLPointsLayer with features', () => {
|
||||
const layer = new WebGLPointsLayer({
|
||||
source: createTestVectorSource(true),
|
||||
style: createTestWebGLStyle(),
|
||||
});
|
||||
expect(hasLayerData(layer)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for empty WebGLPointsLayer', () => {
|
||||
const layer = new WebGLPointsLayer({
|
||||
source: createTestVectorSource(),
|
||||
style: createTestWebGLStyle(),
|
||||
});
|
||||
expect(hasLayerData(layer)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for layer group with WebGLPointsLayer containing data', () => {
|
||||
const webglLayer = new WebGLPointsLayer({
|
||||
source: createTestVectorSource(true),
|
||||
style: createTestWebGLStyle(),
|
||||
});
|
||||
const group = new LayerGroup({
|
||||
layers: [webglLayer],
|
||||
});
|
||||
expect(hasLayerData(group)).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,17 @@
|
||||
import { Map as OpenLayersMap } from 'ol';
|
||||
import Geometry from 'ol/geom/Geometry';
|
||||
import Point from 'ol/geom/Point';
|
||||
import { defaults as interactionDefaults } from 'ol/interaction';
|
||||
import BaseLayer from 'ol/layer/Base';
|
||||
import LayerGroup from 'ol/layer/Group';
|
||||
import ImageLayer from 'ol/layer/Image';
|
||||
import TileLayer from 'ol/layer/Tile';
|
||||
import VectorLayer from 'ol/layer/Vector';
|
||||
import VectorImage from 'ol/layer/VectorImage';
|
||||
import WebGLPointsLayer from 'ol/layer/WebGLPoints';
|
||||
import ImageSource from 'ol/source/Image';
|
||||
import TileSource from 'ol/source/Tile';
|
||||
import VectorSource from 'ol/source/Vector';
|
||||
|
||||
import { DataFrame, GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
import { getColorDimension, getScalarDimension, getScaledDimension, getTextDimension } from 'app/features/dimensions';
|
||||
@@ -143,3 +155,39 @@ export const isUrl = (url: string) => {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a layer has data to display
|
||||
* @param layer The OpenLayers layer to check
|
||||
* @returns boolean indicating if the layer has data
|
||||
*/
|
||||
export function hasLayerData(
|
||||
layer:
|
||||
| LayerGroup
|
||||
| VectorLayer<VectorSource<Geometry>>
|
||||
| VectorImage<VectorSource<Geometry>>
|
||||
| WebGLPointsLayer<VectorSource<Point>>
|
||||
| TileLayer<TileSource>
|
||||
| ImageLayer<ImageSource>
|
||||
| BaseLayer
|
||||
): boolean {
|
||||
if (layer instanceof LayerGroup) {
|
||||
return layer
|
||||
.getLayers()
|
||||
.getArray()
|
||||
.some((subLayer) => hasLayerData(subLayer));
|
||||
}
|
||||
if (layer instanceof VectorLayer || layer instanceof VectorImage) {
|
||||
const source = layer.getSource();
|
||||
return source != null && source.getFeatures().length > 0;
|
||||
}
|
||||
if (layer instanceof WebGLPointsLayer) {
|
||||
const source = layer.getSource();
|
||||
return source != null && source.getFeatures().length > 0;
|
||||
}
|
||||
if (layer instanceof TileLayer || layer instanceof ImageLayer) {
|
||||
// For tile/image layers, check if they have a source
|
||||
return Boolean(layer.getSource());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user