Geomap panel: Generate types (#61636)

This commit is contained in:
Alex Khomenko 2023-01-24 01:12:56 +02:00 committed by GitHub
parent 7ccc845187
commit 3006a457f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 325 additions and 184 deletions

View File

@ -277,8 +277,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"] [0, 0, 0, "Unexpected any. Specify a different type.", "0"]
], ],
"packages/grafana-data/src/geo/layer.ts:5381": [ "packages/grafana-data/src/geo/layer.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"]
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
], ],
"packages/grafana-data/src/panel/PanelPlugin.test.tsx:5381": [ "packages/grafana-data/src/panel/PanelPlugin.test.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
@ -584,8 +583,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "2"], [0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"], [0, 0, 0, "Unexpected any. Specify a different type.", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "4"], [0, 0, 0, "Unexpected any. Specify a different type.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"], [0, 0, 0, "Unexpected any. Specify a different type.", "5"]
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
], ],
"packages/grafana-data/src/types/variables.ts:5381": [ "packages/grafana-data/src/types/variables.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"] [0, 0, 0, "Unexpected any. Specify a different type.", "0"]
@ -993,10 +991,14 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "3"], [0, 0, 0, "Do not use any type assertions.", "3"],
[0, 0, 0, "Do not use any type assertions.", "4"] [0, 0, 0, "Do not use any type assertions.", "4"]
], ],
"packages/grafana-schema/src/veneer/common.types.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"packages/grafana-schema/src/veneer/dashboard.types.ts:5381": [ "packages/grafana-schema/src/veneer/dashboard.types.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Do not use any type assertions.", "2"] [0, 0, 0, "Do not use any type assertions.", "2"],
[0, 0, 0, "Do not use any type assertions.", "3"]
], ],
"packages/grafana-toolkit/src/cli/tasks/component.create.ts:5381": [ "packages/grafana-toolkit/src/cli/tasks/component.create.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],

View File

@ -413,7 +413,7 @@ lineage: seqs: [
#MatcherConfig: { #MatcherConfig: {
id: string | *"" @grafanamaturity(NeedsExpertReview) id: string | *"" @grafanamaturity(NeedsExpertReview)
options?: _ @grafanamaturity(NeedsExpertReview) options?: _ @grafanamaturity(NeedsExpertReview)
} @cuetsy(kind="interface") } @cuetsy(kind="interface") @grafana(TSVeneer="type")
#DynamicConfigValue: { #DynamicConfigValue: {
id: string | *"" @grafanamaturity(NeedsExpertReview) id: string | *"" @grafanamaturity(NeedsExpertReview)

View File

@ -2,74 +2,23 @@ import { Map as OpenLayersMap } from 'ol';
import BaseLayer from 'ol/layer/Base'; import BaseLayer from 'ol/layer/Base';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { MapLayerOptions, FrameGeometrySourceMode } from '@grafana/schema';
import { EventBus } from '../events'; import { EventBus } from '../events';
import { GrafanaTheme2 } from '../themes'; import { GrafanaTheme2 } from '../themes';
import { MatcherConfig, PanelData } from '../types'; import { PanelData } from '../types';
import { PanelOptionsEditorBuilder } from '../utils'; import { PanelOptionsEditorBuilder } from '../utils';
import { RegistryItemWithOptions } from '../utils/Registry'; import { RegistryItemWithOptions } from '../utils/Registry';
/** /**
* @alpha * @deprecated use the type from schema
*/ */
export enum FrameGeometrySourceMode { export { FrameGeometrySourceMode };
Auto = 'auto', // Will scan fields and find best match
Geohash = 'geohash',
Coords = 'coords', // lon field, lat field
Lookup = 'lookup', // keys > location
// H3 = 'h3',
// WKT = 'wkt,
// geojson? geometry text
}
/** /**
* @alpha * @deprecated use the type from schema
*/ */
export interface FrameGeometrySource { export type { FrameGeometrySource, MapLayerOptions } from '@grafana/schema';
mode: FrameGeometrySourceMode;
// Field mappings
geohash?: string;
latitude?: string;
longitude?: string;
h3?: string;
wkt?: string;
lookup?: string;
// Path to Gazetteer
gazetteer?: string;
}
/**
* This gets saved in panel json
*
* depending on the type, it may have additional config
*
* This exists in `grafana/data` so the types are well known and extendable but the
* layout/frame is control by the map panel
*
* @alpha
*/
export interface MapLayerOptions<TConfig = any> {
type: string;
name: string; // configured unique display name
// Custom options depending on the type
config?: TConfig;
// Common method to define geometry fields
location?: FrameGeometrySource;
// Defines which data query refId is associated with the layer
filterData?: MatcherConfig;
// Common properties:
// https://openlayers.org/en/latest/apidoc/module-ol_layer_Base-BaseLayer.html
// Layer opacity (0-1)
opacity?: number;
// Check tooltip (defaults to true)
tooltip?: boolean;
}
/** /**
* @alpha * @alpha
@ -81,7 +30,7 @@ export interface MapLayerHandler<TConfig = any> {
*/ */
update?: (data: PanelData) => void; update?: (data: PanelData) => void;
/** Optional callback to cleaup before getting removed */ /** Optional callback for cleanup before getting removed */
dispose?: () => void; dispose?: () => void;
/** return react node for the legend */ /** return react node for the legend */

