mirror of
https://github.com/grafana/grafana.git
synced 2025-09-17 14:00:22 +08:00
Frontend service: Fix geomap assets not loading (#110146)
* attempting to "fix" geomap * copy gazetteer/maps folders into dockerfile for frontend service * add TODO comments * remove unused import * conditionally use public cdn path * fix unit tests * try refactor e2e test for better stability * Revert "try refactor e2e test for better stability" This reverts commit d966d68e15922613755e120f536bba5436c43d1f. * safer * use grafana_public_path
This commit is contained in:
@ -3409,8 +3409,7 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||||
[0, 0, 0, "Do not use any type assertions.", "5"],
|
[0, 0, 0, "Do not use any type assertions.", "5"],
|
||||||
[0, 0, 0, "Do not use any type assertions.", "6"],
|
[0, 0, 0, "Do not use any type assertions.", "6"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "8"]
|
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/graphite/configuration/ConfigEditor.tsx:5381": [
|
"public/app/plugins/datasource/graphite/configuration/ConfigEditor.tsx:5381": [
|
||||||
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],
|
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],
|
||||||
|
@ -93,6 +93,8 @@ docker_build('grafana-fs-dev',
|
|||||||
'public/dashboards',
|
'public/dashboards',
|
||||||
'public/app/plugins',
|
'public/app/plugins',
|
||||||
'public/build/assets-manifest.json',
|
'public/build/assets-manifest.json',
|
||||||
|
'public/gazetteer',
|
||||||
|
'public/maps',
|
||||||
],
|
],
|
||||||
|
|
||||||
# Sync paths are relative to the Tiltfile
|
# Sync paths are relative to the Tiltfile
|
||||||
|
@ -22,9 +22,11 @@ COPY public/emails public/emails
|
|||||||
COPY public/views public/views
|
COPY public/views public/views
|
||||||
COPY public/dashboards public/dashboards
|
COPY public/dashboards public/dashboards
|
||||||
COPY public/app/plugins public/app/plugins
|
COPY public/app/plugins public/app/plugins
|
||||||
|
COPY public/gazetteer public/gazetteer
|
||||||
|
COPY public/maps public/maps
|
||||||
|
|
||||||
ADD devenv/frontend-service/build/grafana bin/grafana
|
ADD devenv/frontend-service/build/grafana bin/grafana
|
||||||
|
|
||||||
COPY public/build/assets-manifest.json public/build/assets-manifest.json
|
COPY public/build/assets-manifest.json public/build/assets-manifest.json
|
||||||
|
|
||||||
ENTRYPOINT ["bin/grafana", "server"]
|
ENTRYPOINT ["bin/grafana", "server"]
|
||||||
|
@ -2,8 +2,6 @@ import { getCenterPointWGS84 } from 'app/features/transformers/spatial/utils';
|
|||||||
|
|
||||||
import { getGazetteer } from './gazetteer';
|
import { getGazetteer } from './gazetteer';
|
||||||
|
|
||||||
let backendResults: Record<string, unknown> = { hello: 'world' };
|
|
||||||
|
|
||||||
const geojsonObject = {
|
const geojsonObject = {
|
||||||
type: 'FeatureCollection',
|
type: 'FeatureCollection',
|
||||||
features: [
|
features: [
|
||||||
@ -43,20 +41,16 @@ const geojsonObject = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('@grafana/runtime', () => ({
|
|
||||||
...jest.requireActual('@grafana/runtime'),
|
|
||||||
getBackendSrv: () => ({
|
|
||||||
get: jest.fn().mockResolvedValue(backendResults),
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('Placename lookup from geojson format', () => {
|
describe('Placename lookup from geojson format', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
backendResults = { hello: 'world' };
|
jest.spyOn(global, 'fetch').mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
json: jest.fn().mockResolvedValue(geojsonObject),
|
||||||
|
} as unknown as Response);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can lookup by id', async () => {
|
it('can lookup by id', async () => {
|
||||||
backendResults = geojsonObject;
|
|
||||||
const gaz = await getGazetteer('local');
|
const gaz = await getGazetteer('local');
|
||||||
expect(gaz.error).toBeUndefined();
|
expect(gaz.error).toBeUndefined();
|
||||||
expect(getCenterPointWGS84(gaz.find('A')?.geometry())).toMatchInlineSnapshot(`
|
expect(getCenterPointWGS84(gaz.find('A')?.geometry())).toMatchInlineSnapshot(`
|
||||||
@ -67,7 +61,6 @@ describe('Placename lookup from geojson format', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
it('can look up by a code', async () => {
|
it('can look up by a code', async () => {
|
||||||
backendResults = geojsonObject;
|
|
||||||
const gaz = await getGazetteer('airports');
|
const gaz = await getGazetteer('airports');
|
||||||
expect(gaz.error).toBeUndefined();
|
expect(gaz.error).toBeUndefined();
|
||||||
expect(getCenterPointWGS84(gaz.find('B')?.geometry())).toMatchInlineSnapshot(`
|
expect(getCenterPointWGS84(gaz.find('B')?.geometry())).toMatchInlineSnapshot(`
|
||||||
@ -79,7 +72,6 @@ describe('Placename lookup from geojson format', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can look up by an id property', async () => {
|
it('can look up by an id property', async () => {
|
||||||
backendResults = geojsonObject;
|
|
||||||
const gaz = await getGazetteer('airports');
|
const gaz = await getGazetteer('airports');
|
||||||
expect(gaz.error).toBeUndefined();
|
expect(gaz.error).toBeUndefined();
|
||||||
expect(getCenterPointWGS84(gaz.find('C')?.geometry())).toMatchInlineSnapshot(`
|
expect(getCenterPointWGS84(gaz.find('C')?.geometry())).toMatchInlineSnapshot(`
|
||||||
|
@ -2,7 +2,6 @@ import { getCenter } from 'ol/extent';
|
|||||||
import { Geometry, Point } from 'ol/geom';
|
import { Geometry, Point } from 'ol/geom';
|
||||||
|
|
||||||
import { DataFrame, Field, FieldType, KeyValue, toDataFrame } from '@grafana/data';
|
import { DataFrame, Field, FieldType, KeyValue, toDataFrame } from '@grafana/data';
|
||||||
import { getBackendSrv } from '@grafana/runtime';
|
|
||||||
|
|
||||||
import { frameFromGeoJSON } from '../format/geojson';
|
import { frameFromGeoJSON } from '../format/geojson';
|
||||||
import { pointFieldFromLonLat, pointFieldFromGeohash } from '../format/utils';
|
import { pointFieldFromLonLat, pointFieldFromGeohash } from '../format/utils';
|
||||||
@ -181,7 +180,7 @@ export function frameAsGazetter(frame: DataFrame, opts: { path: string; keys?: s
|
|||||||
|
|
||||||
const registry: KeyValue<Gazetteer> = {};
|
const registry: KeyValue<Gazetteer> = {};
|
||||||
|
|
||||||
export const COUNTRIES_GAZETTEER_PATH = 'public/gazetteer/countries.json';
|
export const COUNTRIES_GAZETTEER_PATH = `${window.__grafana_public_path__}build/gazetteer/countries.json`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a path to a file return a cached lookup function
|
* Given a path to a file return a cached lookup function
|
||||||
@ -196,7 +195,8 @@ export async function getGazetteer(path?: string): Promise<Gazetteer> {
|
|||||||
if (!lookup) {
|
if (!lookup) {
|
||||||
try {
|
try {
|
||||||
// block the async function
|
// block the async function
|
||||||
const data = await getBackendSrv().get(path!);
|
const response = await fetch(path);
|
||||||
|
const data = await response.json();
|
||||||
lookup = loadGazetteer(path, data);
|
lookup = loadGazetteer(path, data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('Error loading placename lookup', path, err);
|
console.warn('Error loading placename lookup', path, err);
|
||||||
|
@ -4,22 +4,18 @@ import countriesJSON from '../../../../gazetteer/countries.json';
|
|||||||
|
|
||||||
import { getGazetteer } from './gazetteer';
|
import { getGazetteer } from './gazetteer';
|
||||||
|
|
||||||
let backendResults: Record<string, string> | Array<Record<string, unknown>> = { hello: 'world' };
|
const backendResults: Record<string, string> | Array<Record<string, unknown>> = countriesJSON;
|
||||||
|
|
||||||
jest.mock('@grafana/runtime', () => ({
|
|
||||||
...jest.requireActual('@grafana/runtime'),
|
|
||||||
getBackendSrv: () => ({
|
|
||||||
get: jest.fn().mockResolvedValue(backendResults),
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('Placename lookup from worldmap format', () => {
|
describe('Placename lookup from worldmap format', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
backendResults = { hello: 'world' };
|
jest.spyOn(global, 'fetch').mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
json: jest.fn().mockResolvedValue(backendResults),
|
||||||
|
} as unknown as Response);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('unified worldmap config', async () => {
|
it('unified worldmap config', async () => {
|
||||||
backendResults = countriesJSON;
|
|
||||||
const gaz = await getGazetteer('countries');
|
const gaz = await getGazetteer('countries');
|
||||||
expect(gaz.error).toBeUndefined();
|
expect(gaz.error).toBeUndefined();
|
||||||
expect(toLonLat(gaz.find('US')?.point()?.getCoordinates()!)).toMatchInlineSnapshot(`
|
expect(toLonLat(gaz.find('US')?.point()?.getCoordinates()!)).toMatchInlineSnapshot(`
|
||||||
|
@ -10,10 +10,53 @@ const longitude = [0, -74.1];
|
|||||||
const latitude = [0, 40.7];
|
const latitude = [0, 40.7];
|
||||||
const geohash = ['9q94r', 'dr5rs'];
|
const geohash = ['9q94r', 'dr5rs'];
|
||||||
const names = ['A', 'B'];
|
const names = ['A', 'B'];
|
||||||
|
const geojsonObject = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
id: 'A',
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [0, 0],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
hello: 'A',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [1, 1],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
some_code: 'B',
|
||||||
|
hello: 'B',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [2, 2],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
an_id: 'C',
|
||||||
|
hello: 'C',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
describe('handle location parsing', () => {
|
describe('handle location parsing', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(console, 'warn').mockImplementation();
|
jest.spyOn(console, 'warn').mockImplementation();
|
||||||
|
jest.spyOn(global, 'fetch').mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
json: jest.fn().mockResolvedValue(geojsonObject),
|
||||||
|
} as unknown as Response);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('auto should find geohash field', async () => {
|
it('auto should find geohash field', async () => {
|
||||||
|
@ -180,7 +180,7 @@ export class GrafanaDatasource extends DataSourceWithBackend<GrafanaQuery> {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
maxDataPoints,
|
maxDataPoints,
|
||||||
} as any).pipe(
|
} as DataQueryRequest<GrafanaQuery>).pipe(
|
||||||
map((v) => {
|
map((v) => {
|
||||||
const frame = v.data[0] ?? new MutableDataFrame();
|
const frame = v.data[0] ?? new MutableDataFrame();
|
||||||
return new DataFrameView<FileElement>(frame);
|
return new DataFrameView<FileElement>(frame);
|
||||||
|
@ -394,7 +394,7 @@ export class GeomapPanel extends Component<Props, State> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mouseWheelZoom!.setActive(Boolean(options.mouseWheelZoom));
|
this.mouseWheelZoom?.setActive(Boolean(options.mouseWheelZoom));
|
||||||
|
|
||||||
if (options.showAttribution) {
|
if (options.showAttribution) {
|
||||||
this.map.addControl(new Attribution({ collapsed: true, collapsible: true }));
|
this.map.addControl(new Attribution({ collapsed: true, collapsible: true }));
|
||||||
|
@ -80,7 +80,7 @@ export const geojsonLayer: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
|||||||
const interpolatedUrl = getTemplateSrv().replace(config.src || '');
|
const interpolatedUrl = getTemplateSrv().replace(config.src || '');
|
||||||
|
|
||||||
const source = new VectorSource({
|
const source = new VectorSource({
|
||||||
url: interpolatedUrl,
|
url: `${window.__grafana_public_path__}build/${interpolatedUrl.replace(/^(public\/)/, '')}`,
|
||||||
format: new GeoJSON(),
|
format: new GeoJSON(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ describe('Worldmap Migrations', () => {
|
|||||||
"min": 2,
|
"min": 2,
|
||||||
},
|
},
|
||||||
"symbol": {
|
"symbol": {
|
||||||
"fixed": "img/icons/marker/circle.svg",
|
"fixed": "build/img/icons/marker/circle.svg",
|
||||||
"mode": "fixed",
|
"mode": "fixed",
|
||||||
},
|
},
|
||||||
"symbolAlign": {
|
"symbolAlign": {
|
||||||
|
@ -74,7 +74,7 @@ export const defaultStyleConfig = Object.freeze({
|
|||||||
opacity: 0.4,
|
opacity: 0.4,
|
||||||
symbol: {
|
symbol: {
|
||||||
mode: ResourceDimensionMode.Fixed,
|
mode: ResourceDimensionMode.Fixed,
|
||||||
fixed: 'img/icons/marker/circle.svg',
|
fixed: 'build/img/icons/marker/circle.svg',
|
||||||
},
|
},
|
||||||
symbolAlign: {
|
symbolAlign: {
|
||||||
horizontal: HorizontalAlign.Center,
|
horizontal: HorizontalAlign.Center,
|
||||||
|
@ -75,6 +75,14 @@ module.exports = {
|
|||||||
from: 'public/img',
|
from: 'public/img',
|
||||||
to: 'img',
|
to: 'img',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
from: 'public/maps',
|
||||||
|
to: 'maps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'public/gazetteer',
|
||||||
|
to: 'gazetteer',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
Reference in New Issue
Block a user