mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Geomap: refactor and cleanup structures (#52760)
Co-authored-by: Adela Almasan <adela.almasan@grafana.com>
This commit is contained in:
parent
7eabd7c83a
commit
238d761450
@ -5656,18 +5656,16 @@ exports[`better eslint`] = {
|
||||
"public/app/features/search/service/bluge.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "6"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "7"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "8"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "9"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "10"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "12"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "13"]
|
||||
[0, 0, 0, "Do not use any type assertions.", "11"]
|
||||
],
|
||||
"public/app/features/search/service/sql.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
@ -7042,7 +7040,8 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Do not use any type assertions.", "7"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "8"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "10"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "10"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "11"]
|
||||
],
|
||||
"public/app/plugins/datasource/graphite/components/FunctionEditor.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
@ -8698,6 +8697,19 @@ exports[`better eslint`] = {
|
||||
"public/app/plugins/panel/geomap/components/DataHoverView.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/plugins/panel/geomap/components/MarkersLegend.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[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.", "5"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "6"]
|
||||
],
|
||||
"public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"]
|
||||
],
|
||||
"public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
@ -8716,6 +8728,35 @@ exports[`better eslint`] = {
|
||||
"public/app/plugins/panel/geomap/editor/MapViewEditor.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/plugins/panel/geomap/editor/StyleEditor.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "7"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "8"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "9"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "10"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "11"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "12"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "13"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "14"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "15"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "16"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "17"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "18"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "19"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "20"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "21"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "22"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "23"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "24"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "25"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "26"]
|
||||
],
|
||||
"public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
|
@ -12,7 +12,7 @@ export interface DimensionSupplier<T = any> {
|
||||
isAssumed?: boolean;
|
||||
|
||||
/**
|
||||
* The fied used for
|
||||
* The field used for
|
||||
*/
|
||||
field?: Field;
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { ArrayVector, DataFrame, DataFrameView, getDisplayProcessor, SelectableValue } from '@grafana/data';
|
||||
import { config, getDataSourceSrv } from '@grafana/runtime';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { TermCount } from 'app/core/components/TagFilter/TagFilter';
|
||||
import { GrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
|
||||
import { getGrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
|
||||
import { GrafanaQueryType } from 'app/plugins/datasource/grafana/types';
|
||||
|
||||
import { replaceCurrentFolderQuery } from './utils';
|
||||
@ -19,7 +19,7 @@ export class BlugeSearcher implements GrafanaSearcher {
|
||||
}
|
||||
|
||||
async tags(query: SearchQuery): Promise<TermCount[]> {
|
||||
const ds = (await getDataSourceSrv().get('-- Grafana --')) as GrafanaDatasource;
|
||||
const ds = await getGrafanaDatasource();
|
||||
const target = {
|
||||
refId: 'TagsQuery',
|
||||
queryType: GrafanaQueryType.Search,
|
||||
@ -74,7 +74,7 @@ const nextPageSizes = 100;
|
||||
|
||||
async function doSearchQuery(query: SearchQuery): Promise<QueryResponse> {
|
||||
query = await replaceCurrentFolderQuery(query);
|
||||
const ds = (await getDataSourceSrv().get('-- Grafana --')) as GrafanaDatasource;
|
||||
const ds = await getGrafanaDatasource();
|
||||
const target = {
|
||||
refId: 'Search',
|
||||
queryType: GrafanaQueryType.Search,
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
import {
|
||||
DataSourceWithBackend,
|
||||
getBackendSrv,
|
||||
getDataSourceSrv,
|
||||
getGrafanaLiveSrv,
|
||||
getTemplateSrv,
|
||||
StreamingFrameOptions,
|
||||
@ -211,6 +212,11 @@ export class GrafanaDatasource extends DataSourceWithBackend<GrafanaQuery> {
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the GrafanaDatasource instance */
|
||||
export async function getGrafanaDatasource() {
|
||||
return (await getDataSourceSrv().get('-- Grafana --')) as GrafanaDatasource;
|
||||
}
|
||||
|
||||
export interface FileElement {
|
||||
name: string;
|
||||
['media-type']: string;
|
||||
|
@ -1,18 +1,20 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { useStyles2, VizLegendItem } from '@grafana/ui';
|
||||
import { DataFrame, formattedValueToString, getFieldColorModeForField, GrafanaTheme2 } from '@grafana/data';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import BaseLayer from 'ol/layer/Base';
|
||||
import React, { useMemo } from 'react';
|
||||
import SVG from 'react-inlinesvg';
|
||||
import { useObservable } from 'react-use';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { DataFrame, formattedValueToString, getFieldColorModeForField, GrafanaTheme2 } from '@grafana/data';
|
||||
import { getMinMaxAndDelta } from '@grafana/data/src/field/scale';
|
||||
import { useStyles2, VizLegendItem } from '@grafana/ui';
|
||||
import { ColorScale } from 'app/core/components/ColorScale/ColorScale';
|
||||
import { config } from 'app/core/config';
|
||||
import { DimensionSupplier } from 'app/features/dimensions';
|
||||
import { getThresholdItems } from 'app/plugins/panel/state-timeline/utils';
|
||||
import { getMinMaxAndDelta } from '@grafana/data/src/field/scale';
|
||||
import SVG from 'react-inlinesvg';
|
||||
import { StyleConfigState } from '../../style/types';
|
||||
import { ColorScale } from 'app/core/components/ColorScale/ColorScale';
|
||||
import { useObservable } from 'react-use';
|
||||
import { of } from 'rxjs';
|
||||
import BaseLayer from 'ol/layer/Base';
|
||||
import { MapLayerState } from '../../types';
|
||||
|
||||
import { StyleConfigState } from '../style/types';
|
||||
import { MapLayerState } from '../types';
|
||||
|
||||
export interface MarkersLegendProps {
|
||||
size?: DimensionSupplier<number>;
|
||||
@ -48,7 +50,7 @@ export function MarkersLegend(props: MarkersLegendProps) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const { color, opacity} = styleConfig?.base ?? {};
|
||||
const { color, opacity } = styleConfig?.base ?? {};
|
||||
const symbol = styleConfig?.config.symbol?.fixed;
|
||||
|
||||
if (color && symbol && !colorField) {
|
||||
@ -64,7 +66,7 @@ export function MarkersLegend(props: MarkersLegendProps) {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!colorField) {
|
||||
@ -87,12 +89,21 @@ export function MarkersLegend(props: MarkersLegendProps) {
|
||||
// ]
|
||||
// })
|
||||
|
||||
const display = colorField.display ? (v: number) => formattedValueToString(colorField.display!(v)) : (v: number) => `${v}`;
|
||||
const display = colorField.display
|
||||
? (v: number) => formattedValueToString(colorField.display!(v))
|
||||
: (v: number) => `${v}`;
|
||||
return (
|
||||
<div className={style.infoWrap}>
|
||||
<div className={style.layerName}>{layerName}</div>
|
||||
<div className={cx(style.layerBody, style.colorScaleWrapper)}>
|
||||
<ColorScale hoverValue={hoverValue} colorPalette={colors} min={colorRange.min as number} max={colorRange.max as number} display={display} useStopsPercentage={false}/>
|
||||
<ColorScale
|
||||
hoverValue={hoverValue}
|
||||
colorPalette={colors}
|
||||
min={colorRange.min as number}
|
||||
max={colorRange.max as number}
|
||||
display={display}
|
||||
useStopsPercentage={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
@ -0,0 +1,84 @@
|
||||
import React, { FC, useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import {
|
||||
FrameMatcherID,
|
||||
getFieldDisplayName,
|
||||
MatcherConfig,
|
||||
SelectableValue,
|
||||
StandardEditorProps,
|
||||
} from '@grafana/data';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
const recoverRefIdMissing = (
|
||||
newRefIds: SelectableValue[],
|
||||
oldRefIds: SelectableValue[],
|
||||
previousValue: string | undefined
|
||||
): SelectableValue | undefined => {
|
||||
if (!previousValue) {
|
||||
return;
|
||||
}
|
||||
// Previously selected value is missing from the new list.
|
||||
// Find the value that is in the new list but isn't in the old list
|
||||
let changedTo = newRefIds.find((refId) => {
|
||||
return !oldRefIds.some((refId2) => {
|
||||
return refId === refId2;
|
||||
});
|
||||
});
|
||||
if (changedTo) {
|
||||
// Found the new value, we assume the old value changed to this one, so we'll use it
|
||||
return changedTo;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
export const FrameSelectionEditor: FC<StandardEditorProps<MatcherConfig>> = ({ value, context, onChange, item }) => {
|
||||
const listOfRefId = useMemo(() => {
|
||||
return context.data.map((f) => ({
|
||||
value: f.refId,
|
||||
label: `Query: ${f.refId} (size: ${f.length})`,
|
||||
description: f.fields.map((f) => getFieldDisplayName(f)).join(', '),
|
||||
}));
|
||||
}, [context.data]);
|
||||
|
||||
const [priorSelectionState, updatePriorSelectionState] = useState({
|
||||
refIds: [] as SelectableValue[],
|
||||
value: undefined as string | undefined,
|
||||
});
|
||||
|
||||
const currentValue = useMemo(() => {
|
||||
return (
|
||||
listOfRefId.find((refId) => refId.value === value?.options) ??
|
||||
recoverRefIdMissing(listOfRefId, priorSelectionState.refIds, priorSelectionState.value)
|
||||
);
|
||||
}, [value, listOfRefId, priorSelectionState]);
|
||||
|
||||
const onFilterChange = useCallback(
|
||||
(v: SelectableValue<string>) => {
|
||||
onChange(
|
||||
v?.value
|
||||
? {
|
||||
id: FrameMatcherID.byRefId,
|
||||
options: v.value,
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
},
|
||||
[onChange]
|
||||
);
|
||||
|
||||
if (listOfRefId !== priorSelectionState.refIds || currentValue?.value !== priorSelectionState.value) {
|
||||
updatePriorSelectionState({
|
||||
refIds: listOfRefId,
|
||||
value: currentValue?.value,
|
||||
});
|
||||
}
|
||||
return (
|
||||
<Select
|
||||
options={listOfRefId}
|
||||
onChange={onFilterChange}
|
||||
isClearable={true}
|
||||
placeholder="Change filter"
|
||||
value={currentValue}
|
||||
/>
|
||||
);
|
||||
};
|
@ -1,4 +1,8 @@
|
||||
import { capitalize } from 'lodash';
|
||||
import React, { FC } from 'react';
|
||||
import { useObservable } from 'react-use';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
import { StandardEditorProps } from '@grafana/data';
|
||||
import {
|
||||
ColorPicker,
|
||||
@ -9,10 +13,8 @@ import {
|
||||
InlineLabel,
|
||||
RadioButtonGroup,
|
||||
} from '@grafana/ui';
|
||||
import { Observable } from 'rxjs';
|
||||
import { useObservable } from 'react-use';
|
||||
import { capitalize } from 'lodash';
|
||||
|
||||
import { NumberValueEditor } from 'app/core/components/OptionsUI/number';
|
||||
import { SliderValueEditor } from 'app/core/components/OptionsUI/slider';
|
||||
import {
|
||||
ColorDimensionEditor,
|
||||
ResourceDimensionEditor,
|
||||
@ -29,11 +31,10 @@ import {
|
||||
defaultTextConfig,
|
||||
ScalarDimensionConfig,
|
||||
} from 'app/features/dimensions/types';
|
||||
import { defaultStyleConfig, GeometryTypeId, StyleConfig, TextAlignment, TextBaseline } from '../../style/types';
|
||||
import { styleUsesText } from '../../style/utils';
|
||||
import { LayerContentInfo } from '../../utils/getFeatures';
|
||||
import { NumberValueEditor } from 'app/core/components/OptionsUI/number';
|
||||
import { SliderValueEditor } from 'app/core/components/OptionsUI/slider';
|
||||
|
||||
import { defaultStyleConfig, GeometryTypeId, StyleConfig, TextAlignment, TextBaseline } from '../style/types';
|
||||
import { styleUsesText } from '../style/utils';
|
||||
import { LayerContentInfo } from '../utils/getFeatures';
|
||||
|
||||
export interface StyleEditorOptions {
|
||||
layerInfo?: Observable<LayerContentInfo>;
|
||||
@ -93,11 +94,8 @@ export const StyleEditor: FC<StandardEditorProps<StyleConfig, StyleEditorOptions
|
||||
onChange({ ...value, textConfig: { ...value.textConfig, textBaseline: textBaseline as TextBaseline } });
|
||||
};
|
||||
|
||||
let featuresHavePoints = false;
|
||||
if (settings?.layerInfo) {
|
||||
const propertyOptions = useObservable(settings?.layerInfo);
|
||||
featuresHavePoints = propertyOptions?.geometryType === GeometryTypeId.Point;
|
||||
}
|
||||
const propertyOptions = useObservable(settings?.layerInfo ?? of());
|
||||
const featuresHavePoints = propertyOptions?.geometryType === GeometryTypeId.Point;
|
||||
const hasTextLabel = styleUsesText(value);
|
||||
|
||||
// Simple fixed value display
|
@ -8,13 +8,14 @@ import { GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/da
|
||||
import { Button, InlineField, InlineFieldRow, Select, useStyles2 } from '@grafana/ui';
|
||||
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
|
||||
|
||||
import { StyleEditor } from '../layers/data/StyleEditor';
|
||||
import { DEFAULT_STYLE_RULE } from '../layers/data/geojsonLayer';
|
||||
import { defaultStyleConfig, StyleConfig } from '../style/types';
|
||||
import { ComparisonOperation, FeatureStyleConfig } from '../types';
|
||||
import { getUniqueFeatureValues, LayerContentInfo } from '../utils/getFeatures';
|
||||
import { getSelectionInfo } from '../utils/selection';
|
||||
|
||||
import { StyleEditor } from './StyleEditor';
|
||||
|
||||
export interface StyleRuleEditorSettings {
|
||||
features: Observable<FeatureLike[]>;
|
||||
layerInfo: Observable<LayerContentInfo>;
|
||||
|
@ -5,11 +5,12 @@ import { NestedPanelOptions, NestedValueAccess } from '@grafana/data/src/utils/O
|
||||
import { setOptionImmutably } from 'app/features/dashboard/components/PanelEditor/utils';
|
||||
import { addLocationFields } from 'app/features/geo/editor/locationEditor';
|
||||
|
||||
import { FrameSelectionEditor } from '../layers/data/FrameSelectionEditor';
|
||||
import { defaultMarkersConfig } from '../layers/data/markersLayer';
|
||||
import { DEFAULT_BASEMAP_CONFIG, geomapLayerRegistry, getLayersOptions } from '../layers/registry';
|
||||
import { MapLayerState } from '../types';
|
||||
|
||||
import { FrameSelectionEditor } from './FrameSelectionEditor';
|
||||
|
||||
export interface LayerEditorOptions {
|
||||
state: MapLayerState;
|
||||
category: string[];
|
||||
|
@ -1,62 +0,0 @@
|
||||
import React, { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { FrameMatcherID, getFieldDisplayName, MatcherConfig, SelectableValue, StandardEditorProps } from '@grafana/data';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
const recoverRefIdMissing = (newRefIds: SelectableValue[], oldRefIds: SelectableValue[], previousValue: string | undefined): SelectableValue | undefined => {
|
||||
if (!previousValue) {
|
||||
return;
|
||||
}
|
||||
// Previously selected value is missing from the new list.
|
||||
// Find the value that is in the new list but isn't in the old list
|
||||
let changedTo = newRefIds.find((refId) => {
|
||||
return !oldRefIds.some((refId2) => {
|
||||
return refId === refId2;
|
||||
});
|
||||
});
|
||||
if (changedTo) {
|
||||
// Found the new value, we assume the old value changed to this one, so we'll use it
|
||||
return changedTo;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
export const FrameSelectionEditor: FC<StandardEditorProps<MatcherConfig>> = ({
|
||||
value,
|
||||
context,
|
||||
onChange,
|
||||
item,
|
||||
}) => {
|
||||
const listOfRefId = useMemo(() => {
|
||||
return context.data.map(f => ({
|
||||
value: f.refId,
|
||||
label: `Query: ${f.refId} (size: ${f.length})`,
|
||||
description: f.fields.map(f => getFieldDisplayName(f)).join(', '),
|
||||
}));
|
||||
}, [context.data]);
|
||||
|
||||
const [priorSelectionState, updatePriorSelectionState] = useState({
|
||||
refIds: [] as SelectableValue[],
|
||||
value: undefined as string | undefined,
|
||||
});
|
||||
|
||||
const currentValue = useMemo(() => {
|
||||
return listOfRefId.find((refId) => refId.value === value?.options) ?? recoverRefIdMissing(listOfRefId, priorSelectionState.refIds, priorSelectionState.value);
|
||||
}, [value, listOfRefId])
|
||||
|
||||
const onFilterChange = useCallback((v: SelectableValue<string>) => {
|
||||
onChange(v?.value ? {
|
||||
"id": FrameMatcherID.byRefId,
|
||||
"options": v.value
|
||||
} : undefined);
|
||||
}, [context.options.name]);
|
||||
|
||||
if (listOfRefId !== priorSelectionState.refIds || currentValue?.value !== priorSelectionState.value) {
|
||||
updatePriorSelectionState({
|
||||
refIds: listOfRefId,
|
||||
value: currentValue?.value
|
||||
});
|
||||
}
|
||||
return (
|
||||
<Select options={listOfRefId} onChange={onFilterChange} isClearable={true} placeholder="Change filter" value={currentValue}/>
|
||||
);
|
||||
};
|
@ -1,10 +1,8 @@
|
||||
import {
|
||||
MapLayerRegistryItem,
|
||||
MapLayerOptions,
|
||||
PanelData,
|
||||
GrafanaTheme2,
|
||||
PluginState,
|
||||
SelectableValue,
|
||||
EventBus,
|
||||
} from '@grafana/data';
|
||||
import Map from 'ol/Map';
|
||||
@ -20,12 +18,11 @@ import { GeomapStyleRulesEditor } from '../../editor/GeomapStyleRulesEditor';
|
||||
import { defaultStyleConfig, StyleConfig, StyleConfigState } from '../../style/types';
|
||||
import { getStyleConfigState } from '../../style/utils';
|
||||
import { polyStyle } from '../../style/markers';
|
||||
import { StyleEditor } from './StyleEditor';
|
||||
import { StyleEditor } from '../../editor/StyleEditor';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { map as rxjsmap, first } from 'rxjs/operators';
|
||||
import { getLayerPropertyInfo } from '../../utils/getFeatures';
|
||||
import { GrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
import { getPublicGeoJSONFiles } from '../../utils/utils';
|
||||
|
||||
export interface GeoJSONMapperConfig {
|
||||
// URL for a geojson file
|
||||
@ -60,8 +57,6 @@ export const DEFAULT_STYLE_RULE: FeatureStyleConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
let publicGeoJSONFiles: Array<SelectableValue<string>> | undefined = undefined;
|
||||
|
||||
export const geojsonLayer: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
id: 'geojson',
|
||||
name: 'GeoJSON',
|
||||
@ -153,9 +148,6 @@ export const geojsonLayer: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
|
||||
return {
|
||||
init: () => vectorLayer,
|
||||
update: (data: PanelData) => {
|
||||
console.log('todo... find values matching the ID and update');
|
||||
},
|
||||
registerOptionsUI: (builder) => {
|
||||
// get properties for first feature to use as ui options
|
||||
const layerInfo = features.pipe(
|
||||
@ -163,16 +155,12 @@ export const geojsonLayer: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
rxjsmap((v) => getLayerPropertyInfo(v))
|
||||
);
|
||||
|
||||
if (!publicGeoJSONFiles) {
|
||||
initGeojsonFiles();
|
||||
}
|
||||
|
||||
builder
|
||||
.addSelect({
|
||||
path: 'config.src',
|
||||
name: 'GeoJSON URL',
|
||||
settings: {
|
||||
options: publicGeoJSONFiles ?? [],
|
||||
options: getPublicGeoJSONFiles() ?? [],
|
||||
allowCustomValue: true,
|
||||
},
|
||||
defaultValue: defaultOptions.src,
|
||||
@ -207,27 +195,3 @@ export const geojsonLayer: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
defaultOptions,
|
||||
};
|
||||
|
||||
// This will find all geojson files in the maps and gazetteer folders
|
||||
async function initGeojsonFiles() {
|
||||
if (publicGeoJSONFiles) {
|
||||
return;
|
||||
}
|
||||
publicGeoJSONFiles = [];
|
||||
|
||||
const ds = (await getDataSourceSrv().get('-- Grafana --')) as GrafanaDatasource;
|
||||
for (let folder of ['maps', 'gazetteer']) {
|
||||
ds.listFiles(folder).subscribe({
|
||||
next: (frame) => {
|
||||
frame.forEach((item) => {
|
||||
if (item.name.endsWith('.geojson')) {
|
||||
const value = `public/${folder}/${item.name}`;
|
||||
publicGeoJSONFiles!.push({
|
||||
value,
|
||||
label: value,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,4 +8,11 @@ import { dayNightLayer } from './dayNightLayer';
|
||||
/**
|
||||
* Registry for layer handlers
|
||||
*/
|
||||
export const dataLayers = [markersLayer, heatmapLayer, lastPointTracker, geojsonLayer, dayNightLayer, routeLayer];
|
||||
export const dataLayers = [
|
||||
markersLayer,
|
||||
heatmapLayer,
|
||||
lastPointTracker,
|
||||
geojsonLayer,
|
||||
dayNightLayer,
|
||||
routeLayer,
|
||||
];
|
||||
|
@ -10,16 +10,16 @@ import {
|
||||
import Map from 'ol/Map';
|
||||
import { FeatureLike } from 'ol/Feature';
|
||||
import { getLocationMatchers } from 'app/features/geo/utils/location';
|
||||
import { getScaledDimension, getColorDimension, getTextDimension, getScalarDimension } from 'app/features/dimensions';
|
||||
import { ObservablePropsWrapper } from '../../components/ObservablePropsWrapper';
|
||||
import { MarkersLegend, MarkersLegendProps } from './MarkersLegend';
|
||||
import { MarkersLegend, MarkersLegendProps } from '../../components/MarkersLegend';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { defaultStyleConfig, StyleConfig, StyleDimensions } from '../../style/types';
|
||||
import { StyleEditor } from './StyleEditor';
|
||||
import { defaultStyleConfig, StyleConfig } from '../../style/types';
|
||||
import { StyleEditor } from '../../editor/StyleEditor';
|
||||
import { getStyleConfigState } from '../../style/utils';
|
||||
import VectorLayer from 'ol/layer/Vector';
|
||||
import { isNumber } from 'lodash';
|
||||
import { FrameVectorSource } from 'app/features/geo/utils/frameVectorSource';
|
||||
import { getStyleDimension} from '../../utils/utils';
|
||||
|
||||
// Configuration options for Circle overlays
|
||||
export interface MarkersConfig {
|
||||
@ -121,22 +121,7 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
}
|
||||
|
||||
for (const frame of data.series) {
|
||||
if (style.fields) {
|
||||
const dims: StyleDimensions = {};
|
||||
if (style.fields.color) {
|
||||
dims.color = getColorDimension(frame, style.config.color ?? defaultStyleConfig.color, theme);
|
||||
}
|
||||
if (style.fields.size) {
|
||||
dims.size = getScaledDimension(frame, style.config.size ?? defaultStyleConfig.size);
|
||||
}
|
||||
if (style.fields.text) {
|
||||
dims.text = getTextDimension(frame, style.config.text!);
|
||||
}
|
||||
if (style.fields.rotation) {
|
||||
dims.rotation = getScalarDimension(frame, style.config.rotation ?? defaultStyleConfig.rotation);
|
||||
}
|
||||
style.dims = dims;
|
||||
}
|
||||
style.dims = getStyleDimension(frame, style, theme);
|
||||
|
||||
// Post updates to the legend component
|
||||
if (legend) {
|
||||
|
@ -17,7 +17,7 @@ import { Subscription, throttleTime } from 'rxjs';
|
||||
import { getGeometryField, getLocationMatchers } from 'app/features/geo/utils/location';
|
||||
import { getColorDimension } from 'app/features/dimensions';
|
||||
import { defaultStyleConfig, StyleConfig, StyleDimensions } from '../../style/types';
|
||||
import { StyleEditor } from './StyleEditor';
|
||||
import { StyleEditor } from '../../editor/StyleEditor';
|
||||
import { getStyleConfigState } from '../../style/utils';
|
||||
import VectorLayer from 'ol/layer/Vector';
|
||||
import { isNumber } from 'lodash';
|
||||
|
70
public/app/plugins/panel/geomap/utils/utils.ts
Normal file
70
public/app/plugins/panel/geomap/utils/utils.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { DataFrame, GrafanaTheme2 } from '@grafana/data/src';
|
||||
import { getColorDimension, getScalarDimension, getScaledDimension, getTextDimension } from 'app/features/dimensions';
|
||||
import { getGrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
|
||||
|
||||
import { defaultStyleConfig, StyleConfig, StyleConfigState, StyleDimensions } from '../style/types';
|
||||
|
||||
export function getStyleDimension(
|
||||
frame: DataFrame | undefined,
|
||||
style: StyleConfigState,
|
||||
theme: GrafanaTheme2,
|
||||
customStyleConfig?: StyleConfig
|
||||
) {
|
||||
const dims: StyleDimensions = {};
|
||||
if (customStyleConfig && Object.keys(customStyleConfig).length) {
|
||||
dims.color = getColorDimension(frame, customStyleConfig.color ?? defaultStyleConfig.color, theme);
|
||||
dims.size = getScaledDimension(frame, customStyleConfig.size ?? defaultStyleConfig.size);
|
||||
dims.rotation = getScalarDimension(frame, customStyleConfig.rotation ?? defaultStyleConfig.rotation);
|
||||
if (customStyleConfig.text && (customStyleConfig.text.field || customStyleConfig.text.fixed)) {
|
||||
dims.text = getTextDimension(frame, customStyleConfig.text!);
|
||||
}
|
||||
} else {
|
||||
if (style.fields) {
|
||||
if (style.fields.color) {
|
||||
dims.color = getColorDimension(frame, style.config.color ?? defaultStyleConfig.color, theme);
|
||||
}
|
||||
if (style.fields.size) {
|
||||
dims.size = getScaledDimension(frame, style.config.size ?? defaultStyleConfig.size);
|
||||
}
|
||||
if (style.fields.text) {
|
||||
dims.text = getTextDimension(frame, style.config.text!);
|
||||
}
|
||||
if (style.fields.rotation) {
|
||||
dims.rotation = getScalarDimension(frame, style.config.rotation ?? defaultStyleConfig.rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dims;
|
||||
}
|
||||
|
||||
let publicGeoJSONFiles: Array<SelectableValue<string>> | undefined = undefined;
|
||||
|
||||
export function getPublicGeoJSONFiles(): Array<SelectableValue<string>> {
|
||||
if (!publicGeoJSONFiles) {
|
||||
publicGeoJSONFiles = [];
|
||||
initGeojsonFiles(); // async
|
||||
}
|
||||
return publicGeoJSONFiles;
|
||||
}
|
||||
|
||||
// This will find all geojson files in the maps and gazetteer folders
|
||||
async function initGeojsonFiles() {
|
||||
const ds = await getGrafanaDatasource();
|
||||
for (let folder of ['maps', 'gazetteer']) {
|
||||
ds.listFiles(folder).subscribe({
|
||||
next: (frame) => {
|
||||
frame.forEach((item) => {
|
||||
if (item.name.endsWith('.geojson')) {
|
||||
const value = `public/${folder}/${item.name}`;
|
||||
publicGeoJSONFiles!.push({
|
||||
value,
|
||||
label: value,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user