View File

@ -1,3 +1,4 @@
export type { MatcherConfig } from '@grafana/schema';
import { MonoTypeOperatorFunction } from 'rxjs'; import { MonoTypeOperatorFunction } from 'rxjs';
import { RegistryItemWithOptions } from '../utils/Registry'; import { RegistryItemWithOptions } from '../utils/Registry';
@ -80,10 +81,6 @@ export interface ValueMatcherInfo<TOptions = any> extends RegistryItemWithOption
isApplicable: (field: Field) => boolean; isApplicable: (field: Field) => boolean;
getDefaultOptions: (field: Field) => TOptions; getDefaultOptions: (field: Field) => TOptions;
} }
export interface MatcherConfig<TOptions = any> {
id: string;
options?: TOptions;
}
/** /**
* @public * @public

View File

@ -40,6 +40,43 @@ export interface DataQuery {
refId: string; refId: string;
} }
export interface MapLayerOptions {
/**
* Custom options depending on the type
*/
config?: unknown;
/**
* Defines a frame MatcherConfig that may filter data for the given layer
*/
filterData?: unknown;
/**
* Common method to define geometry fields
*/
location?: FrameGeometrySource;
/**
* configured unique display name
*/
name: string;
/**
* Common properties:
* https://openlayers.org/en/latest/apidoc/module-ol_layer_Base-BaseLayer.html
* Layer opacity (0-1)
*/
opacity?: number;
/**
* Check tooltip (defaults to true)
*/
tooltip?: boolean;
type: string;
}
export enum FrameGeometrySourceMode {
Auto = 'auto',
Coords = 'coords',
Geohash = 'geohash',
Lookup = 'lookup',
}
/** /**
* TODO docs * TODO docs
*/ */
@ -595,6 +632,22 @@ export interface DataSourceRef {
uid?: string; uid?: string;
} }
export interface FrameGeometrySource {
/**
* Path to Gazetteer
*/
gazetteer?: string;
/**
* Field mappings
*/
geohash?: string;
latitude?: string;
longitude?: string;
lookup?: string;
mode: FrameGeometrySourceMode;
wkt?: string;
}
/** /**
* TODO docs * TODO docs
*/ */

View File

@ -0,0 +1,33 @@
package common
MapLayerOptions: {
type: string
// configured unique display name
name: string
// Custom options depending on the type
config?: _
// Common method to define geometry fields
location?: FrameGeometrySource
// Defines a frame MatcherConfig that may filter data for the given layer
filterData?: _
// Common properties:
// https://openlayers.org/en/latest/apidoc/module-ol_layer_Base-BaseLayer.html
// Layer opacity (0-1)
opacity?: int64
// Check tooltip (defaults to true)
tooltip?: bool
} @cuetsy(kind="interface") @grafana(TSVeneer="type")
FrameGeometrySourceMode: "auto" | "geohash" |"coords" | "lookup" @cuetsy(kind="enum",memberNames="Auto|Geohash|Coords|Lookup")
FrameGeometrySource: {
mode: FrameGeometrySourceMode
// Field mappings
geohash?: string
latitude?: string
longitude?: string
wkt?: string
lookup?: string
// Path to Gazetteer
gazetteer?: string
} @cuetsy(kind="interface")

View File

@ -1,7 +1,5 @@
package common package common
// TODO break this up into individual files. Current limitation on this is codegen logic, imports, dependencies
// TODO docs // TODO docs
AxisPlacement: "auto" | "top" | "right" | "bottom" | "left" | "hidden" @cuetsy(kind="enum") AxisPlacement: "auto" | "top" | "right" | "bottom" | "left" | "hidden" @cuetsy(kind="enum")

