Geomap: Custom markers using ResourcePicker with standard marker fallbacks (#39919)

* add custom icons

* use resourcePicker for marker icon

* use regular shapes for specific icons

* update type

* update svgs and remove marker shape selection

* update types and resourcePicker

* add migration and update markers

Co-authored-by: Ryan McKinley <ryantxu@users.noreply.github.com>

* quick cleanup

* update marker path and remove any

* update migration test

* use inline snapshot

* remove unused

* Docs: Add documentation for library elements API (#39829)

* LibraryElements: Adds api documentation

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/http_api/library_element.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Refactor: changes after PR comments

* Apply suggestions from code review

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Chore: updates after review

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* CodeEditor: making sure we trigger the latest onSave callback provided to the component (#39835)

* Fix: prevent queryDisplyText in QueryRowHeader from overflowing (#40094)

* Revert "Fix Query Editor Row horizontal overflow (#39419)"

This reverts commit 42b1fa0f62.

* fix: prevent queryDisplyText in QueryRowHeader from overflowing

* Search: Fix local storage key (#40127)

* Default to 'General' if no folder title is present

* Add bottom padding

* Live: remote write sampling (#40079)

* Stat: recompute shared y range during streaming updates (#39485)

* NavBar: Order App plugins alphabetically (#40078)

* NavBar: Order App plugins alphabetically

* Update pkg/api/index.go

Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>

Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>

* Schema: use the generated graph.gen.ts (#40090)

* actually generate graph.gen.ts

* getting closer

* keep file where it is

* manual fixes

* Update packages/grafana-schema/src/schema/graph.gen.ts

Co-authored-by: sam boyer <sam.boyer@grafana.com>

* Docs: Whats new in 8.2 (#39945)

* Added time range controls updates

* Added plugins catalog update

* Added enterprise images

* Added community contributions highlights for 8.2

* accessibility statement

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-2.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>
Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Live: array for Processor, Outputter and Subscriber in channel rule top level (#39677)

* ReleaseNotes: Updated changelog and release notes for 8.1.7 (#40081)

* more

* more

Co-authored-by: sam boyer <sam.boyer@grafana.com>
Co-authored-by: Petros Kolyvas <code@petros.io>
Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>
Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
Co-authored-by: Alexander Emelin <frvzmb@gmail.com>
Co-authored-by: Grot (@grafanabot) <43478413+grafanabot@users.noreply.github.com>

* Access Control: Add scope type prefix (#40076)

* prefix runtime scopes with key type

* Bump mocha from 7.0.1 to 9.1.2 (#39979)

* Bump mocha from 7.0.1 to 9.1.2

Bumps [mocha](https://github.com/mochajs/mocha) from 7.0.1 to 9.1.2.
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v7.0.1...v9.1.2)

---
updated-dependencies:
- dependency-name: mocha
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* kick drone

* Remove mocha as it's not used by anything

* kick drone

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>

* ReleaseNotes: Updated changelog and release notes for 8.2.0 (#40141)

* ReleaseNotes: Updated changelog and release notes for 8.2.0

* Add link & remove empty line in CHANGELOG

* remove empty line

Co-authored-by: Elfo404 <me@giordanoricci.com>

* Create search filters by interface (#39843)

* Extract search users to a new service

* Fix wire provider

* Fix common_test and remove RouteRegister

* Remove old endpoints

* Fix test

* Create search filters using interfaces

* Move Enterprise filter, rename filter for filters and allow use filters with params

* Each filter has unique key

* Back activeLast30Days filter to OSS

* Fix tests

* Delete unusued param

* Move filters to searchusers service and small refactor

* Fix tests

* Encryption: Refactor securejsondata.SecureJsonData to stop relying on global functions (#38865)

* Encryption: Add support to encrypt/decrypt sjd

* Add datasources.Service as a proxy to datasources db operations

* Encrypt ds.SecureJsonData before calling SQLStore

* Move ds cache code into ds service

* Fix tlsmanager tests

* Fix pluginproxy tests

* Remove some securejsondata.GetEncryptedJsonData usages

* Add pluginsettings.Service as a proxy for plugin settings db operations

* Add AlertNotificationService as a proxy for alert notification db operations

* Remove some securejsondata.GetEncryptedJsonData usages

* Remove more securejsondata.GetEncryptedJsonData usages

* Fix lint errors

* Minor fixes

* Remove encryption global functions usages from ngalert

* Fix lint errors

* Minor fixes

* Minor fixes

* Remove securejsondata.DecryptedValue usage

* Refactor the refactor

* Remove securejsondata.DecryptedValue usage

* Move securejsondata to migrations package

* Move securejsondata to migrations package

* Minor fix

* Fix integration test

* Fix integration tests

* Undo undesired changes

* Fix tests

* Add context.Context into encryption methods

* Fix tests

* Fix tests

* Fix tests

* Trigger CI

* Fix test

* Add names to params of encryption service interface

* Remove bus from CacheServiceImpl

* Add logging

* Add keys to logger

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>

* Add missing key to logger

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>

* Undo changes in markdown files

* Fix formatting

* Add context to secrets service

* Rename decryptSecureJsonData to decryptSecureJsonDataFn

* Name args in GetDecryptedValueFn

* Add template back to NewAlertmanagerNotifier

* Copy GetDecryptedValueFn to ngalert

* Add logging to pluginsettings

* Fix pluginsettings test

Co-authored-by: Tania B <yalyna.ts@gmail.com>
Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>

* Admin: Enable extending filters (#39825)

* Setup extensible filters

* Fix test

* Handle filter as array

* Add className

* Abstract getFilters

* Make docs link external

* Use underline for links in tooltips instead of link color

Co-authored-by: Selene <selenepinillos@gmail.com>

* Chore: update latest.json to 8.2 (#40153)

* Doc: Fixed issue 40017 (#40152)

* Added content as suggested by Will

* removed a few extra words.

* Update docs/sources/administration/configuration.md

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

* Update docs/sources/administration/configuration.md

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

* Update docs/sources/administration/configuration.md

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>

* docs: Add keepCokkies cofiguration option in datasources (#39890)

Signed-off-by: Vinayak Kadam <kadamvinayak03@gmail.com>

* Grammar issues (#40168)

* Packaging: document systemd net bind capability rpm and deb installations (#40165)

* add systemd net bind capability docs for rpm and deb

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Alerting: declare constants for __dashboardUid__ and __panelId__ literals (#39976)

* Babel: Remove unused plugin (#40172)

* removed unused babel plugin

* Update lock file

* Chore(dependencies): Remove puppeteer since we don't use it anywhere (#40137)

* Folders: Prevents deletion of General folder (#40192)

* Datasources: Fix deletion of datasource if plugin cannot be found  (#40095)

* fix(pluginsettings): reject with error so datasource plugin loading failures still render ui

* feat(pluginpage): handle plugin loading error

* refactor(datasources): separate out datasource and meta loading so store has info for deletion

* fix(datasourcesettings): introduce loading flag to wait for datasource and meta loading

* test(datasourcesettings): fix failing test

* test(datasources): assert loading status of datasource settings

* test(datasources): update action tests for latest changes

* Replace SAML library with fork (#40149)

* Update saml library to latest

* Use fork of crewjam/saml with fix for certificate chain bug

* CloudMonitoring: Migrate to use backend plugin SDK contracts (#38650)

* Use SDK contracts for cloudmonitoring

* Get build running, tests passing and do some refactoring (#38754)

* fix build+tests and refactor

* remove alerting stuff

* remove unused field

* fix plugin fetch

* end to end

* resp rename

* tidy annotations

* reformatting

* update refID

* reformat imports

* fix styling

* clean up unmarshalling

* uncomment + fix tests

* appease linter

* remove spaces

* remove old cruft

* add check for empty queries

* update tests

* remove pm as dep

* adjust proxy route contract

* fix service loading

* use UNIX val

* fix endpoint + resp

* h@ckz for frontend

* fix resp

* fix interval

* always set custom meta

* remove unused param

* fix labels fetch

* fix linter

* fix test + remove unused field

* apply pr feedback

* fix grafana-auto intervals

* fix tests

* resolve conflicts

* fix bad merge

* fix conflicts

* remove bad logger import

Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
Co-authored-by: Will Browne <will.browne@grafana.com>

* Do codegen and check no-diff of all (non-blacklisted) CUE->TS codegen during CI (#39922)

* Add file blacklist to `grafana-cli cue gen-ts` cmd

* Add CI step checking all cuetsification is done

* Add dummy command to make the next one fail

* Generate drone bits

* Check diff output failure

* Echo list of untracked files, for failure locality

* Move git cleanness checking into script

* Blacklist of cue files is complete and correct

* Remove news panel plugin from cuetsify blacklist

* Dummy commit, check that untracked gen still fail

* Tie off remaining errors

* Re-add barchart to blacklist
* Remove file left around by earlier pipeline
* Commit generated news models.gen.ts

* Include eslint as part of cuetsified output gen

* Update pkg/cmd/grafana-cli/commands/cuetsify_command.go

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>

* Update scripts/drone/steps/lib.star

Co-authored-by: Maria Alexandra <239999+axelavargas@users.noreply.github.com>

* Update drone.yml

* Last fix on .drone.yml

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
Co-authored-by: Maria Alexandra <239999+axelavargas@users.noreply.github.com>

* Alerting: add organziation ID to the ngAlert webhook payload (#40189)

* Alerting: add organziation ID to the ngAlert webhook payload

* remove systemcallfilters sections from systemd unit files (#40176)

* Add Headers to http client Options (#40214)

* Docs: Add required library for the image renderer (#40201)

* update permissions scopes and description for role scopes (#40206)

* Chore: Migrate yarn from v1 to v2 (#39082)

* Chore: Migrate yarn from v1 to v2

Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>

* ReleaseNotes: Updated changelog and release notes for 8.2.0 (#40233)

Co-authored-by: Ryan McKinley <ryantxu@users.noreply.github.com>
Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
Co-authored-by: Giordano Ricci <me@giordanoricci.com>
Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
Co-authored-by: Alexander Emelin <frvzmb@gmail.com>
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
Co-authored-by: sam boyer <sam.boyer@grafana.com>
Co-authored-by: Petros Kolyvas <code@petros.io>
Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>
Co-authored-by: Grot (@grafanabot) <43478413+grafanabot@users.noreply.github.com>
Co-authored-by: Karl Persson <kalle.persson@grafana.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Selene <selenepinillos@gmail.com>
Co-authored-by: Joan López de la Franca Beltran <5459617+joanlopez@users.noreply.github.com>
Co-authored-by: Tania B <yalyna.ts@gmail.com>
Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
Co-authored-by: Vinayak <vinayak03@users.noreply.github.com>
Co-authored-by: Anne E. Ulrich <aeulrich1997@gmail.com>
Co-authored-by: Kevin Minehart <kmineh0151@gmail.com>
Co-authored-by: Yuriy Tseretyan <yuriy.tseretyan@grafana.com>
Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
Co-authored-by: Alexander Zobnin <alexanderzobnin@gmail.com>
Co-authored-by: idafurjes <36131195+idafurjes@users.noreply.github.com>
Co-authored-by: Will Browne <will.browne@grafana.com>
Co-authored-by: Maria Alexandra <239999+axelavargas@users.noreply.github.com>
Co-authored-by: Jean-Philippe Quéméner <JohnnyQQQQ@users.noreply.github.com>
Co-authored-by: Dimitris Sotirakis <dimitrios.sotirakis@grafana.com>
Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
This commit is contained in:
nikki-kiga 2021-10-08 15:49:04 -07:00 committed by GitHub
parent 12b5956af2
commit 7756181ff9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 344 additions and 50 deletions

View File

@ -4,6 +4,7 @@ import { ResourceDimensionConfig, ResourceDimensionMode, ResourceDimensionOption
import { InlineField, InlineFieldRow, RadioButtonGroup, Button, Modal, Input } from '@grafana/ui';
import { FieldNamePicker } from '../../../../../packages/grafana-ui/src/components/MatchersUI/FieldNamePicker';
import { ResourcePicker } from './ResourcePicker';
import { ResourceFolderName } from '..';
const resourceOptions = [
{ label: 'Fixed', value: ResourceDimensionMode.Fixed, description: 'Fixed value' },
@ -58,21 +59,24 @@ export const ResourceDimensionEditor: FC<
}, []);
const mode = value?.mode ?? ResourceDimensionMode.Fixed;
const showSourceRadio = item.settings?.showSourceRadio ?? true;
const mediaType = item.settings?.resourceType ?? 'icon';
const folderName = item.settings?.folderName ?? ResourceFolderName.Icon;
return (
<>
{isOpen && (
<Modal isOpen={isOpen} title={`Select ${mediaType}`} onDismiss={() => setOpen(false)} closeOnEscape>
<ResourcePicker onChange={onFixedChange} value={value?.fixed} mediaType={mediaType} />
<ResourcePicker onChange={onFixedChange} value={value?.fixed} mediaType={mediaType} folderName={folderName} />
</Modal>
)}
<InlineFieldRow>
<InlineField label="Source" labelWidth={labelWidth} grow={true}>
<RadioButtonGroup value={mode} options={resourceOptions} onChange={onModeChange} fullWidth />
</InlineField>
</InlineFieldRow>
{showSourceRadio && (
<InlineFieldRow>
<InlineField label="Source" labelWidth={labelWidth} grow={true}>
<RadioButtonGroup value={mode} options={resourceOptions} onChange={onModeChange} fullWidth />
</InlineField>
</InlineFieldRow>
)}
{mode !== ResourceDimensionMode.Fixed && (
<InlineFieldRow>
<InlineField label="Field" labelWidth={labelWidth} grow={true}>

View File

@ -18,11 +18,13 @@ import { css } from '@emotion/css';
import { getPublicOrAbsoluteUrl } from '../resource';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { FileElement, GrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
import { ResourceFolderName } from '..';
interface Props {
value?: string; //img/icons/unicons/0-plus.svg
onChange: (value?: string) => void;
mediaType: 'icon' | 'image';
folderName: ResourceFolderName;
}
interface ResourceItem {
@ -33,12 +35,13 @@ interface ResourceItem {
}
export function ResourcePicker(props: Props) {
const { value, onChange, mediaType } = props;
const folders = (mediaType === 'icon' ? ['img/icons/unicons', 'img/icons/iot'] : ['img/bg']).map((v) => ({
const { value, onChange, mediaType, folderName } = props;
const folders = getFolders(mediaType).map((v) => ({
label: v,
value: v,
}));
const folderOfCurrentValue = value ? folders.filter((folder) => value.indexOf(folder.value) > -1)[0] : folders[0];
const folderOfCurrentValue = value || folderName ? folderIfExists(folders, value ?? folderName) : folders[0];
const [currentFolder, setCurrentFolder] = useState<SelectableValue<string>>(folderOfCurrentValue);
const [tabs, setTabs] = useState([
{ label: 'Select', active: true },
@ -169,3 +172,15 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => {
`,
};
});
const getFolders = (mediaType: 'icon' | 'image') => {
if (mediaType === 'icon') {
return [ResourceFolderName.Icon, ResourceFolderName.IOT, ResourceFolderName.Marker];
} else {
return [ResourceFolderName.BG];
}
};
const folderIfExists = (folders: Array<{ label: string; value: string }>, path: string) => {
return folders.filter((folder) => path.indexOf(folder.value) > -1)[0] ?? folders[0];
};

View File

@ -71,6 +71,8 @@ export interface ColorDimensionConfig extends BaseDimensionConfig<string> {}
/** Places that use the value */
export interface ResourceDimensionOptions {
resourceType: 'icon' | 'image';
folderName?: ResourceFolderName;
showSourceRadio?: boolean;
}
export enum ResourceDimensionMode {
@ -84,3 +86,10 @@ export enum ResourceDimensionMode {
export interface ResourceDimensionConfig extends BaseDimensionConfig<string> {
mode: ResourceDimensionMode;
}
export enum ResourceFolderName {
Icon = 'img/icons/unicons',
IOT = 'img/icons/iot',
Marker = 'img/icons/marker',
BG = 'img/bg',
}

View File

@ -11,6 +11,7 @@ import Feature from 'ol/Feature';
import { Point } from 'ol/geom';
import * as layer from 'ol/layer';
import * as source from 'ol/source';
import * as style from 'ol/style';
import tinycolor from 'tinycolor2';
import { dataFrameToPoints, getLocationMatchers } from '../../utils/location';
@ -19,11 +20,15 @@ import {
ScaleDimensionConfig,
getScaledDimension,
getColorDimension,
ResourceDimensionConfig,
ResourceDimensionMode,
ResourceFolderName,
getPublicOrAbsoluteUrl,
} from 'app/features/dimensions';
import { ScaleDimensionEditor, ColorDimensionEditor } from 'app/features/dimensions/editors';
import { ScaleDimensionEditor, ColorDimensionEditor, ResourceDimensionEditor } from 'app/features/dimensions/editors';
import { ObservablePropsWrapper } from '../../components/ObservablePropsWrapper';
import { MarkersLegend, MarkersLegendProps } from './MarkersLegend';
import { circleMarker, markerMakers } from '../../utils/regularShapes';
import { StyleMaker, getMarkerFromPath, MarkerShapePath } from '../../utils/regularShapes';
import { ReplaySubject } from 'rxjs';
// Configuration options for Circle overlays
@ -31,13 +36,15 @@ export interface MarkersConfig {
size: ScaleDimensionConfig;
color: ColorDimensionConfig;
fillOpacity: number;
shape?: string;
showLegend?: boolean;
markerSymbol: ResourceDimensionConfig;
}
const DEFAULT_SIZE = 5;
const defaultOptions: MarkersConfig = {
size: {
fixed: 5,
fixed: DEFAULT_SIZE,
min: 2,
max: 15,
},
@ -45,8 +52,11 @@ const defaultOptions: MarkersConfig = {
fixed: 'dark-green', // picked from theme
},
fillOpacity: 0.4,
shape: 'circle',
showLegend: true,
markerSymbol: {
mode: ResourceDimensionMode.Fixed,
fixed: MarkerShapePath.Circle,
},
};
export const MARKERS_LAYER_ID = 'markers';
@ -88,7 +98,6 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
if (config.showLegend) {
legend = <ObservablePropsWrapper watch={legendProps} initialSubProps={{}} child={MarkersLegend} />;
}
const shape = markerMakers.getIfExists(config.shape) ?? circleMarker;
return {
init: () => vectorLayer,
@ -98,6 +107,24 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
return; // ignore empty
}
const markerPath =
getPublicOrAbsoluteUrl(config.markerSymbol?.fixed) ?? getPublicOrAbsoluteUrl(MarkerShapePath.Circle);
const marker = getMarkerFromPath(config.markerSymbol?.fixed);
const makeIconStyle = (color: string, fillColor: string, radius: number) => {
return new style.Style({
image: new style.Icon({
src: markerPath,
color,
// opacity,
scale: (DEFAULT_SIZE + radius) / 100,
}),
});
};
const shape: StyleMaker = marker?.make ?? makeIconStyle;
const features: Feature<Point>[] = [];
for (const frame of data.series) {
@ -126,8 +153,7 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
frame,
rowIndex: i,
});
dot.setStyle(shape!.make(color, fillColor, radius));
dot.setStyle(shape(color, fillColor, radius));
features.push(dot);
}
@ -150,17 +176,6 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
// Marker overlay options
registerOptionsUI: (builder) => {
builder
.addCustomEditor({
id: 'config.color',
path: 'config.color',
name: 'Marker Color',
editor: ColorDimensionEditor,
settings: {},
defaultValue: {
// Configured values
fixed: 'grey',
},
})
.addCustomEditor({
id: 'config.size',
path: 'config.size',
@ -172,18 +187,33 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
},
defaultValue: {
// Configured values
fixed: 5,
fixed: DEFAULT_SIZE,
min: 1,
max: 20,
},
})
.addSelect({
path: 'config.shape',
name: 'Marker Shape',
.addCustomEditor({
id: 'config.markerSymbol',
path: 'config.markerSymbol',
name: 'Marker Symbol',
editor: ResourceDimensionEditor,
defaultValue: defaultOptions.markerSymbol,
settings: {
options: markerMakers.selectOptions().options,
resourceType: 'icon',
showSourceRadio: false,
folderName: ResourceFolderName.Marker,
},
})
.addCustomEditor({
id: 'config.color',
path: 'config.color',
name: 'Marker Color',
editor: ColorDimensionEditor,
settings: {},
defaultValue: {
// Configured values
fixed: 'grey',
},
defaultValue: 'circle',
})
.addSliderInput({
path: 'config.fillOpacity',
@ -194,7 +224,6 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
max: 1,
step: 0.1,
},
showIf: (cfg) => markerMakers.getIfExists((cfg as any).config?.shape)?.hasFill,
})
.addBooleanSwitch({
path: 'config.showLegend',

View File

@ -1,6 +1,5 @@
import { PanelModel, FieldConfigSource } from '@grafana/data';
import { mapPanelChangedHandler } from './migrations';
import { mapMigrationHandler, mapPanelChangedHandler } from './migrations';
describe('Worldmap Migrations', () => {
let prevFieldConfig: FieldConfigSource;
@ -106,3 +105,169 @@ const simpleWorldmapConfig = {
valueName: 'total',
datasource: null,
};
describe('geomap migrations', () => {
it('updates marker', () => {
const panel = {
id: 2,
gridPos: {
h: 9,
w: 12,
x: 0,
y: 0,
},
type: 'geomap',
title: 'Panel Title',
fieldConfig: {
defaults: {
thresholds: {
mode: 'absolute',
steps: [
{
color: 'green',
value: null,
},
{
color: 'red',
value: 80,
},
],
},
mappings: [],
color: {
mode: 'thresholds',
},
},
overrides: [],
},
options: {
view: {
id: 'zero',
lat: 0,
lon: 0,
zoom: 1,
},
basemap: {
type: 'default',
config: {},
},
layers: [
{
config: {
color: {
fixed: 'dark-green',
},
fillOpacity: 0.4,
markerSymbol: {
fixed: '',
mode: 'fixed',
},
shape: 'circle',
showLegend: true,
size: {
fixed: 5,
max: 15,
min: 2,
},
},
location: {
mode: 'auto',
},
type: 'markers',
},
],
controls: {
showZoom: true,
mouseWheelZoom: true,
showAttribution: true,
showScale: false,
showDebug: false,
},
},
pluginVersion: '8.3.0-pre',
datasource: null,
} as PanelModel;
panel.options = mapMigrationHandler(panel);
expect(panel).toMatchInlineSnapshot(`
Object {
"datasource": null,
"fieldConfig": Object {
"defaults": Object {
"color": Object {
"mode": "thresholds",
},
"mappings": Array [],
"thresholds": Object {
"mode": "absolute",
"steps": Array [
Object {
"color": "green",
"value": null,
},
Object {
"color": "red",
"value": 80,
},
],
},
},
"overrides": Array [],
},
"gridPos": Object {
"h": 9,
"w": 12,
"x": 0,
"y": 0,
},
"id": 2,
"options": Object {
"basemap": Object {
"config": Object {},
"type": "default",
},
"controls": Object {
"mouseWheelZoom": true,
"showAttribution": true,
"showDebug": false,
"showScale": false,
"showZoom": true,
},
"layers": Array [
Object {
"config": Object {
"color": Object {
"fixed": "dark-green",
},
"fillOpacity": 0.4,
"markerSymbol": Object {
"fixed": "img/icons/marker/circle.svg",
"mode": "fixed",
},
"showLegend": true,
"size": Object {
"fixed": 5,
"max": 15,
"min": 2,
},
},
"location": Object {
"mode": "auto",
},
"type": "markers",
},
],
"view": Object {
"id": "zero",
"lat": 0,
"lon": 0,
"zoom": 1,
},
},
"pluginVersion": "8.3.0-pre",
"title": "Panel Title",
"type": "geomap",
}
`);
});
});

View File

@ -1,5 +1,6 @@
import { FieldConfigSource, PanelTypeChangedHandler, Threshold, ThresholdsMode } from '@grafana/data';
import { FieldConfigSource, PanelModel, PanelTypeChangedHandler, Threshold, ThresholdsMode } from '@grafana/data';
import { GeomapPanelOptions } from './types';
import { markerMakers } from './utils/regularShapes';
import { MapCenterID } from './view';
/**
@ -97,3 +98,27 @@ function asNumber(v: any): number | undefined {
const num = +v;
return isNaN(num) ? undefined : num;
}
export const mapMigrationHandler = (panel: PanelModel): Partial<GeomapPanelOptions> => {
const pluginVersion = panel?.pluginVersion;
if (pluginVersion?.startsWith('8.1') || pluginVersion?.startsWith('8.2') || pluginVersion?.startsWith('8.3')) {
if (panel.options?.layers?.length > 0) {
const layer = panel.options.layers[0];
if (layer?.type === 'markers') {
const shape = layer?.config?.shape;
if (shape) {
const marker = markerMakers.getIfExists(shape);
if (marker?.aliasIds && marker.aliasIds?.length > 0) {
layer.config.markerSymbol = {
fixed: marker.aliasIds[0],
mode: 'fixed',
};
delete layer.config.shape;
}
return { ...panel.options, layers: Object.assign([], ...panel.options.layers, { 0: layer }) };
}
}
}
}
return panel.options;
};

View File

@ -3,13 +3,14 @@ import { PanelPlugin } from '@grafana/data';
import { GeomapPanel } from './GeomapPanel';
import { MapViewEditor } from './editor/MapViewEditor';
import { defaultView, GeomapPanelOptions } from './types';
import { mapPanelChangedHandler } from './migrations';
import { mapPanelChangedHandler, mapMigrationHandler } from './migrations';
import { getLayerEditor } from './editor/layerEditor';
import { config } from '@grafana/runtime';
export const plugin = new PanelPlugin<GeomapPanelOptions>(GeomapPanel)
.setNoPadding()
.setPanelChangeHandler(mapPanelChangedHandler)
.setMigrationHandler(mapMigrationHandler)
.useFieldConfig()
.setPanelOptions((builder, context) => {
let category = ['Map view'];

View File

@ -1,15 +1,38 @@
import { Fill, RegularShape, Stroke, Style, Circle } from 'ol/style';
import { Registry, RegistryItem } from '@grafana/data';
interface MarkerMaker extends RegistryItem {
make: (color: string, fillColor: string, radius: number) => Style;
export type StyleMaker = (color: string, fillColor: string, radius: number, markerPath?: string) => Style;
export interface MarkerMaker extends RegistryItem {
// path to icon that will be shown (but then replaced)
aliasIds: string[];
make: StyleMaker;
hasFill: boolean;
}
export enum RegularShapeId {
Circle = 'circle',
Square = 'square',
Triangle = 'triangle',
Star = 'star',
Cross = 'cross',
X = 'x',
}
export enum MarkerShapePath {
Circle = 'img/icons/marker/circle.svg',
Square = 'img/icons/marker/square.svg',
Triangle = 'img/icons/marker/triangle.svg',
Star = 'img/icons/marker/star.svg',
Cross = 'img/icons/marker/cross.svg',
X = 'img/icons/marker/x-mark.svg',
}
export const circleMarker: MarkerMaker = {
id: 'circle',
id: RegularShapeId.Circle,
name: 'Circle',
hasFill: true,
aliasIds: [MarkerShapePath.Circle],
make: (color: string, fillColor: string, radius: number) => {
return new Style({
image: new Circle({
@ -21,12 +44,13 @@ export const circleMarker: MarkerMaker = {
},
};
export const markerMakers = new Registry<MarkerMaker>(() => [
const makers: MarkerMaker[] = [
circleMarker,
{
id: 'square',
id: RegularShapeId.Square,
name: 'Square',
hasFill: true,
aliasIds: [MarkerShapePath.Square],
make: (color: string, fillColor: string, radius: number) => {
return new Style({
image: new RegularShape({
@ -40,9 +64,10 @@ export const markerMakers = new Registry<MarkerMaker>(() => [
},
},
{
id: 'triangle',
id: RegularShapeId.Triangle,
name: 'Triangle',
hasFill: true,
aliasIds: [MarkerShapePath.Triangle],
make: (color: string, fillColor: string, radius: number) => {
return new Style({
image: new RegularShape({
@ -57,9 +82,10 @@ export const markerMakers = new Registry<MarkerMaker>(() => [
},
},
{
id: 'star',
id: RegularShapeId.Star,
name: 'Star',
hasFill: true,
aliasIds: [MarkerShapePath.Star],
make: (color: string, fillColor: string, radius: number) => {
return new Style({
image: new RegularShape({
@ -74,9 +100,10 @@ export const markerMakers = new Registry<MarkerMaker>(() => [
},
},
{
id: 'cross',
id: RegularShapeId.Cross,
name: 'Cross',
hasFill: false,
aliasIds: [MarkerShapePath.Cross],
make: (color: string, fillColor: string, radius: number) => {
return new Style({
image: new RegularShape({
@ -91,9 +118,10 @@ export const markerMakers = new Registry<MarkerMaker>(() => [
},
},
{
id: 'x',
id: RegularShapeId.X,
name: 'X',
hasFill: false,
aliasIds: [MarkerShapePath.X],
make: (color: string, fillColor: string, radius: number) => {
return new Style({
image: new RegularShape({
@ -107,4 +135,15 @@ export const markerMakers = new Registry<MarkerMaker>(() => [
});
},
},
]);
];
export const markerMakers = new Registry<MarkerMaker>(() => makers);
export const getMarkerFromPath = (svgPath: string): MarkerMaker | undefined => {
for (const [key, val] of Object.entries(MarkerShapePath)) {
if (val === svgPath) {
return markerMakers.getIfExists(key);
}
}
return undefined;
};

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/></svg>

After

Width:  |  Height:  |  Size: 98 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19,11H13V5a1,1,0,0,0-2,0v6H5a1,1,0,0,0,0,2h6v6a1,1,0,0,0,2,0V13h6a1,1,0,0,0,0-2Z"/></svg>

After

Width:  |  Height:  |  Size: 159 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#fff" d="M21.75,12a1,1,0,0,0-.55-.89L15.08,8.05v-4a3.08,3.08,0,1,0-6.16,0v4L2.8,11.11a1,1,0,0,0-.55.89v3.33a1,1,0,0,0,.43.83,1,1,0,0,0,.92.11l5.32-2V18l-1.82.6a1,1,0,0,0-.68.95V22a1,1,0,0,0,.3.71,1,1,0,0,0,.7.29h9.17a1,1,0,0,0,1-1V19.5a1,1,0,0,0-.68-.95L15.08,18V14.28l5.32,2a1,1,0,0,0,.92-.11,1,1,0,0,0,.43-.83Zm-7.31-.1a1,1,0,0,0-.93.11,1,1,0,0,0-.43.82v5.84a1,1,0,0,0,.69.95l1.81.6V21H8.41v-.78l1.81-.6a1,1,0,0,0,.69-.95V12.83a1,1,0,0,0-.43-.82,1,1,0,0,0-.93-.11l-5.31,2V12.62l6.11-3.06a1,1,0,0,0,.56-.89V4.08a1.08,1.08,0,1,1,2.16,0V8.67a1,1,0,0,0,.56.89l6.11,3.06v1.27Z"/></svg>

After

Width:  |  Height:  |  Size: 654 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect width="85%" height="85%" x="2" y="2" rx="5"/></svg>

After

Width:  |  Height:  |  Size: 117 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22,9.67A1,1,0,0,0,21.14,9l-5.69-.83L12.9,3a1,1,0,0,0-1.8,0L8.55,8.16,2.86,9a1,1,0,0,0-.81.68,1,1,0,0,0,.25,1l4.13,4-1,5.68a1,1,0,0,0,.4,1,1,1,0,0,0,1.05.07L12,18.76l5.1,2.68a.93.93,0,0,0,.46.12,1,1,0,0,0,.59-.19,1,1,0,0,0,.4-1l-1-5.68,4.13-4A1,1,0,0,0,22,9.67Zm-6.15,4a1,1,0,0,0-.29.89l.72,4.19-3.76-2a1,1,0,0,0-.94,0l-3.76,2,.72-4.19a1,1,0,0,0-.29-.89l-3-3,4.21-.61a1,1,0,0,0,.76-.55L12,5.7l1.88,3.82a1,1,0,0,0,.76.55l4.21.61Z"/></svg>

After

Width:  |  Height:  |  Size: 506 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.87,19.29l-9-15.58a1,1,0,0,0-1.74,0l-9,15.58a1,1,0,0,0,0,1,1,1,0,0,0,.87.5H21a1,1,0,0,0,.87-.5A1,1,0,0,0,21.87,19.29Zm-17.14-.5L12,6.21l7.27,12.58Z"/></svg>

After

Width:  |  Height:  |  Size: 228 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13.41,12l6.3-6.29a1,1,0,1,0-1.42-1.42L12,10.59,5.71,4.29A1,1,0,0,0,4.29,5.71L10.59,12l-6.3,6.29a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L12,13.41l6.29,6.3a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42Z"/></svg>

After

Width:  |  Height:  |  Size: 261 B