View File

@ -26,7 +26,6 @@ export type {
SpecialValueMap, SpecialValueMap,
ValueMappingResult, ValueMappingResult,
Transformation, Transformation,
MatcherConfig,
RowPanel, RowPanel,
GraphPanel, GraphPanel,
HeatmapPanel HeatmapPanel
@ -46,7 +45,6 @@ export {
SpecialValueMatch, SpecialValueMatch,
DashboardCursorSync, DashboardCursorSync,
defaultDashboardCursorSync, defaultDashboardCursorSync,
defaultMatcherConfig,
defaultRowPanel defaultRowPanel
} from './raw/dashboard/x/dashboard_types.gen'; } from './raw/dashboard/x/dashboard_types.gen';
@ -65,6 +63,7 @@ export type {
DataSourceRef, DataSourceRef,
Panel, Panel,
FieldConfigSource, FieldConfigSource,
MatcherConfig,
FieldConfig FieldConfig
} from './veneer/dashboard.types'; } from './veneer/dashboard.types';
@ -83,6 +82,7 @@ export {
VariableHide, VariableHide,
defaultPanel, defaultPanel,
defaultFieldConfigSource, defaultFieldConfigSource,
defaultMatcherConfig,
defaultFieldConfig defaultFieldConfig
} from './veneer/dashboard.types'; } from './veneer/dashboard.types';

View File

@ -1,5 +1,13 @@
import * as raw from '../common/common.gen'; import * as raw from '../common/common.gen';
import { MatcherConfig } from './dashboard.types';
export interface MapLayerOptions<TConfig = any> extends raw.MapLayerOptions {
// Custom options depending on the type
config?: TConfig;
filterData?: MatcherConfig;
}
export interface DataQuery extends raw.DataQuery { export interface DataQuery extends raw.DataQuery {
// TODO remove explicit nulls // TODO remove explicit nulls
datasource?: raw.DataSourceRef | null; datasource?: raw.DataSourceRef | null;

View File

@ -43,6 +43,10 @@ export interface FieldConfigSource<TOptions = Record<string, unknown>> extends r
defaults: FieldConfig<TOptions>; defaults: FieldConfig<TOptions>;
} }
export interface MatcherConfig<TConfig = any> extends raw.MatcherConfig {
options?: TConfig;
}
export const defaultDashboard = raw.defaultDashboard as Dashboard; export const defaultDashboard = raw.defaultDashboard as Dashboard;
export const defaultVariableModel = { export const defaultVariableModel = {
...raw.defaultVariableModel, ...raw.defaultVariableModel,
@ -60,3 +64,4 @@ export const defaultVariableModel = {
export const defaultPanel: Partial<Panel> = raw.defaultPanel; export const defaultPanel: Partial<Panel> = raw.defaultPanel;
export const defaultFieldConfig: Partial<FieldConfig> = raw.defaultFieldConfig; export const defaultFieldConfig: Partial<FieldConfig> = raw.defaultFieldConfig;
export const defaultFieldConfigSource: Partial<FieldConfigSource> = raw.defaultFieldConfigSource; export const defaultFieldConfigSource: Partial<FieldConfigSource> = raw.defaultFieldConfigSource;
export const defaultMatcherConfig: Partial<MatcherConfig> = raw.defaultMatcherConfig;

View File

@ -1,11 +1,5 @@
import { import { Field, FieldType, PanelOptionsEditorBuilder, DataFrame } from '@grafana/data';
Field, import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
FieldType,
FrameGeometrySource,
FrameGeometrySourceMode,
PanelOptionsEditorBuilder,
DataFrame,
} from '@grafana/data';
import { GazetteerPathEditor } from 'app/features/geo/editor/GazetteerPathEditor'; import { GazetteerPathEditor } from 'app/features/geo/editor/GazetteerPathEditor';
import { LocationModeEditor } from './locationModeEditor'; import { LocationModeEditor } from './locationModeEditor';

View File

@ -1,14 +1,9 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { import { StandardEditorProps, DataFrame, GrafanaTheme2 } from '@grafana/data';
StandardEditorProps,
FrameGeometrySourceMode,
DataFrame,
FrameGeometrySource,
GrafanaTheme2,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { Alert, HorizontalGroup, Icon, Select, useStyles2 } from '@grafana/ui'; import { Alert, HorizontalGroup, Icon, Select, useStyles2 } from '@grafana/ui';
import { FrameGeometryField, getGeometryField, getLocationMatchers } from '../utils/location'; import { FrameGeometryField, getGeometryField, getLocationMatchers } from '../utils/location';

View File

@ -1,7 +1,8 @@
import { Point } from 'ol/geom'; import { Point } from 'ol/geom';
import { toLonLat } from 'ol/proj'; import { toLonLat } from 'ol/proj';
import { toDataFrame, FieldType, FrameGeometrySourceMode } from '@grafana/data'; import { toDataFrame, FieldType } from '@grafana/data';
import { FrameGeometrySourceMode } from '@grafana/schema';
import { getGeometryField, getLocationFields, getLocationMatchers } from './location'; import { getGeometryField, getLocationFields, getLocationMatchers } from './location';

View File

@ -1,8 +1,6 @@
import { Geometry } from 'ol/geom'; import { Geometry } from 'ol/geom';
import { import {
FrameGeometrySource,
FrameGeometrySourceMode,
FieldMatcher, FieldMatcher,
getFieldMatcher, getFieldMatcher,
FieldMatcherID, FieldMatcherID,
@ -11,6 +9,7 @@ import {
getFieldDisplayName, getFieldDisplayName,
FieldType, FieldType,
} from '@grafana/data'; } from '@grafana/data';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { getGeoFieldFromGazetteer, pointFieldFromGeohash, pointFieldFromLonLat } from '../format/utils'; import { getGeoFieldFromGazetteer, pointFieldFromGeohash, pointFieldFromLonLat } from '../format/utils';
import { getGazetteer, Gazetteer } from '../gazetteer/gazetteer'; import { getGazetteer, Gazetteer } from '../gazetteer/gazetteer';

View File

@ -3,8 +3,6 @@ import React, { useEffect } from 'react';
import { import {
DataTransformerID, DataTransformerID,
FrameGeometrySource,
FrameGeometrySourceMode,
GrafanaTheme2, GrafanaTheme2,
PanelOptionsEditorBuilder, PanelOptionsEditorBuilder,
PluginState, PluginState,
@ -12,6 +10,7 @@ import {
TransformerRegistryItem, TransformerRegistryItem,
TransformerUIProps, TransformerUIProps,
} from '@grafana/data'; } from '@grafana/data';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { useTheme2 } from '@grafana/ui'; import { useTheme2 } from '@grafana/ui';
import { addLocationFields } from 'app/features/geo/editor/locationEditor'; import { addLocationFields } from 'app/features/geo/editor/locationEditor';

View File

@ -1,4 +1,4 @@
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/data'; import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
// This file should be generated by cue schema // This file should be generated by cue schema

View File

@ -25,7 +25,7 @@ import { GeomapHoverPayload } from './event';
import { getGlobalStyles } from './globalStyles'; import { getGlobalStyles } from './globalStyles';
import { defaultMarkersConfig } from './layers/data/markersLayer'; import { defaultMarkersConfig } from './layers/data/markersLayer';
import { DEFAULT_BASEMAP_CONFIG } from './layers/registry'; import { DEFAULT_BASEMAP_CONFIG } from './layers/registry';
import { ControlsOptions, GeomapPanelOptions, MapLayerState, MapViewConfig, TooltipMode } from './types'; import { ControlsOptions, PanelOptions, MapLayerState, MapViewConfig, TooltipMode } from './types';
import { getActions } from './utils/actions'; import { getActions } from './utils/actions';
import { getLayersExtent } from './utils/getLayersExtent'; import { getLayersExtent } from './utils/getLayersExtent';
import { applyLayerFilter, initLayer } from './utils/layers'; import { applyLayerFilter, initLayer } from './utils/layers';
@ -36,7 +36,7 @@ import { centerPointRegistry, MapCenterID } from './view';
// Allows multiple panels to share the same view instance // Allows multiple panels to share the same view instance
let sharedView: View | undefined = undefined; let sharedView: View | undefined = undefined;
type Props = PanelProps<GeomapPanelOptions>; type Props = PanelProps<PanelOptions>;
interface State extends OverlayProps { interface State extends OverlayProps {
ttip?: GeomapHoverPayload; ttip?: GeomapHoverPayload;
ttipOpen: boolean; ttipOpen: boolean;
@ -144,7 +144,7 @@ export class GeomapPanel extends Component<Props, State> {
* *
* NOTE: changes to basemap and layers are handled independently * NOTE: changes to basemap and layers are handled independently
*/ */
optionsChanged(options: GeomapPanelOptions) { optionsChanged(options: PanelOptions) {
const oldOptions = this.props.options; const oldOptions = this.props.options;
if (options.view !== oldOptions.view) { if (options.view !== oldOptions.view) {
const [updatedSharedView, view] = this.initMapView(options.view, sharedView); const [updatedSharedView, view] = this.initMapView(options.view, sharedView);

View File

@ -4,13 +4,13 @@ import { SelectableValue, StandardEditorContext } from '@grafana/data';
import { InlineFieldRow, InlineField, RadioButtonGroup, Select } from '@grafana/ui'; import { InlineFieldRow, InlineField, RadioButtonGroup, Select } from '@grafana/ui';
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput'; import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
import { GeomapInstanceState, GeomapPanelOptions, MapViewConfig } from '../types'; import { GeomapInstanceState, PanelOptions, MapViewConfig } from '../types';
type Props = { type Props = {
labelWidth: number; labelWidth: number;
value: MapViewConfig; value: MapViewConfig;
onChange: (value?: MapViewConfig | undefined) => void; onChange: (value?: MapViewConfig | undefined) => void;
context: StandardEditorContext<GeomapPanelOptions, GeomapInstanceState>; context: StandardEditorContext<PanelOptions, GeomapInstanceState>;
}; };
// Data scope options for 'Fit to data' // Data scope options for 'Fit to data'

View File

@ -7,9 +7,9 @@ import { AddLayerButton } from 'app/core/components/Layers/AddLayerButton';
import { LayerDragDropList } from 'app/core/components/Layers/LayerDragDropList'; import { LayerDragDropList } from 'app/core/components/Layers/LayerDragDropList';
import { getLayersOptions } from '../layers/registry'; import { getLayersOptions } from '../layers/registry';
import { GeomapPanelOptions, MapLayerState, GeomapInstanceState } from '../types'; import { PanelOptions, MapLayerState, GeomapInstanceState } from '../types';
type LayersEditorProps = StandardEditorProps<unknown, unknown, GeomapPanelOptions, GeomapInstanceState>; type LayersEditorProps = StandardEditorProps<unknown, unknown, PanelOptions, GeomapInstanceState>;
export const LayersEditor = (props: LayersEditorProps) => { export const LayersEditor = (props: LayersEditorProps) => {
const { layers, selected, actions } = props.context.instanceState ?? {}; const { layers, selected, actions } = props.context.instanceState ?? {};

View File

@ -5,7 +5,7 @@ import { StandardEditorProps, SelectableValue } from '@grafana/data';
import { Button, InlineField, InlineFieldRow, Select, VerticalGroup } from '@grafana/ui'; import { Button, InlineField, InlineFieldRow, Select, VerticalGroup } from '@grafana/ui';
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput'; import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
import { GeomapPanelOptions, MapViewConfig, GeomapInstanceState } from '../types'; import { PanelOptions, MapViewConfig, GeomapInstanceState } from '../types';
import { centerPointRegistry, MapCenterID } from '../view'; import { centerPointRegistry, MapCenterID } from '../view';
import { CoordinatesMapViewEditor } from './CoordinatesMapViewEditor'; import { CoordinatesMapViewEditor } from './CoordinatesMapViewEditor';
@ -15,7 +15,7 @@ export const MapViewEditor = ({
value, value,
onChange, onChange,
context, context,
}: StandardEditorProps<MapViewConfig, unknown, GeomapPanelOptions, GeomapInstanceState>) => { }: StandardEditorProps<MapViewConfig, unknown, PanelOptions, GeomapInstanceState>) => {
const labelWidth = 10; const labelWidth = 10;
const views = useMemo(() => { const views = useMemo(() => {

View File

@ -1,14 +1,13 @@
import { import {
MapLayerRegistryItem, MapLayerRegistryItem,
MapLayerOptions,
PanelData, PanelData,
GrafanaTheme2, GrafanaTheme2,
FrameGeometrySourceMode,
EventBus, EventBus,
PluginState, PluginState,
FieldType, FieldType,
Field, Field,
} from '@grafana/data'; } from '@grafana/data';
import { FrameGeometrySourceMode, MapLayerOptions } from '@grafana/schema';
import Map from 'ol/Map'; import Map from 'ol/Map';
import { FeatureLike } from 'ol/Feature'; import { FeatureLike } from 'ol/Feature';
import { getLocationMatchers } from 'app/features/geo/utils/location'; import { getLocationMatchers } from 'app/features/geo/utils/location';

View File

@ -1,9 +1,7 @@
import { import {
MapLayerRegistryItem, MapLayerRegistryItem,
MapLayerOptions,
PanelData, PanelData,
GrafanaTheme2, GrafanaTheme2,
FrameGeometrySourceMode,
PluginState, PluginState,
EventBus, EventBus,
DataHoverEvent, DataHoverEvent,
@ -11,6 +9,12 @@ import {
DataFrame, DataFrame,
TIME_SERIES_TIME_FIELD_NAME, TIME_SERIES_TIME_FIELD_NAME,
} from '@grafana/data'; } from '@grafana/data';
import {
MapLayerOptions,
FrameGeometrySourceMode,
} from '@grafana/schema';
import Map from 'ol/Map'; import Map from 'ol/Map';
import { FeatureLike } from 'ol/Feature'; import { FeatureLike } from 'ol/Feature';
import { Subscription, throttleTime } from 'rxjs'; import { Subscription, throttleTime } from 'rxjs';

View File

@ -6,7 +6,7 @@ import { ResourceDimensionMode } from 'app/features/dimensions';
import { MarkersConfig } from './layers/data/markersLayer'; import { MarkersConfig } from './layers/data/markersLayer';
import { getMarkerAsPath } from './style/markers'; import { getMarkerAsPath } from './style/markers';
import { defaultStyleConfig } from './style/types'; import { defaultStyleConfig } from './style/types';
import { GeomapPanelOptions, TooltipMode } from './types'; import { PanelOptions, TooltipMode } from './types';
import { MapCenterID } from './view'; import { MapCenterID } from './view';
/** /**
@ -26,13 +26,13 @@ export const mapPanelChangedHandler: PanelTypeChangedHandler = (panel, prevPlugi
return {}; return {};
}; };
export function worldmapToGeomapOptions(angular: any): { fieldConfig: FieldConfigSource; options: GeomapPanelOptions } { export function worldmapToGeomapOptions(angular: any): { fieldConfig: FieldConfigSource; options: PanelOptions } {
const fieldConfig: FieldConfigSource = { const fieldConfig: FieldConfigSource = {
defaults: {}, defaults: {},
overrides: [], overrides: [],
}; };
const options: GeomapPanelOptions = { const options: PanelOptions = {
view: { view: {
id: MapCenterID.Zero, id: MapCenterID.Zero,
}, },
@ -107,7 +107,7 @@ function asNumber(v: any): number | undefined {
return isNaN(num) ? undefined : num; return isNaN(num) ? undefined : num;
} }
export const mapMigrationHandler = (panel: PanelModel): Partial<GeomapPanelOptions> => { export const mapMigrationHandler = (panel: PanelModel): Partial<PanelOptions> => {
const pluginVersion = panel?.pluginVersion ?? ''; const pluginVersion = panel?.pluginVersion ?? '';
// before 8.3, only one layer was supported! // before 8.3, only one layer was supported!

View File

@ -0,0 +1,76 @@
// Copyright 2023 Grafana Labs
//
// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package grafanaplugin
import (
"github.com/grafana/thema"
ui "github.com/grafana/grafana/packages/grafana-schema/src/common"
)
Panel: thema.#Lineage & {
name: "geomap"
seqs: [
{
schemas: [
{
PanelOptions: {
view: MapViewConfig
controls: ControlsOptions
basemap: ui.MapLayerOptions
layers: [...ui.MapLayerOptions]
tooltip: TooltipOptions
} @cuetsy(kind="interface")
MapViewConfig: {
id: string | *"zero"
lat?: int64 | *0
lon?: int64 | *0
zoom?: int64 | *1
minZoom?: int64
maxZoom?: int64
padding?: int64
allLayers?: bool | *true
lastOnly?: bool
layer?: string
shared?: bool
} @cuetsy(kind="interface")
ControlsOptions: {
// Zoom (upper left)
showZoom?: bool
// let the mouse wheel zoom
mouseWheelZoom?: bool
// Lower right
showAttribution?: bool
// Scale options
showScale?: bool
// Show debug
showDebug?: bool
// Show measure
showMeasure?: bool
} @cuetsy(kind="interface")
TooltipOptions: {
mode: TooltipMode
} @cuetsy(kind="interface")
TooltipMode: "none" | "details" @cuetsy(kind="enum",memberNames="None|Details")
MapCenterID: "zero"|"coords"|"fit" @cuetsy(kind="enum",members="Zero|Coordinates|Fit")
},
]
},
]
}

View File

@ -0,0 +1,89 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
//
// Generated by:
// public/app/plugins/gen.go
// Using jennies:
// TSTypesJenny
// PluginTSTypesJenny
//
// Run 'make gen-cue' from repository root to regenerate.
import * as ui from '@grafana/schema';
export const PanelModelVersion = Object.freeze([0, 0]);
export interface PanelOptions {
basemap: ui.MapLayerOptions;
controls: ControlsOptions;
layers: Array<ui.MapLayerOptions>;
tooltip: TooltipOptions;
view: MapViewConfig;
}
export const defaultPanelOptions: Partial<PanelOptions> = {
layers: [],
};
export interface MapViewConfig {
allLayers?: boolean;
id: string;
lastOnly?: boolean;
lat?: number;
layer?: string;
lon?: number;
maxZoom?: number;
minZoom?: number;
padding?: number;
shared?: boolean;
zoom?: number;
}
export const defaultMapViewConfig: Partial<MapViewConfig> = {
allLayers: true,
id: 'zero',
lat: 0,
lon: 0,
zoom: 1,
};
export interface ControlsOptions {
/**
* let the mouse wheel zoom
*/
mouseWheelZoom?: boolean;
/**
* Lower right
*/
showAttribution?: boolean;
/**
* Show debug
*/
showDebug?: boolean;
/**
* Show measure
*/
showMeasure?: boolean;
/**
* Scale options
*/
showScale?: boolean;
/**
* Zoom (upper left)
*/
showZoom?: boolean;
}
export interface TooltipOptions {
mode: TooltipMode;
}
export enum TooltipMode {
Details = 'details',
None = 'none',
}
export enum MapCenterID {
Coords = 'coords',
Fit = 'fit',
Zero = 'zero',
}

View File

@ -9,9 +9,9 @@ import { LayersEditor } from './editor/LayersEditor';
import { MapViewEditor } from './editor/MapViewEditor'; import { MapViewEditor } from './editor/MapViewEditor';
import { getLayerEditor } from './editor/layerEditor'; import { getLayerEditor } from './editor/layerEditor';
import { mapPanelChangedHandler, mapMigrationHandler } from './migrations'; import { mapPanelChangedHandler, mapMigrationHandler } from './migrations';
import { defaultView, GeomapPanelOptions, TooltipMode, GeomapInstanceState } from './types'; import { defaultMapViewConfig, PanelOptions, TooltipMode, GeomapInstanceState } from './types';
export const plugin = new PanelPlugin<GeomapPanelOptions>(GeomapPanel) export const plugin = new PanelPlugin<PanelOptions>(GeomapPanel)
.setNoPadding() .setNoPadding()
.setPanelChangeHandler(mapPanelChangedHandler) .setPanelChangeHandler(mapPanelChangedHandler)
.setMigrationHandler(mapMigrationHandler) .setMigrationHandler(mapMigrationHandler)
@ -29,7 +29,7 @@ export const plugin = new PanelPlugin<GeomapPanelOptions>(GeomapPanel)
name: 'Initial view', // don't show it name: 'Initial view', // don't show it
description: 'This location will show when the panel first loads.', description: 'This location will show when the panel first loads.',
editor: MapViewEditor, editor: MapViewEditor,
defaultValue: defaultView, defaultValue: defaultMapViewConfig,
}); });
builder.addBooleanSwitch({ builder.addBooleanSwitch({
@ -37,7 +37,7 @@ export const plugin = new PanelPlugin<GeomapPanelOptions>(GeomapPanel)
path: 'view.shared', path: 'view.shared',
description: 'Use the same view across multiple panels. Note: this may require a dashboard reload.', description: 'Use the same view across multiple panels. Note: this may require a dashboard reload.',
name: 'Share view', name: 'Share view',
defaultValue: defaultView.shared, defaultValue: defaultMapViewConfig.shared,
}); });
// eslint-disable-next-line // eslint-disable-next-line

View File

@ -5,75 +5,13 @@ import BaseLayer from 'ol/layer/Base';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { MapLayerHandler, MapLayerOptions } from '@grafana/data'; import { MapLayerHandler, MapLayerOptions } from '@grafana/data';
import { HideableFieldConfig } from '@grafana/schema';
import { LayerElement } from 'app/core/components/Layers/types'; import { LayerElement } from 'app/core/components/Layers/types';
import { ControlsOptions as ControlsOptionsBase } from './models.gen';
import { StyleConfig } from './style/types'; import { StyleConfig } from './style/types';
import { MapCenterID } from './view';
export interface ControlsOptions { export interface ControlsOptions extends ControlsOptionsBase {
// Zoom (upper left)
showZoom?: boolean;
// let the mouse wheel zoom
mouseWheelZoom?: boolean;
// Lower right
showAttribution?: boolean;
// Scale options
showScale?: boolean;
scaleUnits?: Units; scaleUnits?: Units;
// Show debug
showDebug?: boolean;
// Show measure
showMeasure?: boolean;
}
export enum TooltipMode {
None = 'none',
Details = 'details',
}
export interface TooltipOptions {
mode: TooltipMode;
}
export interface MapViewConfig {
id: string; // placename > lookup
lat?: number;
lon?: number;
zoom?: number;
minZoom?: number;
maxZoom?: number;
padding?: number;
allLayers?: boolean;
lastOnly?: boolean;
layer?: string;
shared?: boolean;
}
export const defaultView: MapViewConfig = {
id: MapCenterID.Zero,
lat: 0,
lon: 0,
zoom: 1,
allLayers: true,
};
/** Support hide from legend/tooltip */
export interface GeomapFieldConfig extends HideableFieldConfig {
// nothing custom yet
}
export interface GeomapPanelOptions {
view: MapViewConfig;
controls: ControlsOptions;
basemap: MapLayerOptions;
layers: MapLayerOptions[];
tooltip: TooltipOptions;
} }
export interface FeatureStyleConfig { export interface FeatureStyleConfig {
@ -122,3 +60,5 @@ export interface MapLayerState<TConfig = unknown> extends LayerElement {
isBasemap?: boolean; isBasemap?: boolean;
mouseEvents: Subject<FeatureLike | undefined>; mouseEvents: Subject<FeatureLike | undefined>;
} }
export { PanelOptions, MapViewConfig, TooltipOptions, TooltipMode, defaultMapViewConfig } from './models.gen';

View File

@ -1,6 +1,6 @@
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { FrameGeometrySourceMode } from '@grafana/data/src'; import { FrameGeometrySourceMode } from '@grafana/schema';
import { GeomapPanel } from '../GeomapPanel'; import { GeomapPanel } from '../GeomapPanel';
import { geomapLayerRegistry } from '../layers/registry'; import { geomapLayerRegistry } from '../layers/registry';

View File

@ -8,7 +8,7 @@ import { getGrafanaDatasource } from 'app/plugins/datasource/grafana/datasource'
import { GeomapPanel } from '../GeomapPanel'; import { GeomapPanel } from '../GeomapPanel';
import { defaultStyleConfig, StyleConfig, StyleConfigState, StyleDimensions } from '../style/types'; import { defaultStyleConfig, StyleConfig, StyleConfigState, StyleDimensions } from '../style/types';
import { GeomapPanelOptions, MapLayerState } from '../types'; import { PanelOptions, MapLayerState } from '../types';
export function getStyleDimension( export function getStyleDimension(
frame: DataFrame | undefined, frame: DataFrame | undefined,
@ -74,7 +74,7 @@ async function initGeojsonFiles() {
} }
} }
export const getNewOpenLayersMap = (panel: GeomapPanel, options: GeomapPanelOptions, div: HTMLDivElement) => { export const getNewOpenLayersMap = (panel: GeomapPanel, options: PanelOptions, div: HTMLDivElement) => {
const [view] = panel.initMapView(options.view, undefined); const [view] = panel.initMapView(options.view, undefined);
return (panel.map = new OpenLayersMap({ return (panel.map = new OpenLayersMap({
view: view, view: view,
@ -88,7 +88,7 @@ export const getNewOpenLayersMap = (panel: GeomapPanel, options: GeomapPanelOpti
})); }));
}; };
export const updateMap = (panel: GeomapPanel, options: GeomapPanelOptions) => { export const updateMap = (panel: GeomapPanel, options: PanelOptions) => {
panel.initControls(options.controls); panel.initControls(options.controls);
panel.forceUpdate(); // first render panel.forceUpdate(); // first render
}; };