Compare commits

..

15 Commits

Author SHA1 Message Date
Grot (@grafanabot)
147704deb9 "Release: Updated versions in package to 8.1.0-beta.2" (#37138) 2021-07-23 10:29:33 +02:00
Grot (@grafanabot)
078d716be9 IconButton: Put tooltip text as aria-label (#36760) (#37137)
* Make tooltip prop aria-label

* Add ariaLabel prop

(cherry picked from commit 8af83b8b78)

Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com>
2021-07-23 10:12:16 +02:00
Grot (@grafanabot)
04cb471599 Expand the value string in annotations and labels of alerts (#37051) (#37105)
This commit makes it possible to use the value string in
annotations and labels for alerts with "{{ $value }}"

(cherry picked from commit 2f4c893cf3)

Co-authored-by: George Robinson <85952834+gerobinson@users.noreply.github.com>
2021-07-23 09:28:49 +02:00
Grot (@grafanabot)
6564f22772 Gazetteer: Update Countries Json (#37129) (#37132)
(cherry picked from commit 2b51e94537)

Co-authored-by: Bryan Uribe <buribe@hmc.edu>
2021-07-23 09:25:20 +02:00
Grot (@grafanabot)
13cd3ea28b Explore: Fix encoding of internal URLs (#36919) (#37100)
* Encode internal explore url

* Fix tests

* Fix comma

(cherry picked from commit 93b4cc7035)

Co-authored-by: Andrej Ocenas <mr.ocenas@gmail.com>
2021-07-23 09:19:25 +02:00
Grot (@grafanabot)
d5e0665081 Storybook: Add a11y addon (#36790) (#37110)
* Storybook: Add a11y addon

* Update lockfile

* Bump Storybook addon versions

* Put Icon at top

* addon-knobs 6.3.0

(cherry picked from commit 437424d5d6)

Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com>
2021-07-23 09:17:59 +02:00
Grot (@grafanabot)
909141592d StatPanel: Disable selection on Sparkline (#37125) (#37128)
(cherry picked from commit a1bbe797df)

Co-authored-by: nikki-kiga <42276368+nikki-kiga@users.noreply.github.com>
2021-07-23 09:14:51 +02:00
Grot (@grafanabot)
fda235a862 Infra: Azure authentication in HttpClientProvider (#36932) (#37124)
* Azure middleware in HttpClientProxy

* Azure authentication under feature flag

* Minor fixes

* Add prefixes to not clash with JsonData

* Return error if JsonData cannot be parsed

* Return original string if URL invalid

* Tests for datasource_cache

(cherry picked from commit c1963024ec)

Co-authored-by: Sergey Kostrukov <sergey@kostrukov.com>
2021-07-22 23:12:31 +02:00
Grot (@grafanabot)
154231a58d Doc: first draft of 8.1 what's new (#37021) (#37115)
* Create whats-new-in-v8-1.md

* Updated index page.

* Fixed two relrefs.

* Added section for annotation panel

(cherry picked from commit 013218e075)

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
2021-07-22 15:28:48 -04:00
Grot (@grafanabot)
197e4344da Prometheus: Azure authentication in configuration UI (#35860) (#37116)
* Azure authentication settings

* Persisting credentials

* Azure settings

* Prometheus-specific settings component

* Azure Prometheus Resource ID configuration

* DataSourceHttpSettings with extensibility for Azure

* Feature toggle for Azure auth

* Fix snapshot

* Update format of persisted credentials

* AzureSettings renamed to AzureAuthSettings

(cherry picked from commit 4664cba935)

Co-authored-by: Sergey Kostrukov <sergey@kostrukov.com>
2021-07-22 21:22:31 +02:00
Grot (@grafanabot)
64b008e28b ReleaseNotes: Updated changelog and release notes for 8.1.0-beta1 (#37111) (#37112) 2021-07-22 18:38:49 +02:00
Grot (@grafanabot)
bc9ac1199b fix sample.ini (#37106) (#37107)
(cherry picked from commit 6b2d33dc14)

Co-authored-by: Alexander Emelin <frvzmb@gmail.com>
2021-07-22 17:25:47 +02:00
Grot (@grafanabot)
2b15e1a962 Folder API: optionally force deleting Grafana 8 alerts when deleting a folder (or error) (#36427) (#37094)
* Folder API: Add an optional query parameter for allowing deleting a  folder containing rules

* Update frontend

- Set forceDeleteRules=true when frontend deletes a folder
- Improve modal text

* Update docs

* Apply suggestions from code review

Co-authored-by: gotjosh <josue@grafana.com>
Co-authored-by: Nathan Rodman <nathanrodman@gmail.com>
Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
(cherry picked from commit b96dd1877c)

Co-authored-by: Sofia Papagiannaki <papagian@users.noreply.github.com>
2021-07-22 17:56:33 +03:00
Grot (@grafanabot)
4308a77e27 Auth: Pass user role to Grafana using auth proxy (#36729) (#37103)
* Pass role to Grafana using auth proxy

By default, the role will be applied to the default org of the user.
If the request uses the standard header "X-Grafana-Org-Id", the role will be applied to the specified org

Tested in both unit test and manually E2E

* Address comment: only allow the user role to be applied to the default org

Co-authored-by: Leonard Gram <leo@xlson.com>
(cherry picked from commit ad1f792b8b)

Co-authored-by: yuwaMSFT2 <yuwa@microsoft.com>
2021-07-22 16:25:51 +02:00
Grot (@grafanabot)
f18749927c "Release: Updated versions in package to 8.1.0-beta.1" (#37091) 2021-07-22 11:21:21 +02:00
4218 changed files with 108331 additions and 271723 deletions

12
.bingo/.gitignore vendored
View File

@@ -1,12 +0,0 @@
# Ignore everything
*
# But not these files:
!.gitignore
!*.mod
!README.md
!Variables.mk
!variables.env
*tmp.mod

View File

@@ -1,14 +0,0 @@
# Project Development Dependencies.
This is directory which stores Go modules with pinned buildable package that is used within this repository, managed by https://github.com/bwplotka/bingo.
- Run `bingo get` to install all tools having each own module file in this directory.
- Run `bingo get <tool>` to install <tool> that have own module file in this directory.
- For Makefile: Make sure to put `include .bingo/Variables.mk` in your Makefile, then use $(<upper case tool name>) variable where <tool> is the .bingo/<tool>.mod.
- For shell: Run `source .bingo/variables.env` to source all environment variable for each tool.
- For go: Import `.bingo/variables.go` to for variable names.
- See https://github.com/bwplotka/bingo or -h on how to add, remove or change binaries dependencies.
## Requirements
- Go 1.14+

View File

@@ -1,31 +0,0 @@
# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.5.1. DO NOT EDIT.
# All tools are designed to be build inside $GOBIN.
BINGO_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
GOPATH ?= $(shell go env GOPATH)
GOBIN ?= $(firstword $(subst :, ,${GOPATH}))/bin
GO ?= $(shell which go)
# Below generated variables ensure that every time a tool under each variable is invoked, the correct version
# will be used; reinstalling only if needed.
# For example for drone variable:
#
# In your main Makefile (for non array binaries):
#
#include .bingo/Variables.mk # Assuming -dir was set to .bingo .
#
#command: $(DRONE)
# @echo "Running drone"
# @$(DRONE) <flags/args..>
#
DRONE := $(GOBIN)/drone-v1.4.0
$(DRONE): $(BINGO_DIR)/drone.mod
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
@echo "(re)installing $(GOBIN)/drone-v1.4.0"
@cd $(BINGO_DIR) && $(GO) build -mod=mod -modfile=drone.mod -o=$(GOBIN)/drone-v1.4.0 "github.com/drone/drone-cli/drone"
WIRE := $(GOBIN)/wire-v0.5.0
$(WIRE): $(BINGO_DIR)/wire.mod
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
@echo "(re)installing $(GOBIN)/wire-v0.5.0"
@cd $(BINGO_DIR) && $(GO) build -mod=mod -modfile=wire.mod -o=$(GOBIN)/wire-v0.5.0 "github.com/google/wire/cmd/wire"

View File

@@ -1,7 +0,0 @@
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
go 1.17
replace github.com/docker/docker => github.com/docker/engine v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
require github.com/drone/drone-cli v1.4.0 // drone

View File

@@ -1 +0,0 @@
module _ // Fake go.mod auto-created by 'bingo' for go -moddir compatibility with non-Go projects. Commit this file, together with other .mod files.

View File

@@ -1,14 +0,0 @@
# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.5.1. DO NOT EDIT.
# All tools are designed to be build inside $GOBIN.
# Those variables will work only until 'bingo get' was invoked, or if tools were installed via Makefile's Variables.mk.
GOBIN=${GOBIN:=$(go env GOBIN)}
if [ -z "$GOBIN" ]; then
GOBIN="$(go env GOPATH)/bin"
fi
DRONE="${GOBIN}/drone-v1.4.0"
WIRE="${GOBIN}/wire-v0.5.0"

View File

@@ -1,5 +0,0 @@
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
go 1.16
require github.com/google/wire v0.5.0 // cmd/wire

View File

@@ -1,6 +1,5 @@
[run]
init_cmds = [
["make", "gen-go"],
["go", "run", "build.go", "-dev", "build-cli"],
["go", "run", "build.go", "-dev", "build-server"],
["./bin/grafana-server", "-packaging=dev", "cfg:app_mode=development"]
@@ -13,10 +12,8 @@ watch_dirs = [
"$WORKDIR/conf",
]
watch_exts = [".go", ".ini", ".toml", ".template.html"]
ignore_files = ["wire_gen.go"]
build_delay = 1500
cmds = [
["make", "gen-go"],
["go", "run", "build.go", "-dev", "build-server"],
["./bin/grafana-server", "-packaging=dev", "cfg:app_mode=development"]
]

View File

@@ -12,14 +12,7 @@ Dockerfile
docs
dump.rdb
node_modules
**/node_modules
/local
/tmp
*.yml
!.yarnrc.yml
*.md
.yarn/*
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/versions
!.yarn/cache

View File

@@ -4,12 +4,12 @@
# 3. Run `make drone`
# More information about this process here: https://github.com/grafana/deployment_tools/blob/master/docs/infrastructure/drone/signing.md
load('scripts/drone/pipelines/pr.star', 'pr_pipelines')
load('scripts/drone/pipelines/main.star', 'main_pipelines')
load('scripts/drone/pipelines/release.star', 'release_pipelines', 'test_release_pipelines')
load('scripts/drone/version.star', 'version_branch_pipelines')
load('scripts/drone/pipelines/cron.star', 'cronjobs')
load('scripts/drone/vault.star', 'secrets')
load('scripts/pr.star', 'pr_pipelines')
load('scripts/main.star', 'main_pipelines')
load('scripts/release.star', 'release_pipelines', 'test_release_pipelines')
load('scripts/version.star', 'version_branch_pipelines')
load('scripts/job.star', 'cronjobs')
load('scripts/vault.star', 'secrets')
def main(ctx):
edition = 'oss'

5503
.drone.yml

File diff suppressed because it is too large Load Diff

View File

@@ -6,5 +6,3 @@ devenv
data
dist
e2e/tmp
public/lib/monaco
deployment_tools_config.json

102
.github/CODEOWNERS vendored
View File

@@ -14,20 +14,13 @@
# Documentation owner: Jita Chatterjee
/docs/ @grafana/docs-squad @pkolyvas
/contribute/ @marcusolsson @grafana/docs-squad @pkolyvas
/docs/sources/developers/plugins/ @marcusolsson @grafana/docs-squad @grafana/plugins-platform-frontend @grafana/plugins-platform-backend
/docs/sources/developers/plugins/backend @marcusolsson @grafana/docs-squad @grafana/plugins-platform-backend
/docs/sources/developers/plugins/ @marcusolsson @grafana/docs-squad
/docs/sources/enterprise/ @osg-grafana @grafana/docs-squad
# Backend code
*.go @grafana/backend-platform
go.mod @grafana/backend-platform
go.sum @grafana/backend-platform
/.bingo @grafana/backend-platform
# Continuous Integration
.drone.yml @grafana/grafana-release-eng
.drone.star @grafana/grafana-release-eng
/scripts/drone/ @grafana/grafana-release-eng
# Cloud Datasources backend code
/pkg/tsdb/cloudwatch @grafana/cloud-datasources @grafana/observability-squad
@@ -43,87 +36,40 @@ go.sum @grafana/backend-platform
/pkg/tsdb/zipkin @grafana/observability-squad
/pkg/tsdb/tempo @grafana/observability-squad
# Database migrations
/pkg/services/sqlstore/migrations @grafana/backend-platform @grafana/hosted-grafana-team
*_mig.go @grafana/backend-platform @grafana/hosted-grafana-team
# Grafana live
/pkg/services/live/ @grafana/grafana-edge-squad
# Unified Alerting
/pkg/services/ngalert @grafana/alerting-squad
/pkg/services/sqlstore/migrations/ualert @grafana/alerting-squad
# Library Services
/pkg/services/libraryelements @grafana/user-essentials
/pkg/services/librarypanels @grafana/user-essentials
# Plugins
/pkg/api/pluginproxy @grafana/plugins-platform-backend
/pkg/plugins @grafana/plugins-platform-backend
/pkg/services/datasourceproxy @grafana/plugins-platform-backend
/pkg/services/datasources @grafana/plugins-platform-backend
# Database migrations
/pkg/services/sqlstore/migrations @grafana/backend-platform @grafana/hosted-grafana-team
*_mig.go @grafana/backend-platform @grafana/hosted-grafana-team
# Backend code docs
/contribute/style-guides/backend.md @grafana/backend-platform
/contribute/architecture/backend @grafana/backend-platform
/contribute/engineering/backend @grafana/backend-platform
/e2e @grafana/user-essentials
/packages @grafana/user-essentials @grafana/plugins-platform-frontend @grafana/grafana-bi-squad
/packages/grafana-e2e-selectors @grafana/user-essentials
/packages/grafana-e2e @grafana/user-essentials
/packages/grafana-toolkit @grafana/plugins-platform-frontend
/packages/grafana-ui/.storybook @grafana/plugins-platform-frontend
/packages/grafana-ui/src/components/DateTimePickers @grafana/grafana-bi-squad
/packages/grafana-ui/src/components/GraphNG @grafana/grafana-bi-squad
/packages/grafana-ui/src/components/Table @grafana/grafana-bi-squad
/packages/grafana-ui/src/components/TimeSeries @grafana/grafana-bi-squad
/packages/grafana-ui/src/components/uPlot @grafana/grafana-bi-squad
/packages/grafana-ui/src/utils/storybook @grafana/plugins-platform-frontend
/packages/jaeger-ui-components/ @grafana/observability-squad
/plugins-bundled @grafana/plugins-platform-frontend
/public @grafana/user-essentials
/public/app/core/components/TimePicker @grafana/grafana-bi-squad
/public/app/core/components/Layers @grafana/grafana-edge-squad
/public/app/features/canvas/ @grafana/grafana-edge-squad
/public/app/features/dimensions/ @grafana/grafana-edge-squad
/public/app/features/live/ @grafana/grafana-edge-squad
/public/app/features/explore/ @grafana/observability-squad
/public/app/features/plugins @grafana/plugins-platform-frontend
/public/app/plugins/panel/alertlist @grafana/alerting-squad
/public/app/plugins/panel/barchart @grafana/grafana-bi-squad
/public/app/plugins/panel/heatmap @grafana/grafana-bi-squad
/public/app/plugins/panel/histogram @grafana/grafana-bi-squad
/public/app/plugins/panel/nodeGraph @grafana/observability-squad
/public/app/plugins/panel/piechart @grafana/grafana-bi-squad
/public/app/plugins/panel/state-timeline @grafana/grafana-bi-squad
/public/app/plugins/panel/status-history @grafana/grafana-bi-squad
/public/app/plugins/panel/table @grafana/grafana-bi-squad
/public/app/plugins/panel/timeseries @grafana/grafana-bi-squad
/public/app/plugins/panel/geomap @grafana/grafana-edge-squad
/public/app/plugins/panel/canvas @grafana/grafana-edge-squad
/public/app/plugins/panel/candlestick @grafana/grafana-edge-squad
/public/app/plugins/panel/icon @grafana/grafana-edge-squad
/scripts/build/release-packages.sh @grafana/plugins-platform-frontend
/scripts/circle-release-next-packages.sh @grafana/plugins-platform-frontend
/scripts/ci-frontend-metrics.sh @grafana/user-essentials @grafana/plugins-platform-frontend @grafana/grafana-bi-squad
/scripts/ci-reference-docs-build.sh @grafana/plugins-platform-frontend
/scripts/ci-reference-docs-lint.sh @grafana/plugins-platform-frontend
/scripts/grunt @grafana/frontend-ops
/scripts/webpack @grafana/frontend-ops
/scripts/generate-a11y-report.sh @grafana/user-essentials
package.json @grafana/frontend-ops
tsconfig.json @grafana/frontend-ops
lerna.json @grafana/frontend-ops
.babelrc @grafana/frontend-ops
.prettierrc.js @grafana/frontend-ops
.eslintrc @grafana/frontend-ops
.pa11yci.conf.js @grafana/user-essentials
.pa11yci-pr.conf.js @grafana/user-essentials
/e2e @grafana/grafana-frontend-platform
/packages @grafana/grafana-frontend-platform
/plugins-bundled @grafana/grafana-frontend-platform
/public @grafana/grafana-frontend-platform
/scripts/build/release-packages.sh @grafana/grafana-frontend-platform
/scripts/circle-release-next-packages.sh @grafana/grafana-frontend-platform
/scripts/ci-frontend-metrics.sh @grafana/grafana-frontend-platform
/scripts/grunt @grafana/grafana-frontend-platform
/scripts/webpack @grafana/grafana-frontend-platform
package.json @grafana/grafana-frontend-platform
tsconfig.json @grafana/grafana-frontend-platform
lerna.json @grafana/grafana-frontend-platform
.babelrc @grafana/grafana-frontend-platform
.prettierrc.js @grafana/grafana-frontend-platform
.eslintrc @grafana/grafana-frontend-platform
# @grafana/ui component documentation
*.mdx @marcusolsson @jessover9000 @grafana/plugins-platform-frontend
*.mdx @marcusolsson @jessover9000 @grafana/grafana-frontend-platform
/public/app/features/explore/ @grafana/observability-squad
/packages/jaeger-ui-components/ @grafana/observability-squad
# Core datasources
/public/app/plugins/datasource/cloudwatch @grafana/cloud-datasources @grafana/observability-squad
@@ -144,4 +90,4 @@ lerna.json @grafana/frontend-ops
/public/app/plugins/datasource/alertmanager @grafana/alerting-squad
# Cloud middleware
/grafana-mixin/ @grafana/hosted-grafana-team
/grafana-mixin/ @grafana/cloud-middleware

View File

@@ -5,7 +5,7 @@ labels: 'type: bug'
---
<!--
Please use this template to create your bug report. By providing as much info as possible you help us understand the issue, reproduce it and resolve it for you quicker. Therefore take a couple of extra minutes to make sure you have provided all info needed.
Please use this template to create your bug report. By providing as much info as possible you help us understand the issue, reproduce it and resolve it for you quicker. Therefor take a couple of extra minutes to make sure you have provided all info needed.
PROTIP: record your screen and attach it as a gif to showcase the issue.

16
.github/commands.json vendored
View File

@@ -49,21 +49,5 @@
"action": "close",
"addLabel": "not implemented",
"comment": "This feature request has been open for a long time with few received upvotes or comments, so we are closing it. We're trying to limit open GitHub issues in order to better track planned work and features. \r\n\r\nThis doesn't mean that we'll never ever implement it or that we will never accept a PR for it. A closed issue can still attract upvotes and act as a ticket to track feature demand\/interest. \r\n\r\nThank You to you for taking the time to create this issue!"
},
{
"type": "label",
"name": "oss-user-essentials",
"action": "addToProject",
"addToProject": {
"url": "https://github.com/orgs/grafana/projects/78"
}
},
{
"type": "label",
"name": "area/plugins-catalog",
"action": "addToProject",
"addToProject": {
"url": "https://github.com/orgs/grafana/projects/76"
}
}
]

View File

@@ -1,9 +0,0 @@
[
{
"type": "check-milestone",
"title": "Milestone Check",
"targetUrl": "https://github.com/grafana/grafana/blob/main/contribute/merge-pull-request.md#assign-a-milestone",
"success": "Milestone set",
"failure": "Milestone not set"
}
]

View File

@@ -66,6 +66,9 @@
"packaging/**/*",
"scripts/build/**/*",
"scripts/*.sh",
"scripts/*.star",
".drone.star",
".drone.yml",
"Makefile",
"Dockerfile",
"Dockerfile.ubuntu"
@@ -73,16 +76,6 @@
"action": "updateLabel",
"addLabel": "type/build-packaging"
},
{
"type": "changedfiles",
"matches": [
"scripts/*.star",
".drone.star",
".drone.yml"
],
"action": "updateLabel",
"addLabel": "type/ci"
},
{
"type": "changedfiles",
"matches": [ "public/app/plugins/datasource/grafana-azure-monitor-datasource/**/*", "pkg/tsdb/azuremonitor/**/*"],
@@ -183,7 +176,6 @@
"type": "author",
"name": "pr/external",
"notMemberOf": { "org": "grafana" },
"ignoreList": ["renovate[bot]"],
"action": "updateLabel",
"addLabel": "pr/external"
}

View File

@@ -1,47 +0,0 @@
{
"extends": [
"config:base"
],
"enabledManagers": ["npm"],
"ignoreDeps": [
"@types/systemjs",
"@types/d3-force", // we should bump this once we move to esm modules
"@types/d3-interpolate", // we should bump this once we move to esm modules
"@types/d3-scale-chromatic", // we should bump this once we move to esm modules
"@types/react-icons", // jaeger-ui-components is being refactored to use @grafana/ui icons instead
"d3",
"d3-force", // we should bump this once we move to esm modules
"d3-interpolate", // we should bump this once we move to esm modules
"d3-scale-chromatic", // we should bump this once we move to esm modules
"eslint", // wait until `eslint-plugin-react-hooks>4.2.0` is released
"execa", // we should bump this once we move to esm modules
"history", // we should bump this together with react-router-dom
"react-icons", // jaeger-ui-components is being refactored to use @grafana/ui icons instead
"react-router-dom", // we should bump this together with history
"slate",
"slate-plain-serializer",
"systemjs",
"ts-loader", // we should remove ts-loader and use babel-loader instead
"ora" // we should bump this once we move to esm modules
],
"ignorePaths": ["packages/grafana-toolkit/package.json", "emails/**", "plugins-bundled/**", "**/mocks/**"],
"labels": ["area/frontend", "dependencies"],
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"extends": ["schedule:monthly"]
}
],
"patch": {
"enabled": false
},
"pin": {
"enabled": false
},
"prConcurrentLimit": 10,
"reviewers": ["team:grafana/frontend-ops"],
"separateMajorMinor": false,
"vulnerabilityAlerts": {
"addLabels": ["area/security"]
}
}

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
# This is a basic workflow to help you get started with Actions
- uses: actions-ecosystem/action-regex-match@v2.0.2
- uses: actions-ecosystem/action-regex-match@v2
id: regex-match
with:
text: ${{ github.event.inputs.version }}
@@ -53,7 +53,7 @@ jobs:
repository: "grafana/grafana-github-actions"
path: ./actions
ref: main
- uses: actions/setup-node@v2.4.1
- uses: actions/setup-node@v2.1.5
with:
node-version: '14'
- name: Install Actions

View File

@@ -1,28 +0,0 @@
name: PR Checks
on:
pull_request:
types:
- opened
- synchronize
issues:
types:
- milestoned
- demilestoned
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
uses: actions/checkout@v2
with:
repository: "grafana/grafana-github-actions"
path: ./actions
ref: main
- name: Install Actions
run: npm install --production --prefix ./actions
- name: Run PR Checks
uses: ./actions/pr-checks
with:
token: ${{secrets.GITHUB_TOKEN}}
configPath: pr-checks

View File

@@ -1,17 +0,0 @@
name: Run when PRs are closed
on:
pull_request:
types:
- closed
jobs:
close_job:
# this job will only run if the PR has been closed without being merged
if: github.event.pull_request.merged == false
runs-on: ubuntu-latest
steps:
- run: |
echo PR #${{ github.event.number }} has been closed without being merged, removing milestone.
gh pr edit ${{ github.event.number }} --milestone "" --repo $GITHUB_REPOSITORY
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -16,21 +16,16 @@ jobs:
steps:
- uses: actions/checkout@v1
- run: git clone --single-branch --no-tags --depth 1 -b master https://grafanabot:${{ secrets.GH_BOT_ACCESS_TOKEN }}@github.com/grafana/website-sync ./.github/actions/website-sync
- uses: actions/cache@v2.1.5
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: generate-packages-docs
uses: actions/setup-node@v2.4.1
uses: actions/setup-node@v2.1.5
id: generate-docs
with:
node-version: '14'
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- uses: actions/cache@v2.1.6
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
yarn-
- run: yarn install --immutable
- run: yarn install --pure-lockfile --no-progress
- run: ./scripts/ci-reference-docs-build.sh
- name: publish-to-git
uses: ./.github/actions/website-sync

View File

@@ -1,23 +0,0 @@
name: Remove milestone
on:
workflow_dispatch:
inputs:
version:
required: true
description: Needs to match, exactly, the name of a milestone
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
uses: actions/checkout@v2
with:
repository: "grafana/grafana-github-actions"
path: ./actions
ref: main
- name: Install Actions
run: npm install --production --prefix ./actions
- name: Remove milestone from open issues
uses: ./actions/remove-milestone
with:
token: ${{secrets.GH_BOT_ACCESS_TOKEN}}

28
.gitignore vendored
View File

@@ -7,28 +7,17 @@ awsconfig
/.awcache
/dist
/public/build
public/dist/tsconfig.tsbuildinfo
/public/views/index.html
/public/views/error.html
/emails/dist
/reports
/e2e/tmp
.yarnrc
.yarn/
vendor/
/docs/menu.yaml
/requests
# Yarn
.yarn/*
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
# we temporarily commit this file because yarn downloading it
# somehow produces different checksum values
!.yarn/cache/pa11y-ci-https-1e9675e9e1-668c9119bd.zip
.pnp.*
# Enterprise emails
/emails/templates/enterprise_*
/public/emails/enterprise_*
@@ -64,7 +53,6 @@ public/css/*.min.css
!.vscode/launch.json
.vs/
.eslintcache
.stylelintcache
/data/*
/bin/*
@@ -87,8 +75,6 @@ profile.cov
/pkg/cmd/grafana-server/grafana-server
/pkg/cmd/grafana-server/debug
/pkg/extensions/*
/pkg/server/wireexts_enterprise.go
/pkg/cmd/grafana-cli/runner/wireexts_enterprise.go
!/pkg/extensions/main.go
/public/app/extensions
debug.test
@@ -96,7 +82,6 @@ debug.test
/packaging/**/*.rpm
/packaging/**/*.deb
/packaging/**/*.tar.gz
/packaging/**/*.tar.gz.sha256
# Ignore OSX indexing
.DS_Store
@@ -137,17 +122,8 @@ compilation-stats.json
!/e2e/**/screenshots/expected/*
/e2e/**/videos/*
# a11y tests
/pa11y-ci-results.json
/pa11y-ci-report
# report dumping the whole system env
/report.*.json
# auto generated frontend docs
/docs/sources/packages_api
# auto generated Go files
*_gen.go
deployment_tools_config.json

View File

@@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn run precommit

View File

@@ -1,123 +0,0 @@
var config = {
defaults: {
concurrency: 1,
runners: ['axe'],
useIncognitoBrowserContext: false,
chromeLaunchConfig: {
args: ['--no-sandbox'],
},
// see https://github.com/grafana/grafana/pull/41693#issuecomment-979921463 for context
// on why we're ignoring singleValue/react-select-*-placeholder elements
hideElements: '#updateVersion, [class*="-singleValue"], [id^="react-select-"][id$="-placeholder"]',
},
urls: [
{
url: '${HOST}/login',
wait: 500,
rootElement: '.main-view',
threshold: 12,
},
{
url: '${HOST}/login',
wait: 500,
actions: [
"wait for element input[name='user'] to be added",
"set field input[name='user'] to admin",
"set field input[name='password'] to admin",
"click element button[aria-label='Login button']",
"wait for element [aria-label='Skip change password button'] to be visible",
],
threshold: 13,
rootElement: '.main-view',
},
{
url: '${HOST}/?orgId=1',
wait: 500,
threshold: 0,
},
{
url: '${HOST}/d/O6f11TZWk/panel-tests-bar-gauge',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/d/O6f11TZWk/panel-tests-bar-gauge?orgId=1&editview=settings',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/?orgId=1&search=open',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/alerting/list',
wait: 500,
rootElement: '.main-view',
// the unified alerting promotion alert's content contrast is too low
// see https://github.com/grafana/grafana/pull/41829
threshold: 5,
},
{
url: '${HOST}/datasources',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/org/users',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/org/teams',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/plugins',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/org',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/org/apikeys',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
{
url: '${HOST}/dashboards',
wait: 500,
rootElement: '.main-view',
threshold: 0,
},
],
};
function myPa11yCiConfiguration(urls, defaults) {
const HOST_SERVER = process.env.HOST || 'localhost';
const PORT_SERVER = process.env.PORT || '3001';
for (var idx = 0; idx < urls.length; idx++) {
urls[idx] = { ...urls[idx], url: urls[idx].url.replace('${HOST}', `${HOST_SERVER}:${PORT_SERVER}`) };
}
return {
defaults: defaults,
urls: urls,
};
}
module.exports = myPa11yCiConfiguration(config.urls, config.defaults);

View File

@@ -1,106 +0,0 @@
var config = {
defaults: {
concurrency: 1,
runners: ['axe'],
useIncognitoBrowserContext: false,
chromeLaunchConfig: {
args: ['--no-sandbox'],
},
// see https://github.com/grafana/grafana/pull/41693#issuecomment-979921463 for context
// on why we're ignoring singleValue/react-select-*-placeholder elements
hideElements: '#updateVersion, [class*="-singleValue"], [id^="react-select-"][id$="-placeholder"]',
},
urls: [
{
url: '${HOST}/login',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/login', //skip password and login
actions: [
"wait for element input[name='user'] to be added",
"set field input[name='user'] to admin",
"set field input[name='password'] to admin",
"click element button[aria-label='Login button']",
"wait for element [aria-label='Skip change password button'] to be visible",
],
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/?orgId=1',
wait: 500,
},
{
url: '${HOST}/d/O6f11TZWk/panel-tests-bar-gauge',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/d/O6f11TZWk/panel-tests-bar-gauge?orgId=1&editview=settings',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/?orgId=1&search=open',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/alerting/list',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/datasources',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/org/users',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/org/teams',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/plugins',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/org',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/org/apikeys',
wait: 500,
rootElement: '.main-view',
},
{
url: '${HOST}/dashboards',
wait: 500,
rootElement: '.main-view',
},
],
};
function myPa11yCiConfiguration(urls, defaults) {
const HOST_SERVER = process.env.HOST || 'localhost';
const PORT_SERVER = process.env.PORT || '3001';
for (var idx = 0; idx < urls.length; idx++) {
urls[idx] = { ...urls[idx], url: urls[idx].url.replace('${HOST}', `${HOST_SERVER}:${PORT_SERVER}`) };
}
return {
defaults: defaults,
urls: urls,
};
}
module.exports = myPa11yCiConfiguration(config.urls, config.defaults);

View File

@@ -5,9 +5,8 @@ pkg/
node_modules
public/vendor/
vendor/
/data/
data/
e2e/tmp
public/build/
public/sass/*.generated.scss
devenv/
public/lib/monaco

View File

@@ -1,6 +0,0 @@
{
"eslint.packageManager": "yarn",
"eslint.nodePath": ".yarn/sdks",
"workspace.workspaceFolderCheckCwd": false,
"tsserver.tsdk": ".yarn/sdks/typescript/lib"
}

9
.vscode/launch.json vendored
View File

@@ -9,15 +9,6 @@
"program": "${workspaceFolder}/pkg/cmd/grafana-server/",
"env": {},
"args": ["--homepath", "${workspaceFolder}", "--packaging", "dev"]
},
{
"name": "Debug Jest test",
"type": "node",
"request": "launch",
"runtimeArgs": ["--inspect-brk", "${workspaceRoot}/node_modules/.bin/jest", "--runInBand", "${file}"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"port": 9229
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require eslint/bin/eslint.js
require(absPnpApiPath).setup();
}
}
// Defer to the real eslint/bin/eslint.js your application uses
module.exports = absRequire(`eslint/bin/eslint.js`);

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require eslint
require(absPnpApiPath).setup();
}
}
// Defer to the real eslint your application uses
module.exports = absRequire(`eslint`);

View File

@@ -1,6 +0,0 @@
{
"name": "eslint",
"version": "7.28.0-sdk",
"main": "./lib/api.js",
"type": "commonjs"
}

View File

@@ -1,6 +0,0 @@
# This file is automatically generated by @yarnpkg/sdks.
# Manual changes might be lost!
integrations:
- vscode
- vim

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require prettier/index.js
require(absPnpApiPath).setup();
}
}
// Defer to the real prettier/index.js your application uses
module.exports = absRequire(`prettier/index.js`);

View File

@@ -1,6 +0,0 @@
{
"name": "prettier",
"version": "2.2.1-sdk",
"main": "./index.js",
"type": "commonjs"
}

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require stylelint/bin/stylelint.js
require(absPnpApiPath).setup();
}
}
// Defer to the real stylelint/bin/stylelint.js your application uses
module.exports = absRequire(`stylelint/bin/stylelint.js`);

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require stylelint/lib/index.js
require(absPnpApiPath).setup();
}
}
// Defer to the real stylelint/lib/index.js your application uses
module.exports = absRequire(`stylelint/lib/index.js`);

View File

@@ -1,6 +0,0 @@
{
"name": "stylelint",
"version": "14.0.1-sdk",
"main": "lib/index.js",
"type": "commonjs"
}

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require typescript/bin/tsc
require(absPnpApiPath).setup();
}
}
// Defer to the real typescript/bin/tsc your application uses
module.exports = absRequire(`typescript/bin/tsc`);

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require typescript/bin/tsserver
require(absPnpApiPath).setup();
}
}
// Defer to the real typescript/bin/tsserver your application uses
module.exports = absRequire(`typescript/bin/tsserver`);

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require typescript/lib/tsc.js
require(absPnpApiPath).setup();
}
}
// Defer to the real typescript/lib/tsc.js your application uses
module.exports = absRequire(`typescript/lib/tsc.js`);

View File

@@ -1,184 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
const moduleWrapper = tsserver => {
if (!process.versions.pnp) {
return tsserver;
}
const {isAbsolute} = require(`path`);
const pnpApi = require(`pnpapi`);
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
return `${locator.name}@${locator.reference}`;
}));
// VSCode sends the zip paths to TS using the "zip://" prefix, that TS
// doesn't understand. This layer makes sure to remove the protocol
// before forwarding it to TS, and to add it back on all returned paths.
function toEditorPath(str) {
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
// We also take the opportunity to turn virtual paths into physical ones;
// this makes it much easier to work with workspaces that list peer
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
// file instances instead of the real ones.
//
// We only do this to modules owned by the the dependency tree roots.
// This avoids breaking the resolution when jumping inside a vendor
// with peer dep (otherwise jumping into react-dom would show resolution
// errors on react).
//
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
if (resolved) {
const locator = pnpApi.findPackageLocator(resolved);
if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) {
str = resolved;
}
}
str = normalize(str);
if (str.match(/\.zip\//)) {
switch (hostInfo) {
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
// VSCode only adds it automatically for supported schemes,
// so we have to do it manually for the `zip` scheme.
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
//
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
//
// Update Oct 8 2021: VSCode changed their format in 1.61.
// Before | ^zip:/c:/foo/bar.zip/package.json
// After | ^/zip//c:/foo/bar.zip/package.json
//
case `vscode <1.61`: {
str = `^zip:${str}`;
} break;
case `vscode`: {
str = `^/zip/${str}`;
} break;
// To make "go to definition" work,
// We have to resolve the actual file system path from virtual path
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
case `coc-nvim`: {
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
str = resolve(`zipfile:${str}`);
} break;
// Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
// We have to resolve the actual file system path from virtual path,
// everything else is up to neovim
case `neovim`: {
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
str = `zipfile:${str}`;
} break;
default: {
str = `zip:${str}`;
} break;
}
}
}
return str;
}
function fromEditorPath(str) {
switch (hostInfo) {
case `coc-nvim`:
case `neovim`: {
str = str.replace(/\.zip::/, `.zip/`);
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
// So in order to convert it back, we use .* to match all the thing
// before `zipfile:`
return process.platform === `win32`
? str.replace(/^.*zipfile:\//, ``)
: str.replace(/^.*zipfile:/, ``);
} break;
case `vscode`:
default: {
return process.platform === `win32`
? str.replace(/^\^?(zip:|\/zip)\/+/, ``)
: str.replace(/^\^?(zip:|\/zip)\/+/, `/`);
} break;
}
}
// Force enable 'allowLocalPluginLoads'
// TypeScript tries to resolve plugins using a path relative to itself
// which doesn't work when using the global cache
// https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
// VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
// TypeScript already does local loads and if this code is running the user trusts the workspace
// https://github.com/microsoft/vscode/issues/45856
const ConfiguredProject = tsserver.server.ConfiguredProject;
const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
ConfiguredProject.prototype.enablePluginsWithOptions = function() {
this.projectService.allowLocalPluginLoads = true;
return originalEnablePluginsWithOptions.apply(this, arguments);
};
// And here is the point where we hijack the VSCode <-> TS communications
// by adding ourselves in the middle. We locate everything that looks
// like an absolute path of ours and normalize it.
const Session = tsserver.server.Session;
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
let hostInfo = `unknown`;
Object.assign(Session.prototype, {
onMessage(/** @type {string} */ message) {
const parsedMessage = JSON.parse(message)
if (
parsedMessage != null &&
typeof parsedMessage === `object` &&
parsedMessage.arguments &&
typeof parsedMessage.arguments.hostInfo === `string`
) {
hostInfo = parsedMessage.arguments.hostInfo;
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK && process.env.VSCODE_IPC_HOOK.match(/Code\/1\.([1-5][0-9]|60)\./)) {
hostInfo += ` <1.61`;
}
}
return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {
return typeof value === `string` ? fromEditorPath(value) : value;
}));
},
send(/** @type {any} */ msg) {
return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
return typeof value === `string` ? toEditorPath(value) : value;
})));
}
});
return tsserver;
};
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require typescript/lib/tsserver.js
require(absPnpApiPath).setup();
}
}
// Defer to the real typescript/lib/tsserver.js your application uses
module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`));

View File

@@ -1,184 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
const moduleWrapper = tsserver => {
if (!process.versions.pnp) {
return tsserver;
}
const {isAbsolute} = require(`path`);
const pnpApi = require(`pnpapi`);
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
return `${locator.name}@${locator.reference}`;
}));
// VSCode sends the zip paths to TS using the "zip://" prefix, that TS
// doesn't understand. This layer makes sure to remove the protocol
// before forwarding it to TS, and to add it back on all returned paths.
function toEditorPath(str) {
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
// We also take the opportunity to turn virtual paths into physical ones;
// this makes it much easier to work with workspaces that list peer
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
// file instances instead of the real ones.
//
// We only do this to modules owned by the the dependency tree roots.
// This avoids breaking the resolution when jumping inside a vendor
// with peer dep (otherwise jumping into react-dom would show resolution
// errors on react).
//
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
if (resolved) {
const locator = pnpApi.findPackageLocator(resolved);
if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) {
str = resolved;
}
}
str = normalize(str);
if (str.match(/\.zip\//)) {
switch (hostInfo) {
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
// VSCode only adds it automatically for supported schemes,
// so we have to do it manually for the `zip` scheme.
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
//
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
//
// Update Oct 8 2021: VSCode changed their format in 1.61.
// Before | ^zip:/c:/foo/bar.zip/package.json
// After | ^/zip//c:/foo/bar.zip/package.json
//
case `vscode <1.61`: {
str = `^zip:${str}`;
} break;
case `vscode`: {
str = `^/zip/${str}`;
} break;
// To make "go to definition" work,
// We have to resolve the actual file system path from virtual path
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
case `coc-nvim`: {
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
str = resolve(`zipfile:${str}`);
} break;
// Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
// We have to resolve the actual file system path from virtual path,
// everything else is up to neovim
case `neovim`: {
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
str = `zipfile:${str}`;
} break;
default: {
str = `zip:${str}`;
} break;
}
}
}
return str;
}
function fromEditorPath(str) {
switch (hostInfo) {
case `coc-nvim`:
case `neovim`: {
str = str.replace(/\.zip::/, `.zip/`);
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
// So in order to convert it back, we use .* to match all the thing
// before `zipfile:`
return process.platform === `win32`
? str.replace(/^.*zipfile:\//, ``)
: str.replace(/^.*zipfile:/, ``);
} break;
case `vscode`:
default: {
return process.platform === `win32`
? str.replace(/^\^?(zip:|\/zip)\/+/, ``)
: str.replace(/^\^?(zip:|\/zip)\/+/, `/`);
} break;
}
}
// Force enable 'allowLocalPluginLoads'
// TypeScript tries to resolve plugins using a path relative to itself
// which doesn't work when using the global cache
// https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
// VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
// TypeScript already does local loads and if this code is running the user trusts the workspace
// https://github.com/microsoft/vscode/issues/45856
const ConfiguredProject = tsserver.server.ConfiguredProject;
const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
ConfiguredProject.prototype.enablePluginsWithOptions = function() {
this.projectService.allowLocalPluginLoads = true;
return originalEnablePluginsWithOptions.apply(this, arguments);
};
// And here is the point where we hijack the VSCode <-> TS communications
// by adding ourselves in the middle. We locate everything that looks
// like an absolute path of ours and normalize it.
const Session = tsserver.server.Session;
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
let hostInfo = `unknown`;
Object.assign(Session.prototype, {
onMessage(/** @type {string} */ message) {
const parsedMessage = JSON.parse(message)
if (
parsedMessage != null &&
typeof parsedMessage === `object` &&
parsedMessage.arguments &&
typeof parsedMessage.arguments.hostInfo === `string`
) {
hostInfo = parsedMessage.arguments.hostInfo;
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK && process.env.VSCODE_IPC_HOOK.match(/Code\/1\.([1-5][0-9]|60)\./)) {
hostInfo += ` <1.61`;
}
}
return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {
return typeof value === `string` ? fromEditorPath(value) : value;
}));
},
send(/** @type {any} */ msg) {
return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
return typeof value === `string` ? toEditorPath(value) : value;
})));
}
});
return tsserver;
};
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require typescript/lib/tsserverlibrary.js
require(absPnpApiPath).setup();
}
}
// Defer to the real typescript/lib/tsserverlibrary.js your application uses
module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`));

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require typescript/lib/typescript.js
require(absPnpApiPath).setup();
}
}
// Defer to the real typescript/lib/typescript.js your application uses
module.exports = absRequire(`typescript/lib/typescript.js`);

View File

@@ -1,6 +0,0 @@
{
"name": "typescript",
"version": "4.4.3-sdk",
"main": "./lib/typescript.js",
"type": "commonjs"
}

View File

@@ -1,82 +0,0 @@
enableTelemetry: false
nodeLinker: pnp
packageExtensions:
"@grafana/slate-react@0.22.10-grafana":
peerDependencies:
slate-react: ">=0.22.0"
"@mdx-js/loader@1.6.22":
peerDependencies:
react: 17.0.1
"@storybook/addon-docs@6.4.4":
peerDependencies:
"@storybook/manager-webpack5": 6.4.4
"@storybook/addon-essentials@6.4.4":
peerDependencies:
"@storybook/components": 6.4.4
"@storybook/core-events": 6.4.4
"@storybook/manager-webpack5": 6.4.4
"@storybook/theming": 6.4.4
"@storybook/core-server@6.4.4":
peerDependencies:
"@babel/core": ^7.0.0
"@storybook/core@6.4.4":
peerDependencies:
"@babel/core": ^7.0.0
"@storybook/manager-webpack5": 6.4.4
"@storybook/csf-tools@6.4.4":
peerDependencies:
"@babel/core": ^7.0.0
"@storybook/react@6.4.4":
peerDependencies:
"@storybook/manager-webpack5": 6.4.4
doctrine@3.0.0:
dependencies:
assert: 2.0.0
moveable@0.26.0:
dependencies:
"@daybrush/utils": 1.6.0
framework-utils: ^1.1.0
react-simple-compat: 1.2.1
rc-time-picker@3.7.3:
peerDependencies:
react: 17.0.1
react-dom: 17.0.1
rc-trigger@2.6.5:
peerDependencies:
react: 17.0.1
react-dom: 17.0.1
react-compat-moveable@0.14.0:
dependencies:
"@egjs/agent": ^2.2.1
"@egjs/children-differ": ^1.0.1
"@scena/matrix": 1.1.1
css-to-mat: ^1.0.3
gesto: ^1.4.0
overlap-area: ^1.0.0
peerDependencies:
framework-utils: ^1.1.0
react-dev-utils@11.0.4:
peerDependencies:
typescript: 4.4.3
webpack: 5.51.1
react-docgen-typescript-loader@3.7.2:
peerDependencies:
webpack: 4.41.5
react-icons@2.2.7:
peerDependencies:
prop-types: "*"
react-resizable@3.0.4:
peerDependencies:
react-dom: 17.0.1
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
spec: "@yarnpkg/plugin-typescript"
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"
- path: .yarn/plugins/@yarnpkg/plugin-outdated.cjs
spec: "https://mskelton.dev/yarn-outdated/v2"
yarnPath: .yarn/releases/yarn-3.1.1.cjs

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
# 5.4.5 (2019-08-29)
- **Security**: Urgent security patch release. Please read more in our [blog](https://grafana.com/blog/2019/08/29/grafana-5.4.5-and-6.3.4-released-with-important-security-fix/)
@@ -179,7 +180,7 @@ See [security announcement](https://community.grafana.com/t/grafana-5-3-3-and-4-
- **Alerting**: Link to view full size image in Microsoft Teams alert notifier [#13121](https://github.com/grafana/grafana/issues/13121), thx [@holiiveira](https://github.com/holiiveira)
- **Alerting**: Fixes a bug where all alerts would send reminders after upgrade & restart [#13402](https://github.com/grafana/grafana/pull/13402)
- **Alerting**: Concurrent render limit for graphs used in notifications [#13401](https://github.com/grafana/grafana/pull/13401)
- **Postgres/MySQL/MSSQL**: Add support for replacing $\_\_interval and $\_\_interval_ms in alert queries [#11555](https://github.com/grafana/grafana/issues/11555), thx [@svenklemm](https://github.com/svenklemm)
- **Postgres/MySQL/MSSQL**: Add support for replacing $__interval and $\_\_interval_ms in alert queries [#11555](https://github.com/grafana/grafana/issues/11555), thx [@svenklemm](https://github.com/svenklemm)
# 5.3.0-beta1 (2018-09-06)
@@ -213,18 +214,18 @@ See [security announcement](https://community.grafana.com/t/grafana-5-3-3-and-4-
- **OAuth**: Fix overriding tls_skip_verify_insecure using environment variable [#12747](https://github.com/grafana/grafana/issues/12747), thx [@jangaraj](https://github.com/jangaraj)
- **Prometheus**: Fix graph panel bar width issue in aligned prometheus queries [#12379](https://github.com/grafana/grafana/issues/12379)
- **Prometheus**: Heatmap - fix unhandled error when some points are missing [#12484](https://github.com/grafana/grafana/issues/12484)
- **Prometheus**: Add $**interval, $**interval_ms, \$**range, $**range_s & $\_\_range_ms support for dashboard and template queries [#12597](https://github.com/grafana/grafana/issues/12597) [#12882](https://github.com/grafana/grafana/issues/12882), thx [@roidelapluie](https://github.com/roidelapluie)
- **Prometheus**: Add $__interval, $**interval_ms, \$**range, $__range_s & $\_\_range_ms support for dashboard and template queries [#12597](https://github.com/grafana/grafana/issues/12597) [#12882](https://github.com/grafana/grafana/issues/12882), thx [@roidelapluie](https://github.com/roidelapluie)
- **Elasticsearch**: For alerting/backend, support having index name to the right of pattern in index pattern [#12731](https://github.com/grafana/grafana/issues/12731)
- **Graphite**: Fix for quoting of int function parameters (when using variables) [#11927](https://github.com/grafana/grafana/pull/11927)
- **InfluxDB**: Support timeFilter in query templating for InfluxDB [#12598](https://github.com/grafana/grafana/pull/12598), thx [kichristensen](https://github.com/kichristensen)
- **Postgres/MySQL/MSSQL**: New $\_\_unixEpochGroup and $\_\_unixEpochGroupAlias macros [#12892](https://github.com/grafana/grafana/issues/12892), thx [@svenklemm](https://github.com/svenklemm)
- **Postgres/MySQL/MSSQL**: New $__unixEpochGroup and $\_\_unixEpochGroupAlias macros [#12892](https://github.com/grafana/grafana/issues/12892), thx [@svenklemm](https://github.com/svenklemm)
- **Postgres/MySQL/MSSQL**: Add previous fill mode to \$\_\_timeGroup macro which will fill in previously seen value when point is missing [#12756](https://github.com/grafana/grafana/issues/12756), thx [@svenklemm](https://github.com/svenklemm)
- **Postgres/MySQL/MSSQL**: Use floor rounding in \$\_\_timeGroup macro function [#12460](https://github.com/grafana/grafana/issues/12460), thx [@svenklemm](https://github.com/svenklemm)
- **Postgres/MySQL/MSSQL**: Use metric column as prefix when returning multiple value columns [#12727](https://github.com/grafana/grafana/issues/12727), thx [@svenklemm](https://github.com/svenklemm)
- **Postgres/MySQL/MSSQL**: New $\_\_timeGroupAlias macro. Postgres $\_\_timeGroup no longer automatically adds time column alias [#12749](https://github.com/grafana/grafana/issues/12749), thx [@svenklemm](https://github.com/svenklemm)
- **Postgres/MySQL/MSSQL**: New $__timeGroupAlias macro. Postgres $\_\_timeGroup no longer automatically adds time column alias [#12749](https://github.com/grafana/grafana/issues/12749), thx [@svenklemm](https://github.com/svenklemm)
- **Postgres/MySQL/MSSQL**: Escape single quotes in variables [#12785](https://github.com/grafana/grafana/issues/12785), thx [@eMerzh](https://github.com/eMerzh)
- **Postgres/MySQL/MSSQL**: Min time interval support [#13157](https://github.com/grafana/grafana/issues/13157), thx [@svenklemm](https://github.com/svenklemm)
- **MySQL/MSSQL**: Use datetime format instead of epoch for $\_\_timeFilter, $**timeFrom and \$**timeTo macros [#11618](https://github.com/grafana/grafana/issues/11618) [#11619](https://github.com/grafana/grafana/issues/11619), thx [@AustinWinstanley](https://github.com/AustinWinstanley)
- **MySQL/MSSQL**: Use datetime format instead of epoch for $__timeFilter, $**timeFrom and \$**timeTo macros [#11618](https://github.com/grafana/grafana/issues/11618) [#11619](https://github.com/grafana/grafana/issues/11619), thx [@AustinWinstanley](https://github.com/AustinWinstanley)
- **Postgres**: Escape ssl mode parameter in connectionstring [#12644](https://github.com/grafana/grafana/issues/12644), thx [@yogyrahmawan](https://github.com/yogyrahmawan)
- **Cloudwatch**: Improved error handling [#12489](https://github.com/grafana/grafana/issues/12489), thx [@mtanda](https://github.com/mtanda)
- **Cloudwatch**: AppSync metrics and dimensions [#12300](https://github.com/grafana/grafana/issues/12300), thx [@franciscocpg](https://github.com/franciscocpg)
@@ -1018,7 +1019,7 @@ Pull Request: [#8472](https://github.com/grafana/grafana/pull/8472)
## Enhancements
- **Telegram**: Added Telegram alert notifier [#7098](https://github.com/grafana/grafana/pull/7098), thx [@leonoff](https://github.com/leonoff)
- **Templating**: Make $\_\_interval and $\_\_interval_ms global built in variables that can be used in by any data source (in panel queries), closes [#7190](https://github.com/grafana/grafana/issues/7190), closes [#6582](https://github.com/grafana/grafana/issues/6582)
- **Templating**: Make $__interval and $\_\_interval_ms global built in variables that can be used in by any data source (in panel queries), closes [#7190](https://github.com/grafana/grafana/issues/7190), closes [#6582](https://github.com/grafana/grafana/issues/6582)
- **S3 Image Store**: External s3 image store (used in alert notifications) now support AWS IAM Roles, closes [#6985](https://github.com/grafana/grafana/issues/6985), [#7058](https://github.com/grafana/grafana/issues/7058) thx [@mtanda](https://github.com/mtanda)
- **SingleStat**: Implements diff aggregation method for singlestat [#7234](https://github.com/grafana/grafana/issues/7234), thx [@oliverpool](https://github.com/oliverpool)
- **Dataproxy**: Added setting to enable more verbose logging in dataproxy [#7209](https://github.com/grafana/grafana/pull/7209), thx [@Ricky-N](https://github.com/Ricky-N)

View File

@@ -26,12 +26,10 @@ Report a bug by submitting a [bug report](https://github.com/grafana/grafana/iss
Follow the issue template and add additional information that will help us replicate the problem.
For data visualization issues:
- Query results from the inspect drawer (data tab & query inspector)
- Panel settings can be extracted in the panel inspect drawer JSON tab
For a dashboard related issues:
- Dashboard JSON can be found in the dashboard settings JSON model view
For authentication and alerting Grafana server logs are useful.
@@ -42,7 +40,7 @@ If you believe you've found a security vulnerability, please read our [security
### Suggest enhancements
If you have an idea of how to improve Grafana, submit an [enhancement request](https://github.com/grafana/grafana/discussions/new).
If you have an idea of how to improve Grafana, submit an [enhancement request](https://github.com/grafana/grafana/issues/new?labels=type%3A+feature+request&template=2-feature_request.md).
We want to make Grafana accessible to even more people. Submit an [accessibility issue](https://github.com/grafana/grafana/issues/new?labels=type%3A+accessibility&template=3-accessibility.md) to help us understand what we can improve.

View File

@@ -1,17 +1,14 @@
FROM node:16-alpine3.14 as js-builder
FROM node:14.16.0-alpine3.13 as js-builder
ENV NODE_OPTIONS=--max_old_space_size=8000
WORKDIR /usr/src/app/
WORKDIR /grafana
COPY package.json yarn.lock .yarnrc.yml ./
COPY .yarn .yarn
COPY package.json yarn.lock ./
COPY packages packages
COPY plugins-bundled plugins-bundled
RUN yarn install
RUN apk --no-cache add git
RUN yarn install --pure-lockfile --no-progress
COPY tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js babel.config.json ./
COPY tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js ./
COPY public public
COPY tools tools
COPY scripts scripts
@@ -20,26 +17,25 @@ COPY emails emails
ENV NODE_ENV production
RUN yarn build
FROM golang:1.17.3-alpine3.14 as go-builder
FROM golang:1.16.1-alpine3.13 as go-builder
RUN apk add --no-cache gcc g++ make
RUN apk add --no-cache gcc g++
WORKDIR /grafana
WORKDIR $GOPATH/src/github.com/grafana/grafana
COPY go.mod go.sum embed.go Makefile build.go package.json ./
COPY cue cue
COPY packages/grafana-schema packages/grafana-schema
COPY public/app/plugins public/app/plugins
COPY pkg pkg
COPY scripts scripts
COPY cue.mod cue.mod
COPY .bingo .bingo
COPY go.mod go.sum embed.go ./
RUN go mod verify
RUN make build-go
COPY cue cue
COPY public/app/plugins public/app/plugins
COPY pkg pkg
COPY build.go package.json ./
RUN go run build.go build
# Final stage
FROM alpine:3.14.3
FROM alpine:3.13
LABEL maintainer="Grafana team <hello@grafana.com>"
@@ -47,45 +43,43 @@ ARG GF_UID="472"
ARG GF_GID="0"
ENV PATH="/usr/share/grafana/bin:$PATH" \
GF_PATHS_CONFIG="/etc/grafana/grafana.ini" \
GF_PATHS_DATA="/var/lib/grafana" \
GF_PATHS_HOME="/usr/share/grafana" \
GF_PATHS_LOGS="/var/log/grafana" \
GF_PATHS_PLUGINS="/var/lib/grafana/plugins" \
GF_PATHS_PROVISIONING="/etc/grafana/provisioning"
GF_PATHS_CONFIG="/etc/grafana/grafana.ini" \
GF_PATHS_DATA="/var/lib/grafana" \
GF_PATHS_HOME="/usr/share/grafana" \
GF_PATHS_LOGS="/var/log/grafana" \
GF_PATHS_PLUGINS="/var/lib/grafana/plugins" \
GF_PATHS_PROVISIONING="/etc/grafana/provisioning"
WORKDIR $GF_PATHS_HOME
RUN apk add --no-cache ca-certificates bash tzdata musl-utils
RUN apk add --no-cache openssl ncurses-libs ncurses-terminfo-base --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
RUN apk upgrade ncurses-libs ncurses-terminfo-base --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
RUN apk info -vv | sort
RUN apk add --no-cache ca-certificates bash tzdata && \
apk add --no-cache openssl musl-utils
COPY conf ./conf
RUN if [ ! $(getent group "$GF_GID") ]; then \
addgroup -S -g $GF_GID grafana; \
fi
addgroup -S -g $GF_GID grafana; \
fi
RUN export GF_GID_NAME=$(getent group $GF_GID | cut -d':' -f1) && \
mkdir -p "$GF_PATHS_HOME/.aws" && \
adduser -S -u $GF_UID -G "$GF_GID_NAME" grafana && \
mkdir -p "$GF_PATHS_PROVISIONING/datasources" \
"$GF_PATHS_PROVISIONING/dashboards" \
"$GF_PATHS_PROVISIONING/notifiers" \
"$GF_PATHS_PROVISIONING/plugins" \
"$GF_PATHS_PROVISIONING/access-control" \
"$GF_PATHS_LOGS" \
"$GF_PATHS_PLUGINS" \
"$GF_PATHS_DATA" && \
cp "$GF_PATHS_HOME/conf/sample.ini" "$GF_PATHS_CONFIG" && \
cp "$GF_PATHS_HOME/conf/ldap.toml" /etc/grafana/ldap.toml && \
chown -R "grafana:$GF_GID_NAME" "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" && \
chmod -R 777 "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING"
mkdir -p "$GF_PATHS_HOME/.aws" && \
adduser -S -u $GF_UID -G "$GF_GID_NAME" grafana && \
mkdir -p "$GF_PATHS_PROVISIONING/datasources" \
"$GF_PATHS_PROVISIONING/dashboards" \
"$GF_PATHS_PROVISIONING/notifiers" \
"$GF_PATHS_PROVISIONING/plugins" \
"$GF_PATHS_PROVISIONING/access-control" \
"$GF_PATHS_LOGS" \
"$GF_PATHS_PLUGINS" \
"$GF_PATHS_DATA" && \
cp "$GF_PATHS_HOME/conf/sample.ini" "$GF_PATHS_CONFIG" && \
cp "$GF_PATHS_HOME/conf/ldap.toml" /etc/grafana/ldap.toml && \
chown -R "grafana:$GF_GID_NAME" "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" && \
chmod -R 777 "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING"
COPY --from=go-builder /grafana/bin/*/grafana-server /grafana/bin/*/grafana-cli ./bin/
COPY --from=js-builder /grafana/public ./public
COPY --from=js-builder /grafana/tools ./tools
COPY --from=go-builder /go/src/github.com/grafana/grafana/bin/*/grafana-server /go/src/github.com/grafana/grafana/bin/*/grafana-cli ./bin/
COPY --from=js-builder /usr/src/app/public ./public
COPY --from=js-builder /usr/src/app/tools ./tools
EXPOSE 3000

View File

@@ -1,18 +1,14 @@
FROM node:16-alpine3.14 as js-builder
ENV NODE_OPTIONS=--max_old_space_size=8000
FROM node:14.15.1-slim AS js-builder
WORKDIR /usr/src/app/
COPY package.json yarn.lock ./
COPY packages packages
COPY .yarnrc.yml ./
COPY .yarn .yarn
COPY plugins-bundled plugins-bundled
RUN yarn install
RUN apt-get update && apt-get install -yq git
RUN yarn install --pure-lockfile
COPY tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js babel.config.json ./
COPY tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js ./
COPY public public
COPY tools tools
COPY scripts scripts
@@ -21,21 +17,20 @@ COPY emails emails
ENV NODE_ENV production
RUN yarn build
FROM golang:1.17.3 AS go-builder
FROM golang:1.16 AS go-builder
WORKDIR /src/grafana
COPY go.mod go.sum embed.go ./
COPY Makefile build.go package.json ./
COPY .bingo .bingo
COPY pkg pkg/
COPY cue cue/
COPY cue.mod cue.mod/
COPY packages/grafana-schema packages/grafana-schema/
COPY public/app/plugins public/app/plugins/
RUN go mod verify
RUN make build-go
COPY build.go package.json ./
COPY pkg pkg/
COPY cue cue/
COPY public/app/plugins public/app/plugins/
RUN go run build.go build
FROM ubuntu:20.04

View File

@@ -4,7 +4,7 @@ The main goal of issue triage is to categorize all incoming Grafana issues and m
> **Note:** This information is for Grafana project Maintainers, Owners, and Admins. If you are a Contributor, then you will not be able to perform most of the tasks in this topic.
The core maintainers of the Grafana project are responsible for categorizing all incoming issues and delegating any critical or important issue to other maintainers. Currently one maintainer each week is responsible. Besides that part, triage provides an important way to contribute to an open source project.
The core maintainers of the Grafana project are responsible for categorizing all incoming issues and delegating any critical or important issue to other maintainers. Currently one maintainer each week is responsible. Besides that part, triage provides an important way to contribute to an open source project.
Triage helps ensure issues resolve quickly by:
@@ -18,7 +18,6 @@ If you don't have the knowledge or time to code, consider helping with triage. T
## Simplified flowchart diagram of the issue triage process
<!-- https://textik.com/#610afa78553def29 -->
```
+--------------------------+
+----------------+ New issue opened/ |
@@ -77,16 +76,15 @@ Instructions for setting up filters in Gmail can be found [here](#setting-up-gma
## 2. Ensure the issue contains basic information
Before triaging an issue very far, make sure that the issue's author provided the standard issue information. This will help you make an educated recommendation on how to categorize the issue. The Grafana project utilizes [GitHub issue templates](https://help.github.com/en/articles/creating-issue-templates-for-your-repository) to guide contributors to provide standard information that must be included for each type of template or type of issue.
Before triaging an issue very far, make sure that the issue's author provided the standard issue information. This will help you make an educated recommendation on how to categorize the issue. The Grafana project utilizes [GitHub issue templates](https://help.github.com/en/articles/creating-issue-templates-for-your-repository) to guide contributors to provide standard information that must be included for each type of template or type of issue.
### Standard issue information that must be included
Given a certain [issue template](<[template](https://github.com/grafana/grafana/issues/new/choose)>) have been used by the issue author or depending how the issue is perceived by the issue triage responsible, the following should help you understand what standard issue information that must be included.
Given a certain [issue template]([template](https://github.com/grafana/grafana/issues/new/choose)) have been used by the issue author or depending how the issue is perceived by the issue triage responsible, the following should help you understand what standard issue information that must be included.
#### Bug reports
Should explain what happened, what was expected and how to reproduce it together with any additional information that may help giving a complete picture of what happened such as screenshots, [query inspector](https://community.grafana.com/t/using-grafanas-query-inspector-to-troubleshoot-issues/2630) output and any environment related information that's applicable and/or maybe related to the reported problem:
- Grafana version
- Data source type & version
- Platform & OS Grafana is installed on
@@ -172,12 +170,10 @@ If it's not perfectly clear that it's an actual bug, quickly try to reproduce it
4. Move on to [prioritizing the issue](#4-prioritization-of-issues).
**It can't be reproduced:**
1. Either [ask for more information](#2-ensure-the-issue-contains-basic-information) needed to investigate it more thoroughly.
2. Either [delegate further investigations](#investigation-of-issues) to someone else.
**It works as intended/by design:**
1. Kindly and politely add a comment explaining briefly why we think it works as intended and close the issue.
2. Label the issue `type/works-as-intended`.
@@ -199,7 +195,6 @@ Second, label the issue `type/docs` and at least one `area/*` or `datasource/*`
**Minor typo/error/lack of information:**
There's a minor typo/error/lack of information that adds a lot of confusion for users and given the amount of work is a big win to make sure fixing it:
1. Either update the documentation yourself and open a pull request.
2. Either delegate the work to someone else by assigning that person to the issue and add the issue to next major/minor milestone.
@@ -304,12 +299,12 @@ For some other combinations it may not be possible at all for a maintainer to se
Even if you don't have the time or knowledge to investigate an issue we highly recommend that you [upvote](https://help.github.com/en/articles/about-conversations-on-github#reacting-to-ideas-in-comments) the issue if you happen to have the same problem. If you have further details that may help investigating the issue please provide as much information as possible.
## Automation
## Automation
We have some automation that triggers on comments or labels being added to issues. Many of these automated behaviors are defined in [commands.json](https://github.com/grafana/grafana/blob/main/.github/commands.json). Or in other [GitHub Actions](https://github.com/grafana/grafana/tree/main/.github/workflows)
- Add /duplicate `#<issue number>` to have Grafana label & close issue with an appropriate message.
- Add `bot/question` and the bot will close it with an appropriate message.
* Add /duplicate `#<issue number>` to have Grafana label & close issue with an appropriate message.
* Add `bot/question` and the bot will close it with an appropriate message.
[Read more on bot actions](https://github.com/grafana/grafana/blob/main/.github/bot.md)
@@ -329,7 +324,6 @@ Part of issue triage should also be triaging of external PRs. Main goal should b
If you're using Gmail it's highly recommended that you setup filters to automatically remove email from the inbox and label them accordingly to make it easy for you to understand when you need to act upon a notification or process all incoming issues that haven't been triaged.
This may be setup by personal preference, but here's a working configuration for reference.
1. Follow instructions in [gist](https://gist.github.com/marefr/9167c2e31466f6316c1cba118874e74f)
2. In Gmail, go to Settings -> Filters and Blocked Addresses
3. Import filters -> select xml file -> Open file
@@ -338,7 +332,6 @@ This may be setup by personal preference, but here's a working configuration for
6. Create filters
This will give you a structure of labels in the sidebar similar to the following:
```
- Inbox
...

View File

@@ -2,12 +2,9 @@
##
## For more information, refer to https://suva.sh/posts/well-documented-makefiles/
WIRE_TAGS = "oss"
-include local/Makefile
include .bingo/Variables.mk
.PHONY: all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-full lint-go golangci-lint test-go test-js gen-ts test run run-frontend clean devenv devenv-down protobuf drone help
.PHONY: all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-dev build-docker-full lint-go golangci-lint test-go test-js test run run-frontend clean devenv devenv-down protobuf drone help
GO = go
GO_FILES ?= ./pkg/...
@@ -26,15 +23,11 @@ deps: deps-js ## Install all dependencies.
node_modules: package.json yarn.lock ## Install node modules.
@echo "install frontend dependencies"
YARN_ENABLE_PROGRESS_BARS=false yarn install --immutable
yarn install --pure-lockfile --no-progress
##@ Building
gen-go: $(WIRE)
@echo "generate go files"
$(WIRE) gen -tags $(WIRE_TAGS) ./pkg/server ./pkg/cmd/grafana-cli/runner
build-go: gen-go ## Build all Go binaries.
build-go: ## Build all Go binaries.
@echo "build go files"
$(GO) run build.go build
@@ -43,7 +36,7 @@ build-server: ## Build Grafana server.
$(GO) run build.go build-server
build-cli: ## Build Grafana CLI application.
@echo "build grafana-cli"
@echo "build in CI environment"
$(GO) run build.go build-cli
build-js: ## Build frontend assets.
@@ -86,7 +79,7 @@ golangci-lint: scripts/go/bin/golangci-lint
--config ./scripts/go/configs/.golangci.toml \
$(GO_FILES)
lint-go: golangci-lint ## Run all code checks for backend. You can use GO_FILES to specify exact files to check
lint-go: golangci-lint # Run all code checks for backend.
# with disabled SC1071 we are ignored some TCL,Expect `/usr/bin/env expect` scripts
shellcheck: $(SH_FILES) ## Run checks for shell scripts.
@@ -95,6 +88,13 @@ shellcheck: $(SH_FILES) ## Run checks for shell scripts.
##@ Docker
build-docker-dev: ## Build Docker image for development (fast).
@echo "build development container"
@echo "\033[92mInfo:\033[0m the frontend code is expected to be built already."
$(GO) run build.go -goos linux -pkg-arch amd64 ${OPT} build pkg-archive latest
cp dist/grafana-latest.linux-x64.tar.gz packaging/docker
cd packaging/docker && docker build --tag grafana/grafana:dev .
build-docker-full: ## Build Docker image for development.
@echo "build docker container"
docker build --tag grafana/grafana:dev .
@@ -140,19 +140,13 @@ clean: ## Clean up intermediate build artifacts.
rm -rf node_modules
rm -rf public/build
gen-ts:
@echo "generating TypeScript definitions"
go get github.com/tkrajina/typescriptify-golang-structs/typescriptify@v0.1.7
tscriptify -interface -package=github.com/grafana/grafana/pkg/services/live/pipeline -import="import { FieldConfig } from '@grafana/data'" -target=public/app/features/live/pipeline/models.gen.ts pkg/services/live/pipeline/config.go
go mod tidy
# This repository's configuration is protected (https://readme.drone.io/signature/).
# Use this make target to regenerate the configuration YAML files when
# Use this make target to regenerate the configuration YAML files when
# you modify starlark files.
drone: $(DRONE)
$(DRONE) starlark --format
$(DRONE) lint .drone.yml --trusted
$(DRONE) --server https://drone.grafana.net sign --save grafana/grafana
drone:
drone starlark
drone lint
drone --server https://drone.grafana.net sign --save grafana/grafana
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

View File

@@ -1,4 +1,6 @@
Copyright 2014-2021 Grafana Labs
This software is based on Kibana:
This software is based on Kibana:
Copyright 2012-2013 Elasticsearch BV

View File

@@ -1,27 +1,27 @@
# Plugin development
# Plugin development
This document is not meant as a complete guide for developing plugins but more as a changelog for changes in
Grafana that can impact plugin development. Whenever you as a plugin author encounter an issue with your plugin after
upgrading Grafana please check here before creating an issue.
upgrading Grafana please check here before creating an issue.
## Plugin development resources
- [Grafana plugin developer guide](https://grafana.com/docs/grafana/latest/developers/plugins/)
- [Grafana plugin developer guide](http://docs.grafana.org/plugins/developing/development/)
- [Webpack Grafana plugin template project](https://github.com/CorpGlory/grafana-plugin-template-webpack)
- [Simple JSON datasource plugin](https://github.com/grafana/simple-json-datasource)
## Changes in Grafana v4.6
This version of Grafana has big changes that will impact a limited set of plugins. We moved from systemjs to webpack
for built-in plugins and everything internal. External plugins still use systemjs but now with a limited
set of Grafana components they can import. Plugins can depend on libs like lodash & moment and internal components
like before using the same import paths. However since everything in Grafana is no longer accessible, a few plugins could encounter issues when importing a Grafana dependency.
for built-in plugins and everything internal. External plugins still use systemjs but now with a limited
set of Grafana components they can import. Plugins can depend on libs like lodash & moment and internal components
like before using the same import paths. However since everything in Grafana is no longer accessible, a few plugins could encounter issues when importing a Grafana dependency.
[List of exposed components plugins can import/require](https://github.com/grafana/grafana/blob/main/public/app/features/plugins/plugin_loader.ts#L48)
If you think we missed exposing a crucial lib or Grafana component let us know by opening an issue.
If you think we missed exposing a crucial lib or Grafana component let us know by opening an issue.
### Deprecated components
### Deprecated components
The angular directive `<spectrum-picker>` is now deprecated (will still work for a version more) but we recommend plugin authors
upgrade to new `<color-picker color="ctrl.color" onChange="ctrl.onSparklineColorChange"></color-picker>`

View File

@@ -30,8 +30,8 @@ The Grafana documentation is available at [grafana.com/docs](https://grafana.com
If you're interested in contributing to the Grafana project:
- Start by reading the [Contributing guide](https://github.com/grafana/grafana/blob/HEAD/CONTRIBUTING.md).
- Learn how to set up your local environment, in our [Developer guide](https://github.com/grafana/grafana/blob/HEAD/contribute/developer-guide.md).
- Start by reading the [Contributing guide](/CONTRIBUTING.md).
- Learn how to set up your local environment, in our [Developer guide](/contribute/developer-guide.md).
- Explore our [beginner-friendly issues](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22).
- Look through our [style guide and Storybook](https://developers.grafana.com/ui/latest/index.html).
@@ -40,8 +40,8 @@ If you're interested in contributing to the Grafana project:
- Follow [@grafana on Twitter](https://twitter.com/grafana/).
- Read and subscribe to the [Grafana blog](https://grafana.com/blog/).
- If you have a specific question, check out our [discussion forums](https://community.grafana.com/).
- For general discussions, join us on the [official Slack](https://slack.grafana.com) team.
- For general discussions, join us on the [official Slack](http://slack.raintank.io/) team.
## License
Grafana is distributed under [AGPL-3.0-only](LICENSE). For Apache-2.0 exceptions, see [LICENSING.md](https://github.com/grafana/grafana/blob/HEAD/LICENSING.md).
Grafana is distributed under [AGPL-3.0-only](LICENSE). For Apache-2.0 exceptions, see [LICENSING.md](LICENSING.md).

View File

@@ -1,5 +1,5 @@
# Roadmap
The roadmap is a tentative plan for the core development team. Things change constantly as pull requests come in and priorities change, but it will give you an idea of our current vision and plan.
The roadmap is a tentative plan for the core development team. Things change constantly as pull requests come in and priorities change, but it will give you an idea of our current vision and plan.
To view the Roadmap, go to the Issues tab on GitHub. There you will find three roadmap issues pinned at the top.

View File

@@ -1,10 +1,10 @@
# Reporting security issues
If you think you have found a security vulnerability, please send a report to [security@grafana.com](mailto:security@grafana.com). This address can be used for all of Grafana Labs's open source and commercial products (including but not limited to Grafana, Grafana Cloud, Grafana Enterprise, and grafana.com). We can accept only vulnerability reports at this address.
If you think you have found a security vulnerability, please send a report to [security@grafana.com](mailto:security@grafana.com). This address can be used for all of Grafana Labs's open source and commercial products (including but not limited to Grafana, Grafana Cloud, Grafana Enterprise, and grafana.com). We can accept only vulnerability reports at this address.
Please encrypt your message to us; please use our PGP key. The key fingerprint is:
F988 7BEA 027A 049F AE8E 5CAA D125 8932 BE24 C5CA
F988 7BEA 027A 049F AE8E 5CAA D125 8932 BE24 C5CA
The key is available from [keyserver.ubuntu.com](https://keyserver.ubuntu.com/pks/lookup?search=0xF9887BEA027A049FAE8E5CAAD1258932BE24C5CA&fingerprint=on&op=index).
@@ -14,7 +14,7 @@ Grafana Labs will send you a response indicating the next steps in handling your
## Security announcements
We maintain a category on the community site called [Security Announcements](https://community.grafana.com/c/support/security-announcements),
where we will post a summary, remediation, and mitigation details for any patch containing security fixes.
We maintain a category on the community site called [Security Announcements](https://community.grafana.com/c/security-announcements),
where we will post a summary, remediation, and mitigation details for any patch containing security fixes.
You can also subscribe to email updates to this category if you have a grafana.com account and sign on to the community site or track updates via an [RSS feed](https://community.grafana.com/c/support/security-announcements.rss).
You can also subscribe to email updates to this category if you have a grafana.com account and sign on to the community site or track updates via an [RSS feed](https://community.grafana.com/c/security-announcements.rss).

View File

@@ -1,13 +1,10 @@
# Get Grafana help
---
------------------
First, check the official [Grafana documentation](https://grafana.com/docs/).
If you require further help or support then ask a question in the [Grafana community site](https://community.grafana.com/) or [Grafana Slack](http://slack.raintank.io/). You can also search the community site for previously answered questions, in case someone already had your problem and got help.
**Please note:**
**Please note:**
- The Grafana project uses GitHub mainly for tracking bugs and feature requests.
- Do not open an issue just to ask a question. The issue will be closed immediately.
- Only submit issues for bug reports, feature requests, or enhancements.

View File

@@ -13,7 +13,6 @@ Team members and their access to repositories is maintained through [GitHub team
## Proposing changes
Examples of proposed changes are overarching architecture, component design, and specific code or graphical elements. Proposed changes SHOULD cover the big picture and intention, but individual parts SHOULD be split into the smallest possible changes. Changes SHOULD be based on and target the main branch. Depending on size of the proposed change, each change SHOULD be discussed, in increasing order of change size and complexity:
- Directly in a RR (Pull Request) - this MAY be done, but SHOULD not be the common case.
- Issue
- Developer mailing list
@@ -25,7 +24,6 @@ Significant changes MUST be discussed and agreed upon with the relevant subsyste
Depending on the size and complexity of a PR, different requirements MUST be applied. Any team member contributing substantially to a PR MUST NOT count against review requirements.
Commits MUST be merged into main using PRs. They MUST NOT be merged into main directly.
- Every merge MUST be approved by at least one team member.
- Non-trivial changes MUST be approved by at least
- two team members, or
@@ -35,7 +33,6 @@ Commits MUST be merged into main using PRs. They MUST NOT be merged into main di
- the relevant subsystem maintainer.
PRs MUST be [reviewed](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/reviewing-changes-in-pull-requests) and [approved](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/approving-a-pull-request-with-required-reviews) via GitHubs review system.
- Reviewers MAY write comments if approving
- Reviewers MUST write comments if rejecting a PR or if requesting changes.
@@ -43,9 +40,9 @@ Once a PR is approved as per above, any team member MAY merge the PR.
## Backporting a PR
PRs intended for inclusion in the next PATCH release they must be backported to the release branch. The bot can do this automatically. [Read more on backport PRs](https://github.com/grafana/grafana/blob/main/.github/bot.md). Both the source PR and the backport PR should be assigned to the patch release milestone, unless you are backporting to many releases then it can differ.
PRs intended for inclusion in the next PATCH release they must be backported to the release branch. The bot can do this automatically. [Read more on backport PRs](https://github.com/grafana/grafana/blob/main/.github/bot.md). Both the source PR and the backport PR should be assigned to the patch release milestone, unless you are backporting to many releases then it can differ.
Backport PRs are also needed during the beta period to get fixes into the stable release.
Backport PRs are also needed during the beta period to get fixes into the stable release.
# Release workflow
@@ -54,7 +51,6 @@ Backport PRs are also needed during the beta period to get fixes into the stable
Grafana uses trunk-based development.
In particular, we found that the following principles match how we work:
- Main and release branches MUST always build without failure.
- Branches SHOULD be merged often. Larger changes SHOULD be activated with feature flags until they are ready. Long-lived development branches SHOULD be avoided.
- Changes MAY be enabled by default once they are in a complete state
@@ -65,7 +61,6 @@ In particular, we found that the following principles match how we work:
Releases MUST follow [Semantic Versioning](https://semver.org/) in naming and SHOULD follow Semantic Versioning as closely as reasonably possible for non-library software.
Release branches MUST be split from the following branches.
- MAJOR release branches MUST be based on main.
- MINOR release branches MUST be based on main.
- PATCH release branches MUST be split from the relevant MINOR release branchs most current PATCH
@@ -73,7 +68,6 @@ Release branches MUST be split from the following branches.
Security releases follow the same process but MUST be prepared in secret. Security releases MUST NOT include changes which are not related to the security fix. Normal release processes MUST accommodate the security release process. SECURITY.md MUST be followed.
Releases follow the following cadence
- MAJOR: Yearly
- MINOR: Every 4-6 weeks
- PATCH: As needed

View File

@@ -1,58 +0,0 @@
{
"babelrc": false,
// Note: order is bottom-to-top and/or right-to-left
"presets": [
[
"@babel/preset-env",
{
"bugfixes": true,
"browserslistEnv": "dev",
"useBuiltIns": "entry",
"corejs": "3.10"
}
],
[
"@babel/preset-typescript",
{
"allowNamespaces": true,
"allowDeclareFields": true
}
],
[
"@babel/preset-react",
{
"runtime": "automatic"
}
]
],
"plugins": [
[
"@babel/plugin-transform-typescript",
{
"allowNamespaces": true,
"allowDeclareFields": true
}
],
["@babel/plugin-proposal-object-rest-spread", { "loose": true }],
"@babel/plugin-transform-react-constant-elements",
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-syntax-dynamic-import", // needed for `() => import()` in routes.ts
"angularjs-annotate"
],
"env": {
"production": {
"presets": [
[
"@babel/preset-env",
{
"browserslistEnv": "production"
}
]
]
},
"hot": {
"plugins": ["react-refresh/babel"]
}
}
}

466
build.go
View File

@@ -3,14 +3,476 @@
package main
import (
"bytes"
"crypto/md5"
"crypto/sha256"
"encoding/json"
"flag"
"fmt"
"go/build"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
)
"github.com/grafana/grafana/pkg/build"
const (
windows = "windows"
linux = "linux"
)
var (
//versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
goarch string
goos string
gocc string
cgo bool
libc string
pkgArch string
version string = "v1"
buildTags []string
// deb & rpm does not support semver so have to handle their version a little differently
linuxPackageVersion string = "v1"
linuxPackageIteration string = ""
race bool
workingDir string
includeBuildId bool = true
buildId string = "0"
serverBinary string = "grafana-server"
cliBinary string = "grafana-cli"
binaries []string = []string{serverBinary, cliBinary}
isDev bool = false
enterprise bool = false
skipRpmGen bool = false
skipDebGen bool = false
printGenVersion bool = false
)
func main() {
log.SetOutput(os.Stdout)
log.SetFlags(0)
os.Exit(build.RunCmd())
var buildIdRaw string
var buildTagsRaw string
flag.StringVar(&goarch, "goarch", runtime.GOARCH, "GOARCH")
flag.StringVar(&goos, "goos", runtime.GOOS, "GOOS")
flag.StringVar(&gocc, "cc", "", "CC")
flag.StringVar(&libc, "libc", "", "LIBC")
flag.StringVar(&buildTagsRaw, "build-tags", "", "Sets custom build tags")
flag.BoolVar(&cgo, "cgo-enabled", cgo, "Enable cgo")
flag.StringVar(&pkgArch, "pkg-arch", "", "PKG ARCH")
flag.BoolVar(&race, "race", race, "Use race detector")
flag.BoolVar(&includeBuildId, "includeBuildId", includeBuildId, "IncludeBuildId in package name")
flag.BoolVar(&enterprise, "enterprise", enterprise, "Build enterprise version of Grafana")
flag.StringVar(&buildIdRaw, "buildId", "0", "Build ID from CI system")
flag.BoolVar(&isDev, "dev", isDev, "optimal for development, skips certain steps")
flag.BoolVar(&skipRpmGen, "skipRpm", skipRpmGen, "skip rpm package generation (default: false)")
flag.BoolVar(&skipDebGen, "skipDeb", skipDebGen, "skip deb package generation (default: false)")
flag.BoolVar(&printGenVersion, "gen-version", printGenVersion, "generate Grafana version and output (default: false)")
flag.Parse()
buildId = shortenBuildId(buildIdRaw)
readVersionFromPackageJson()
if pkgArch == "" {
pkgArch = goarch
}
if printGenVersion {
printGeneratedVersion()
return
}
if len(buildTagsRaw) > 0 {
buildTags = strings.Split(buildTagsRaw, ",")
}
log.Printf("Version: %s, Linux Version: %s, Package Iteration: %s\n", version, linuxPackageVersion, linuxPackageIteration)
if flag.NArg() == 0 {
log.Println("Usage: go run build.go build")
return
}
workingDir, _ = os.Getwd()
for _, cmd := range flag.Args() {
switch cmd {
case "setup":
setup()
case "build-srv", "build-server":
clean()
doBuild("grafana-server", "./pkg/cmd/grafana-server", buildTags)
case "build-cli":
clean()
doBuild("grafana-cli", "./pkg/cmd/grafana-cli", buildTags)
case "build":
//clean()
for _, binary := range binaries {
doBuild(binary, "./pkg/cmd/"+binary, buildTags)
}
case "build-frontend":
yarn("build")
case "sha-dist":
shaFilesInDist()
case "latest":
makeLatestDistCopies()
case "clean":
clean()
default:
log.Fatalf("Unknown command %q", cmd)
}
}
}
func makeLatestDistCopies() {
files, err := ioutil.ReadDir("dist")
if err != nil {
log.Fatalf("failed to create latest copies. Cannot read from /dist")
}
latestMapping := map[string]string{
"_amd64.deb": "dist/grafana_latest_amd64.deb",
".x86_64.rpm": "dist/grafana-latest-1.x86_64.rpm",
".linux-amd64.tar.gz": "dist/grafana-latest.linux-x64.tar.gz",
".linux-amd64-musl.tar.gz": "dist/grafana-latest.linux-x64-musl.tar.gz",
".linux-armv7.tar.gz": "dist/grafana-latest.linux-armv7.tar.gz",
".linux-armv7-musl.tar.gz": "dist/grafana-latest.linux-armv7-musl.tar.gz",
".linux-armv6.tar.gz": "dist/grafana-latest.linux-armv6.tar.gz",
".linux-arm64.tar.gz": "dist/grafana-latest.linux-arm64.tar.gz",
".linux-arm64-musl.tar.gz": "dist/grafana-latest.linux-arm64-musl.tar.gz",
}
for _, file := range files {
for extension, fullName := range latestMapping {
if strings.HasSuffix(file.Name(), extension) {
runError("cp", path.Join("dist", file.Name()), fullName)
}
}
}
}
func readVersionFromPackageJson() {
reader, err := os.Open("package.json")
if err != nil {
log.Fatal("Failed to open package.json")
return
}
defer reader.Close()
jsonObj := map[string]interface{}{}
jsonParser := json.NewDecoder(reader)
if err := jsonParser.Decode(&jsonObj); err != nil {
log.Fatal("Failed to decode package.json")
}
version = jsonObj["version"].(string)
linuxPackageVersion = version
linuxPackageIteration = ""
// handle pre version stuff (deb / rpm does not support semver)
parts := strings.Split(version, "-")
if len(parts) > 1 {
linuxPackageVersion = parts[0]
linuxPackageIteration = parts[1]
}
// add timestamp to iteration
if includeBuildId {
if buildId != "0" {
linuxPackageIteration = fmt.Sprintf("%s%s", buildId, linuxPackageIteration)
} else {
linuxPackageIteration = fmt.Sprintf("%d%s", time.Now().Unix(), linuxPackageIteration)
}
}
}
func yarn(params ...string) {
runPrint(`yarn run`, params...)
}
func genPackageVersion() string {
if includeBuildId {
return fmt.Sprintf("%v-%v", linuxPackageVersion, linuxPackageIteration)
} else {
return version
}
}
func setup() {
args := []string{"install", "-v"}
if goos == windows {
args = append(args, "-buildmode=exe")
}
args = append(args, "./pkg/cmd/grafana-server")
runPrint("go", args...)
}
func printGeneratedVersion() {
fmt.Print(genPackageVersion())
}
func test(pkg string) {
setBuildEnv()
args := []string{"test", "-short", "-timeout", "60s"}
if goos == windows {
args = append(args, "-buildmode=exe")
}
args = append(args, pkg)
runPrint("go", args...)
}
func doBuild(binaryName, pkg string, tags []string) {
libcPart := ""
if libc != "" {
libcPart = fmt.Sprintf("-%s", libc)
}
binary := fmt.Sprintf("./bin/%s-%s%s/%s", goos, goarch, libcPart, binaryName)
if isDev {
//don't include os/arch/libc in output path in dev environment
binary = fmt.Sprintf("./bin/%s", binaryName)
}
if goos == windows {
binary += ".exe"
}
if !isDev {
rmr(binary, binary+".md5")
}
args := []string{"build", "-ldflags", ldflags()}
if goos == windows {
// Work around a linking error on Windows: "export ordinal too large"
args = append(args, "-buildmode=exe")
}
if len(tags) > 0 {
args = append(args, "-tags", strings.Join(tags, ","))
}
if race {
args = append(args, "-race")
}
args = append(args, "-o", binary)
args = append(args, pkg)
if !isDev {
setBuildEnv()
runPrint("go", "version")
libcPart := ""
if libc != "" {
libcPart = fmt.Sprintf("/%s", libc)
}
fmt.Printf("Targeting %s/%s%s\n", goos, goarch, libcPart)
}
runPrint("go", args...)
if !isDev {
// Create an md5 checksum of the binary, to be included in the archive for
// automatic upgrades.
err := md5File(binary)
if err != nil {
log.Fatal(err)
}
}
}
func ldflags() string {
var b bytes.Buffer
b.WriteString("-w")
b.WriteString(fmt.Sprintf(" -X main.version=%s", version))
b.WriteString(fmt.Sprintf(" -X main.commit=%s", getGitSha()))
b.WriteString(fmt.Sprintf(" -X main.buildstamp=%d", buildStamp()))
b.WriteString(fmt.Sprintf(" -X main.buildBranch=%s", getGitBranch()))
if v := os.Getenv("LDFLAGS"); v != "" {
b.WriteString(fmt.Sprintf(" -extldflags \"%s\"", v))
}
return b.String()
}
func rmr(paths ...string) {
for _, path := range paths {
log.Println("rm -r", path)
os.RemoveAll(path)
}
}
func clean() {
if isDev {
return
}
rmr("dist")
rmr("tmp")
rmr(filepath.Join(build.Default.GOPATH, fmt.Sprintf("pkg/%s_%s/github.com/grafana", goos, goarch)))
}
func setBuildEnv() {
os.Setenv("GOOS", goos)
if goos == windows {
// require windows >=7
os.Setenv("CGO_CFLAGS", "-D_WIN32_WINNT=0x0601")
}
if goarch != "amd64" || goos != linux {
// needed for all other archs
cgo = true
}
if strings.HasPrefix(goarch, "armv") {
os.Setenv("GOARCH", "arm")
os.Setenv("GOARM", goarch[4:])
} else {
os.Setenv("GOARCH", goarch)
}
if cgo {
os.Setenv("CGO_ENABLED", "1")
}
if gocc != "" {
os.Setenv("CC", gocc)
}
}
func getGitBranch() string {
v, err := runError("git", "rev-parse", "--abbrev-ref", "HEAD")
if err != nil {
return "main"
}
return string(v)
}
func getGitSha() string {
v, err := runError("git", "rev-parse", "--short", "HEAD")
if err != nil {
return "unknown-dev"
}
return string(v)
}
func buildStamp() int64 {
// use SOURCE_DATE_EPOCH if set.
if s, _ := strconv.ParseInt(os.Getenv("SOURCE_DATE_EPOCH"), 10, 64); s > 0 {
return s
}
bs, err := runError("git", "show", "-s", "--format=%ct")
if err != nil {
return time.Now().Unix()
}
s, _ := strconv.ParseInt(string(bs), 10, 64)
return s
}
func runError(cmd string, args ...string) ([]byte, error) {
ecmd := exec.Command(cmd, args...)
bs, err := ecmd.CombinedOutput()
if err != nil {
return nil, err
}
return bytes.TrimSpace(bs), nil
}
func runPrint(cmd string, args ...string) {
log.Println(cmd, strings.Join(args, " "))
ecmd := exec.Command(cmd, args...)
ecmd.Stdout = os.Stdout
ecmd.Stderr = os.Stderr
err := ecmd.Run()
if err != nil {
log.Fatal(err)
}
}
func md5File(file string) error {
fd, err := os.Open(file)
if err != nil {
return err
}
defer fd.Close()
h := md5.New()
_, err = io.Copy(h, fd)
if err != nil {
return err
}
out, err := os.Create(file + ".md5")
if err != nil {
return err
}
_, err = fmt.Fprintf(out, "%x\n", h.Sum(nil))
if err != nil {
return err
}
return out.Close()
}
func shaFilesInDist() {
filepath.Walk("./dist", func(path string, f os.FileInfo, err error) error {
if path == "./dist" {
return nil
}
if !strings.Contains(path, ".sha256") {
err := shaFile(path)
if err != nil {
log.Printf("Failed to create sha file. error: %v\n", err)
}
}
return nil
})
}
func shaFile(file string) error {
fd, err := os.Open(file)
if err != nil {
return err
}
defer fd.Close()
h := sha256.New()
_, err = io.Copy(h, fd)
if err != nil {
return err
}
out, err := os.Create(file + ".sha256")
if err != nil {
return err
}
_, err = fmt.Fprintf(out, "%x\n", h.Sum(nil))
if err != nil {
return err
}
return out.Close()
}
func shortenBuildId(buildId string) string {
buildId = strings.Replace(buildId, "-", "", -1)
if len(buildId) < 9 {
return buildId
}
return buildId[0:8]
}

View File

@@ -172,12 +172,6 @@ idle_conn_timeout_seconds = 90
# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request.
send_user_header = false
# Limit the amount of bytes that will be read/accepted from responses of outgoing HTTP requests.
response_limit = 0
# Limits the number of rows that Grafana will process from SQL data sources.
row_limit = 1000000
#################################### Analytics ###########################
[analytics]
# Server reporting, sends usage counters to stats.grafana.org every 24 hours.
@@ -208,18 +202,6 @@ rudderstack_write_key =
# Rudderstack data plane url, enabled only if rudderstack_write_key is also set
rudderstack_data_plane_url =
# Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set
rudderstack_sdk_url =
# Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config
rudderstack_config_url =
# Application Insights connection string. Specify an URL string to enable this feature.
application_insights_connection_string =
# Optional. Specifies an Application Insights endpoint URL where the endpoint string is wrapped in backticks ``.
application_insights_endpoint_url =
#################################### Security ############################
[security]
# disable creation of admin user on first start of grafana
@@ -234,12 +216,6 @@ admin_password = admin
# used for signing
secret_key = SW2YcwTIb9zpOOhoPsMm
# current key provider used for envelope encryption, default to static value specified by secret_key
encryption_provider = secretKey
# list of configured key providers, space separated (Enterprise only): e.g., awskms.v1 azurekv.v1
available_encryption_providers =
# disable gravatar profile images
disable_gravatar = false
@@ -522,11 +498,9 @@ role_attribute_path =
role_attribute_strict = false
groups_attribute_path =
id_token_attribute_name =
team_ids_attribute_path =
auth_url =
token_url =
api_url =
teams_url =
allowed_domains =
team_ids =
allowed_organizations =
@@ -534,7 +508,6 @@ tls_skip_verify_insecure = false
tls_client_cert =
tls_client_key =
tls_client_ca =
use_pkce = false
#################################### Basic Auth ##########################
[auth.basic]
@@ -742,67 +715,11 @@ global_session = -1
# global limit of alerts
global_alert_rule = -1
#################################### Unified Alerting ####################
[unified_alerting]
# Enable the Unified Alerting sub-system and interface. When enabled we'll migrate all of your alert rules and notification channels to the new system. New alert rules will be created and your notification channels will be converted into an Alertmanager configuration. Previous data is preserved to enable backwards compatibility but new data is removed when switching. When this configuration section and flag are not defined, the state is defined at runtime. See the documentation for more details.
enabled =
# Comma-separated list of organization IDs for which to disable unified alerting. Only supported if unified alerting is enabled.
disabled_orgs =
# Specify the frequency of polling for admin config changes.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
admin_config_poll_interval = 60s
# Specify the frequency of polling for Alertmanager config changes.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
alertmanager_config_poll_interval = 60s
# Listen address/hostname and port to receive unified alerting messages for other Grafana instances. The port is used for both TCP and UDP. It is assumed other Grafana instances are also running on the same port.
ha_listen_address = "0.0.0.0:9094"
# Explicit address/hostname and port to advertise other Grafana instances. The port is used for both TCP and UDP.
ha_advertise_address = ""
# Comma-separated list of initial instances (in a format of host:port) that will form the HA cluster. Configuring this setting will enable High Availability mode for alerting.
ha_peers = ""
# Time to wait for an instance to send a notification via the Alertmanager. In HA, each Grafana instance will
# be assigned a position (e.g. 0, 1). We then multiply this position with the timeout to indicate how long should
# each instance wait before sending the notification to take into account replication lag.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
ha_peer_timeout = 15s
# The interval between sending gossip messages. By lowering this value (more frequent) gossip messages are propagated
# across cluster more quickly at the expense of increased bandwidth usage.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
ha_gossip_interval = 200ms
# The interval between gossip full state syncs. Setting this interval lower (more frequent) will increase convergence speeds
# across larger clusters at the expense of increased bandwidth usage.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
ha_push_pull_interval = 60s
# Enable or disable alerting rule execution. The alerting UI remains visible. This option has a legacy version in the `[alerting]` section that takes precedence.
execute_alerts = true
# Alert evaluation timeout when fetching data from the datasource. This option has a legacy version in the `[alerting]` section that takes precedence.
# The timeout string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
evaluation_timeout = 30s
# Number of times we'll attempt to evaluate an alert rule before giving up on that evaluation. This option has a legacy version in the `[alerting]` section that takes precedence.
max_attempts = 3
# Minimum interval to enforce between rule evaluations. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time. This option has a legacy version in the `[alerting]` section that takes precedence.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
min_interval = 10s
#################################### Alerting ############################
[alerting]
# Enable the legacy alerting sub-system and interface. If Unified Alerting is already enabled and you try to go back to legacy alerting, all data that is part of Unified Alerting will be deleted. When this configuration section and flag are not defined, the state is defined at runtime. See the documentation for more details.
enabled =
# Makes it possible to turn off alert execution but alerting UI is visible
# Disable alerting engine & UI features
enabled = true
# Makes it possible to turn off alert rule execution but alerting UI is visible
execute_alerts = true
# Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state)
@@ -920,10 +837,6 @@ zipkin_propagation = false
# Not disabling is the most common setting when using Zipkin elsewhere in your infrastructure.
disable_shared_zipkin_spans = false
[tracing.opentelemetry.jaeger]
# jaeger destination (ex http://localhost:14268/api/traces)
address =
#################################### External Image Storage ##############
[external_image_storage]
# Used for uploading images to public servers so they can be included in slack/email messages.
@@ -981,12 +894,10 @@ enable_alpha = false
app_tls_skip_verify_insecure = false
# Enter a comma-separated list of plugin identifiers to identify plugins to load even if they are unsigned. Plugins with modified signatures are never loaded.
allow_loading_unsigned_plugins =
# Enable or disable installing / uninstalling / updating plugins directly from within Grafana.
plugin_admin_enabled = true
# Enable or disable installing plugins directly from within Grafana.
plugin_admin_enabled = false
plugin_admin_external_manage_enabled = false
plugin_catalog_url = https://grafana.com/grafana/plugins/
# Enter a comma-separated list of plugin identifiers to hide in the plugin catalog.
plugin_catalog_hidden_plugins =
#################################### Grafana Live ##########################################
[live]
@@ -1053,14 +964,12 @@ rendering_chrome_bin =
# Mode 'reusable' will have one browser instance and will create a new incognito page on each request.
rendering_mode =
# When rendering_mode = clustered, you can instruct how many browsers or incognito pages can execute concurrently. Default is 'browser'
# When rendering_mode = clustered you can instruct how many browsers or incognito pages can execute concurrently. Default is 'browser'
# and will cluster using browser instances.
# Mode 'context' will cluster using incognito pages.
rendering_clustering_mode =
# When rendering_mode = clustered, you can define the maximum number of browser instances/incognito pages that can execute concurrently. Default is '5'.
# When rendering_mode = clustered you can define maximum number of browser instances/incognito pages that can execute concurrently..
rendering_clustering_max_concurrency =
# When rendering_mode = clustered, you can specify the duration a rendering request can take before it will time out. Default is `30` seconds.
rendering_clustering_timeout =
# Limit the maximum viewport width, height and device scale factor that can be requested.
rendering_viewport_max_width =

View File

@@ -178,12 +178,6 @@
# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false.
;send_user_header = false
# Limit the amount of bytes that will be read/accepted from responses of outgoing HTTP requests.
;response_limit = 0
# Limits the number of rows that Grafana will process from SQL data sources.
;row_limit = 1000000
#################################### Analytics ####################################
[analytics]
# Server reporting, sends usage counters to stats.grafana.org every 24 hours.
@@ -208,18 +202,6 @@
# Google Tag Manager ID, only enabled if you specify an id here
;google_tag_manager_id =
# Rudderstack write key, enabled only if rudderstack_data_plane_url is also set
;rudderstack_write_key =
# Rudderstack data plane url, enabled only if rudderstack_write_key is also set
;rudderstack_data_plane_url =
# Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set
;rudderstack_sdk_url =
# Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config
;rudderstack_config_url =
#################################### Security ####################################
[security]
# disable creation of admin user on first start of grafana
@@ -234,12 +216,6 @@
# used for signing
;secret_key = SW2YcwTIb9zpOOhoPsMm
# current key provider used for envelope encryption, default to static value specified by secret_key
;encryption_provider = secretKey
# list of configured key providers, space separated (Enterprise only): e.g., awskms.v1 azurekv.v1
;available_encryption_providers =
# disable gravatar profile images
;disable_gravatar = false
@@ -507,19 +483,16 @@
;auth_url = https://foo.bar/login/oauth/authorize
;token_url = https://foo.bar/login/oauth/access_token
;api_url = https://foo.bar/user
;teams_url =
;allowed_domains =
;team_ids =
;allowed_organizations =
;role_attribute_path =
;role_attribute_strict = false
;groups_attribute_path =
;team_ids_attribute_path =
;tls_skip_verify_insecure = false
;tls_client_cert =
;tls_client_key =
;tls_client_ca =
;use_pkce = false
#################################### Basic Auth ##########################
[auth.basic]
@@ -725,67 +698,11 @@
# global limit of alerts
;global_alert_rule = -1
#################################### Unified Alerting ####################
[unified_alerting]
#Enable the Unified Alerting sub-system and interface. When enabled we'll migrate all of your alert rules and notification channels to the new system. New alert rules will be created and your notification channels will be converted into an Alertmanager configuration. Previous data is preserved to enable backwards compatibility but new data is removed.```
;enabled = true
# Comma-separated list of organization IDs for which to disable unified alerting. Only supported if unified alerting is enabled.
;disabled_orgs =
# Specify the frequency of polling for admin config changes.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;admin_config_poll_interval = 60s
# Specify the frequency of polling for Alertmanager config changes.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;alertmanager_config_poll_interval = 60s
# Listen address/hostname and port to receive unified alerting messages for other Grafana instances. The port is used for both TCP and UDP. It is assumed other Grafana instances are also running on the same port. The default value is `0.0.0.0:9094`.
;ha_listen_address = "0.0.0.0:9094"
# Listen address/hostname and port to receive unified alerting messages for other Grafana instances. The port is used for both TCP and UDP. It is assumed other Grafana instances are also running on the same port. The default value is `0.0.0.0:9094`.
;ha_advertise_address = ""
# Comma-separated list of initial instances (in a format of host:port) that will form the HA cluster. Configuring this setting will enable High Availability mode for alerting.
;ha_peers = ""
# Time to wait for an instance to send a notification via the Alertmanager. In HA, each Grafana instance will
# be assigned a position (e.g. 0, 1). We then multiply this position with the timeout to indicate how long should
# each instance wait before sending the notification to take into account replication lag.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;ha_peer_timeout = "15s"
# The interval between sending gossip messages. By lowering this value (more frequent) gossip messages are propagated
# across cluster more quickly at the expense of increased bandwidth usage.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;ha_gossip_interval = "200ms"
# The interval between gossip full state syncs. Setting this interval lower (more frequent) will increase convergence speeds
# across larger clusters at the expense of increased bandwidth usage.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;ha_push_pull_interval = "60s"
# Enable or disable alerting rule execution. The alerting UI remains visible. This option has a legacy version in the `[alerting]` section that takes precedence.
;execute_alerts = true
# Alert evaluation timeout when fetching data from the datasource. This option has a legacy version in the `[alerting]` section that takes precedence.
# The timeout string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;evaluation_timeout = 30s
# Number of times we'll attempt to evaluate an alert rule before giving up on that evaluation. This option has a legacy version in the `[alerting]` section that takes precedence.
;max_attempts = 3
# Minimum interval to enforce between rule evaluations. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time. This option has a legacy version in the `[alerting]` section that takes precedence.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;min_interval = 10s
#################################### Alerting ############################
[alerting]
# Disable legacy alerting engine & UI features
;enabled = false
# Makes it possible to turn off alert execution but alerting UI is visible
# Disable alerting engine & UI features
;enabled = true
# Makes it possible to turn off alert rule execution but alerting UI is visible
;execute_alerts = true
# Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state)
@@ -798,6 +715,7 @@
# This limit will protect the server from render overloading and make sure notifications are sent out quickly
;concurrent_render_limit = 5
# Default setting for alert calculation timeout. Default value is 30
;evaluation_timeout_seconds = 30
@@ -903,10 +821,6 @@
# Not disabling is the most common setting when using Zipkin elsewhere in your infrastructure.
;disable_shared_zipkin_spans = false
[tracing.opentelemetry.jaeger]
# jaeger destination (ex http://localhost:14268/api/traces)
; address = http://localhost:14268/api/traces
#################################### External image storage ##########################
[external_image_storage]
# Used for uploading images to public servers so they can be included in slack/email messages.
@@ -960,12 +874,10 @@
;app_tls_skip_verify_insecure = false
# Enter a comma-separated list of plugin identifiers to identify plugins to load even if they are unsigned. Plugins with modified signatures are never loaded.
;allow_loading_unsigned_plugins =
# Enable or disable installing / uninstalling / updating plugins directly from within Grafana.
# Enable or disable installing plugins directly from within Grafana.
;plugin_admin_enabled = false
;plugin_admin_external_manage_enabled = false
;plugin_catalog_url = https://grafana.com/grafana/plugins/
# Enter a comma-separated list of plugin identifiers to hide in the plugin catalog.
;plugin_catalog_hidden_plugins =
#################################### Grafana Live ##########################################
[live]
@@ -1031,14 +943,12 @@
# Mode 'reusable' will have one browser instance and will create a new incognito page on each request.
;rendering_mode =
# When rendering_mode = clustered, you can instruct how many browsers or incognito pages can execute concurrently. Default is 'browser'
# When rendering_mode = clustered you can instruct how many browsers or incognito pages can execute concurrently. Default is 'browser'
# and will cluster using browser instances.
# Mode 'context' will cluster using incognito pages.
;rendering_clustering_mode =
# When rendering_mode = clustered, you can define the maximum number of browser instances/incognito pages that can execute concurrently. Default is '5'.
# When rendering_mode = clustered you can define maximum number of browser instances/incognito pages that can execute concurrently..
;rendering_clustering_max_concurrency =
# When rendering_mode = clustered, you can specify the duration a rendering request can take before it will time out. Default is `30` seconds.
;rendering_clustering_timeout =
# Limit the maximum viewport width, height and device scale factor that can be requested.
;rendering_viewport_max_width =

View File

@@ -6,7 +6,6 @@ This directory contains guides for contributors to the Grafana project.
- [Contributing documentation](documentation.md)
- [Developer guide](developer-guide.md)
- [Triage issues](triage-issues.md)
- [Merge a pull request](merge-pull-request.md)
The `style-guides` directory contains style guides for the Grafana software project and documentation.

View File

@@ -4,10 +4,10 @@ Are you looking to take on contributions with bigger impact? These guides help y
Learn more about the backend architecture:
- Part 1: [Services](backend/services.md)
- Part 1: [Services](backend/services.md)
- Part 2: [Communication](backend/communication.md)
- Part 3: [Database](backend/database.md)
Learn more about the frontend architecture:
- Part 1: [Data requests](frontend-data-requests.md)

View File

@@ -1,12 +1,12 @@
# Package hierarchy
The Go package hierarchy in Grafana should be organized logically (Ben Johnson's
[article](https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1) served as inspiration), according to the
[article](https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1) served as inspiration), according to the
following principles:
- Domain types and interfaces should be in "root" packages (not necessarily at the very top, of the hierarchy, but
* Domain types and interfaces should be in "root" packages (not necessarily at the very top, of the hierarchy, but
logical roots)
- Sub-packages should depend on roots - sub-packages here typically contain implementations, for example of services
* Sub-packages should depend on roots - sub-packages here typically contain implementations, for example of services
## Practical example

View File

@@ -2,136 +2,71 @@
A Grafana _service_ encapsulates and exposes application logic to the rest of the application, through a set of related operations.
Grafana uses [Wire](https://github.com/google/wire), which is a code generation tool that automates connecting components using [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection). Dependencies between components are represented in Wire as function parameters, encouraging explicit initialization instead of global variables.
Before a service can start communicating with the rest of Grafana, it needs to be registered in the _service registry_.
The service registry keeps track of all available services during runtime. On start-up, Grafana uses the registry to build a dependency graph of services, a _service graph_.
Even though the services in Grafana do different things, they share a number of patterns. To better understand how a service works, let's build one from scratch!
Before a service can start communicating with the rest of Grafana, it needs to be registered with Wire, see `ProvideService` factory function/method in the service example below and how it's being referenced in the wire.go example below.
## Create a service
When Wire is run it will inspect the parameters of `ProvideService` and make sure that all it's dependencies has been wired up and initialized properly.
To start building a service:
**Service example:**
- Create a new Go package `mysvc` in the [pkg/services](/pkg/services) directory.
- Create a `service.go` file inside your new directory.
All services need to implement the [Service](https://godoc.org/github.com/grafana/grafana/pkg/registry#Service) interface:
```go
package example
// Service service is the service responsible for X, Y and Z.
type Service struct {
logger log.Logger
cfg *setting.Cfg
sqlStore *sqlstore.SQLStore
type MyService struct {
}
// ProvideService provides Service as dependency for other services.
func ProvideService(cfg *setting.Cfg, sqlStore *sqlstore.SQLStore) (*Service, error) {
s := &Service{
logger: log.New("service"),
cfg: cfg,
sqlStore: sqlStore,
}
if s.IsDisabled() {
// skip certain initialization logic
return s, nil
}
if err := s.init(); err != nil {
return nil, err
}
return s, nil
}
func (s *Service) init() error {
// additional initialization logic...
func (s *MyService) Init() error {
return nil
}
// IsDisabled returns true if the service is disabled.
//
// Satisfies the registry.CanBeDisabled interface which will guarantee
// that Run() is not called if the service is disabled.
func (s *Service) IsDisabled() bool {
return !s.cfg.IsServiceEnabled()
}
// Run runs the service in the background.
//
// Satisfies the registry.BackgroundService interface which will
// guarantee that the service can be registered as a background service.
func (s *Service) Run(ctx context.Context) error {
// background service logic...
<-ctx.Done()
return ctx.Err()
}
```
[wire.go](/pkg/server/wire.go)
The `Init` method is used to initialize and configure the service to make it ready to use. Services that return an error halt Grafana's startup process and cause the error to be logged as it exits.
## Register a service
Every service needs to be registered with the application for it to be included in the service graph.
To register a service, call the `registry.RegisterService` function in an `init` function within your package.
```go
// +build wireinject
package server
import (
"github.com/google/wire"
"github.com/grafana/grafana/pkg/example"
"github.com/grafana/grafana/pkg/services/sqlstore"
)
var wireBasicSet = wire.NewSet(
example.ProvideService,
)
var wireSet = wire.NewSet(
wireBasicSet,
sqlstore.ProvideService,
)
var wireTestSet = wire.NewSet(
wireBasicSet,
)
func Initialize(cla setting.CommandLineArgs, opts Options, apiOpts api.ServerOptions) (*Server, error) {
wire.Build(wireExtsSet)
return &Server{}, nil
func init() {
registry.RegisterService(&MyService{})
}
func InitializeForTest(cla setting.CommandLineArgs, opts Options, apiOpts api.ServerOptions, sqlStore *sqlstore.SQLStore) (*Server, error) {
wire.Build(wireExtsTestSet)
return &Server{}, nil
}
```
## Background services
`init` functions are only run whenever a package is imported, so we also need to import the package in the application. In the `server.go` file under `pkg/server`, import the package we just created:
A background service is a service that runs in the background of the lifecycle between Grafana starts up and shutdown. If you want a service to be run in the background your Service should satisfy the `registry.BackgroundService` interface and add it as argument to the [ProvideBackgroundServiceRegistry](/pkg/server/backgroundsvcs/background_services.go) function and add it as argument to `NewBackgroundServiceRegistry` to register it as a background service.
```go
import _ "github.com/grafana/grafana/pkg/services/mysvc"
```
You can see an example implementation above of the Run method.
## Dependencies
## Disabled services
Grafana uses the [inject](https://github.com/facebookgo/inject) package to inject dependencies during runtime.
If you want to guarantee that a background service is not run by Grafana when certain criteria is met/service is disabled your service should satisfy the `registry.CanBeDisabled` interface. When the service.IsDisabled method return false Grafana would not call the service.Run method.
For example, to access the [bus](communication.md), add it to the `MyService` struct:
If you want to run certain initialization code if service is disabled or not, you need to handle this in the service factory method.
```go
type MyService struct {
Bus bus.Bus `inject:""`
}
```
You can see an example implementation above of the IsDisabled method and custom initialization code when service is disabled.
You can also inject other services in the same way:
## Run Wire / generate code
```go
type MyService struct {
Service other.Service `inject:""`
}
```
When running `make run` it will call `make gen-go` on the first run. `gen-go` in turn will call the wire binary and generate the code in [wire_gen.go](/pkg/server/wire_gen.go) and [wire_gen.go](/pkg/cmd/grafana-cli/runner/wire_gen.go). The wire binary is installed using [bingo](https://github.com/bwplotka/bingo) which will make sure to download and install all the tools needed, including the Wire binary at using a specific version.
## OSS vs Enterprise
Grafana OSS and Grafana Enterprise shares code and dependencies. Grafana Enterprise might need to override/extend certain OSS services.
There's a [wireexts_oss.go](/pkg/server/wireexts_oss.go) that has the `wireinject` and `oss` build tags as requirements. Here services that might have other implementations, e.g. Grafana Enterprise, can be registered.
Similarly, there's a wireexts_enterprise.go file in the Enterprise source code repository where other service implementations can be overridden/be registered.
To extend oss background service create a specific background interface for that type and inject that type to [ProvideBackgroundServiceRegistry](/pkg/server/backgroundsvcs/background_services.go) instead of the concrete type. Then add a wire binding for that interface in [wireexts_oss.go](/pkg/server/wireexts_oss.go) and in the enterprise wireexts file.
> **Note:** Any injected dependency needs to be an exported field. Any unexported fields result in a runtime error.
## Methods

View File

@@ -3,7 +3,6 @@
[BackendSrv](https://grafana.com/docs/grafana/latest/packages_api/runtime/backendsrv) handles all outgoing HTTP requests from Grafana. This document explains the high-level concepts used by `BackendSrv`.
## Canceling requests
This section describes how canceling requests work in Grafana. While data sources can implement their own cancellation concept, we recommend that you use the method we describe here.
A data request can take a long time to finish. During the time between when a request starts and finishes, the user can change context. For example, the user may navigate away or issue the same request again.
@@ -13,35 +12,29 @@ If we wait for canceled requests to complete, it might create unnecessary load o
Grafana uses a concept called _request cancelation_ to cancel any ongoing request that Grafana doesn't need.
#### Before Grafana 7.2
Before Grafana can cancel any data request, it has to identify that request. Grafana identifies a request using the property `requestId` [passed as options](https://github.com/grafana/grafana/blob/main/docs/sources/packages_api/runtime/backendsrvrequest.md) when you use [BackendSrv](https://grafana.com/docs/grafana/latest/packages_api/runtime/backendsrv).
The cancellation logic is as follows:
- When an ongoing request discovers that an additional request with the same `requestId` has started, then Grafana will cancel the ongoing request.
- When an ongoing request discovers that the special "cancel all requests" `requestId` was sent, then Grafana will cancel the ongoing request.
#### After Grafana 7.2
Grafana 7.2 introduced an additional way of canceling requests using [RxJs](https://github.com/ReactiveX/rxjs). To support the new cancellation functionality, the data source needs to use the new `fetch` function in [BackendSrv](https://grafana.com/docs/grafana/latest/packages_api/runtime/backendsrv).
Migrating the core data sources to the new `fetch` function [is an ongoing process that you can read about in this issue.](https://github.com/grafana/grafana/issues/27222)
## Request queue
Depending on how the web browser implements the protocol for HTTP 1.1, it will limit the number of parallel requests, lets call this limit _max_parallel_browser_request_.
Depending on how the web browser implements the protocol for HTTP 1.1, it will limit the number of parallel requests, lets call this limit _max_parallel_browser_request_.
Unless you have configured Grafana to use HTTP2, the browser limits parallel data requests according to the browser's implementation. For more information on how to enable HTTP2, refer to [Configuration](https://grafana.com/docs/grafana/latest/administration/configuration/#protocol).
Because there is a _max_parallel_browser_request_ limit, if some of the requests take a long time, they will block later requests and make interacting with Grafana very slow.
#### Before Grafana 7.2
Not supported.
Not supported.
#### After Grafana 7.2
Grafana uses a _request queue_ to process all incoming data requests in order while reserving a free "spot" for any requests to the Grafana API.
Grafana uses a _request queue_ to process all incoming data requests in order while reserving a free "spot" for any requests to the Grafana API.
Since the first implementation of the request queue doesn't take into account what browser the user uses, the _request queue_ limit for parallel data source requests is hard-coded to 5.

View File

@@ -55,17 +55,6 @@ Pull requests that create new UI components or modify existing ones must adhere
- Use the [Grafana theme palette](/contribute/style-guides/themes.md) for styling. It contains colors with good contrast which aids accessibility.
- Use [RTL](https://testing-library.com/docs/dom-testing-library/api-accessibility/) for writing unit tests. It helps to create accessible components.
Pull requests that introduce accessibility(a11y) errors:
We use [pa11y-ci](https://github.com/pa11y/pa11y-ci) to collect accessibility errors on [some URLs on the project](https://github.com/grafana/grafana/issues/36555), threshold errors are specified per URL.
If the contribution introduces new a11y errors, our continuous integration will fail, preventing you to merge on the main branch. In those cases there are two alternatives for moving forward:
- Check the error log on the pipeline step `test-a11y-frontend-pr`, identify what was the error, and fix it.
- Locally run the command `yarn test:accessibility-report` that generates an HTML accessibility report, then go to the URL that contains your change, identify the error, and fix it. Keep in mind, a local e2e Grafana instance is going to be running on `http://localhost:3001`.
You can also prevent introducing a11y errors by installing an a11y plugin in your browser, for example, axe DevTools, Accessibility Insights for Web among others.
### Backend-specific guidelines
Please refer to the [backend style guidelines](/contribute/style-guides/backend.md).
@@ -95,25 +84,23 @@ The area should use upper camel case, e.g. UpperCamelCase.
Prefer using one of the following areas:
- **Build:** Change the build system, or external dependencies
- **Chore:** Change that don't affect functionality
- **Dashboard:** Change the Dashboard feature
- **Docs:** Change documentation
- **Explore:** Change the Explore feature
- **Plugins:** Change the ... plugin
- **Build:** Changes to the build system, or external dependencies.
- **Chore:** Changes that don't affect functionality.
- **Dashboard:** Changes to the Dashboard feature.
- **Docs:** Changes to documentation.
- **Explore:** Changes to the Explore feature.
- **Plugins:** Changes to any of the plugins.
For changes to data sources, the area is the name of the data source. For example, AzureMonitor, Graphite, or Prometheus.
For changes to data sources, the area should be the name of the data source, e.g., AzureMonitor, Graphite, and Prometheus.
For changes to panels, the area is the name of the panel, suffixed with Panel. For example, GraphPanel, SinglestatPanel, or TablePanel.
For changes to panels, the area should be the name of the panel, suffixed with Panel, e.g., GraphPanel, SinglestatPanel, and TablePanel.
**Examples**
- `Build: Support publishing MSI to grafana.com`
- `Explore: Add Live option for supported data sources`
- `GraphPanel: Fix legend sorting issues`
- `Docs: Change url to URL in all documentation files`
If you're unsure, see the existing [changelog](https://github.com/grafana/grafana/blob/main/CHANGELOG.md) for inspiration or guidance.
- `Docs: Changed url to URL in all documentation files`
### Pull request titles

View File

@@ -10,8 +10,14 @@ Make sure you have the following dependencies installed before setting up your d
- [Git](https://git-scm.com/)
- [Go](https://golang.org/dl/) (see [go.mod](../go.mod#L3) for minimum required version)
- [Node.js (Long Term Support)](https://nodejs.org)
- [Yarn](https://yarnpkg.com)
Additionally you'll need:
- [Node.js](https://nodejs.org) (see `volta.node` property in [package.json](../package.json) for the correct version).
- [Yarn](https://yarnpkg.com) (see `volta.yarn` property in [package.json](../package.json) for the correct version).
We recommend using [Volta](https://github.com/volta-cli/volta) to manage your JS toolchain.
Refer to the [Volta Getting Started Guide](https://docs.volta.sh/guide/getting-started) for setup instructions for your operating system.
### macOS
@@ -20,8 +26,6 @@ We recommend using [Homebrew](https://brew.sh/) for installing any missing depen
```
brew install git
brew install go
brew install node@16
npm install -g yarn
```
### Windows
@@ -48,7 +52,7 @@ Grafana consists of two components; the _frontend_, and the _backend_.
Before we can build the frontend assets, we need to install the dependencies:
```
yarn install --immutable
yarn install --pure-lockfile
```
After the command has finished, we can start building our source code:
@@ -81,23 +85,7 @@ When you log in for the first time, Grafana asks you to change your password.
The Grafana backend includes SQLite which requires GCC to compile. So in order to compile Grafana on Windows you need to install GCC. We recommend [TDM-GCC](http://tdm-gcc.tdragon.net/download). Eventually, if you use [Scoop](https://scoop.sh), you can install GCC through that.
You can build the back-end as follows:
1. Follow the [instructions](https://github.com/google/wire#installing) to install the Wire tool.
2. Generate code using Wire:
```
# Normally Wire tool installed at $GOPATH/bin/wire.exe
<Wire tool install path> gen -tags oss ./pkg/server ./pkg/cmd/grafana-cli/runner
```
3. Build the Grafana binaries:
```
go run build.go build
```
The Grafana binaries will be in bin\\windows-amd64.
You can simply build the back-end as follows: `go run build.go build`. The Grafana binaries will be in bin\\windows-amd64.
Alternately, if you wish to use the `make` command, install [Make for Windows](http://gnuwin32.sourceforge.net/packages/make.htm) and use it in a Unix shell (f.ex. Git Bash).
## Test Grafana
@@ -204,6 +192,11 @@ make build-docker-full
The resulting image will be tagged as grafana/grafana:dev.
> **Note:** If you've already set up a local development environment, and you're running a `linux/amd64` machine, you can speed up building the Docker image:
1. Build the frontend: `go run build.go build-frontend`.
1. Build the Docker image: `make build-docker-dev`.
**Note:** If you are using Docker for macOS, be sure to set the memory limit to be larger than 2 GiB. Otherwise, `grunt build` may fail. The memory limit settings are available under **Docker Desktop** -> **Preferences** -> **Advanced**.
## Troubleshooting
@@ -223,7 +216,7 @@ ulimit -a
To change the number of open files allowed, run:
```
ulimit -S -n 4096
ulimit -S -n 2048
```
The number of files needed may be different on your environment. To determine the number of open files needed by `make run`, run:

View File

@@ -17,6 +17,6 @@ mage protobuf
After upgrading the protobuf dependency in Grafana and the plugin SDK, it might be wise to test that things still work,
before making corresponding PRs:
- Test a plugin built with upgraded SDK on upgraded Grafana
- Test a plugin built with non-upgraded SDK on upgraded Grafana
- Test a plugin built with upgraded SDK on non-upgraded Grafana
* Test a plugin built with upgraded SDK on upgraded Grafana
* Test a plugin built with non-upgraded SDK on upgraded Grafana
* Test a plugin built with upgraded SDK on non-upgraded Grafana

View File

@@ -6,12 +6,12 @@ This document defines technical terms used in Grafana.
## TLS/SSL
The acronyms [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security) (Transport Layer Security and
The acronyms [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security) (Transport Layer Security and
[SSL](https://en.wikipedia.org/wiki/SSL) (Secure Socket Layer) are both used to describe the HTTPS security layer,
and are in practice synonymous. However, TLS is considered the current name for the technology, and SSL is considered
[deprecated](https://tools.ietf.org/html/rfc7568).
[deprecated](https://tools.ietf.org/html/rfc7568).
As such, while both terms are in use (also in our codebase) and are indeed interchangeable, TLS is the preferred term.
That said however, we have at Grafana Labs decided to use both acronyms in combination when referring to this type of
As such, while both terms are in use (also in our codebase) and are indeed interchangeable, TLS is the preferred term.
That said however, we have at Grafana Labs decided to use both acronyms in combination when referring to this type of
technology, i.e. _TLS/SSL_. This is in order to not confuse those who may not be aware of them being synonymous,
and SSL still being so prevalent in common discourse.

View File

@@ -1,118 +0,0 @@
# Merge a pull request
When a pull request has been reviewed and approved by at least one person and all checks have passed it's time to merge the pull request.
## Who is expected to merge a pull request?
Maintainers are responsible for merging all pull requests. If a maintainer has opened a pull request the general rule is that the same maintainer merges the pull request. If a non-maintainer has opened a pull request it's suggested that one of the maintainers reviewing the pull request merges the pull request.
## Checklist/summary
The following checklist/summary should give you a quick overview of what to ask/consider before merging a pull request.
- Reviewed and approved?
- All checks passed?
- Proper pull request title?
- Milestone assigned?
- Add to changelog/release notes?
- Needs backporting?
## Before merge
Before actually merging a pull request there's a couple of things to take into consideration.
### Format the pull request title
Make sure that the pull request title is properly formatted according to `<Area>: <Summary>` and try to make the summary short and understandable for the community as a whole.
All commits in a pull request are squashed when merged and the pull request title will be the default subject line of the squashed commit message. It's also used for [changelog/release notes](#include-in-changelog-and-release-notes).
See [formatting guidelines](create-pull-request.md#formatting-guidelines) for more information.
### Assign a milestone
It's recommended to add a milestone to every pull request. This makes it easier to track what changes did go into a certain release. Without this you're basically left with going through git commits which could be a lot harder.
There's also various tooling built that in some cases requires a pull request to be assigned a milestone, for example [generating changelog/release notes](#include-in-changelog-and-release-notes).
### Include in changelog and release notes?
At Grafana we generate the [changelog](https://github.com/grafana/grafana/blob/main/CHANGELOG.md) and [release notes](https://grafana.com/docs/grafana/latest/release-notes/) based on merged pull requests. Including changes in the changelog/release notes is very important to provide a somewhat complete picture of what changes a Grafana release actually includes.
Exactly what changes should be added to the changelog is hard to answer but some general guidance would be any change that you think would be interesting for the community as a whole. Use your best judgement and/or ask other maintainers for advice.
There's a GitHub action available in the repository named [Update changelog](https://github.com/grafana/grafana/blob/main/.github/workflows/update-changelog.yml) that can manually be triggered to re-generate the changelog and release notes for any release.
To include a pull request in the changelog/release notes the general rule of thumb is that a milestone should be assigned and labeled with `add to changelog`.
The changelog/release notes are divided into sections and here's a description of how you make a pull request show up in a certain section.
**Features and enhancements:**
Milestone assigned and labeled with `add to changelog` and any of the other section rules don't apply.
**Bug fixes:**
Milestone assigned and labeled with `add to changelog` and either labeled with `type/bug` or the pull request title contains `fix` or `fixes`.
**Plugin development fixes & changes:**
Milestone assigned and labeled with `area/grafana/toolkit`, `area/grafana/ui` or `area/grafana/runtime`.
**Deprecations:**
In case the pull request introduces a deprecation you should document this. Label the pull request with `add to changelog` and use the following template at the end of the pull request description describing the deprecation change.
```md
# Deprecation notice
<Deprecation description>
```
**Breaking changes:**
In case the pull request introduces a breaking change you should document this. Label the pull request with `add to changelog` and `breaking change` and use the following template at the end of the pull request description describing the breaking change.
```md
# Release notice breaking change
<Breaking change description>
```
### Should the pull request be backported?
If your pull request has changes that need to go into one or several existing release branches you need to backport the changes. Please refer to [Backport PR](.github/bot.md#backport-pr) for detailed instructions.
Some examples when backport is required:
- The change needs to be released in the next upcoming patch release, e.g. v8.1.3, so you have to backport it, e.g. into the v8.1.x release branch.
- You have a change to be released in the next major/minor release, e.g. v8.0.0, and there's already a release branch, e.g. v8.0.x, you have to backport it, e.g. into the v8.0.x release branch.
- The change includes documentation changes that needs to be updated for one or multiple older versions, then you have to backport it to each release branch.
Some examples when backport is not required:
- The change is supposed to be released in the next major/minor release, e.g. v8.0.0, but the release branch, e.g. v8.0.x, has not yet been created.
> **Note:** You can still backport a pull request after it's been merged.
## Doing the actual merge
Time to actually merge the pull request changes. All commits in a pull request are squashed, hence the GitHub `Squash and merge` button is used to initialize the merge.
This will present you with options allowing you to optionally change the commit message before merging. Please remember that developers might use the commit information when reviewing changes of files, doing git blame and resolving merge conflicts etc., trying to quickly figure out what the actual change was. But there's not really any best practices around this, the following is an attempt to bring some guidance.
Do:
- Make sure the pull request title is formatted properly before merging, this will automatically give you a good and short summary of the commit/change.
- Leave `Co-authored-by:` lines as is so that co-authors will be accounted for the contribution.
- Remove any commit information that doesn't bring any context to the change.
Consider:
- Add any references to issues that the pull request fixes/closes/references to ease giving quick context to things. Doing this allows cross-reference between the commit and referenced issue(s).
Finalize the merge by clicking on the `Confirm squash and merge` button.
## After the merge
Make sure to close any referenced/related issues. It's recommended to assign the same milestone on the issues that the pull request fixes/closes, but not required.

View File

@@ -42,8 +42,8 @@ In the `sqlstore` package we do database operations in tests and while some migh
### Assertions
Use respectively [`assert.*`](https://github.com/stretchr/testify#assert-package) functions to make assertions that
should _not_ halt the test ("soft checks") and [`require.*`](https://github.com/stretchr/testify#require-package)
Use respectively [`assert.*`](https://github.com/stretchr/testify#assert-package) functions to make assertions that
should _not_ halt the test ("soft checks") and [`require.*`](https://github.com/stretchr/testify#require-package)
functions to make assertions that _should_ halt the test ("hard checks"). Typically you want to use the latter type of
check to assert that errors have or have not happened, since continuing the test after such an assertion fails is
chaotic (the system under test will be in an undefined state) and you'll often have segfaults in practice.
@@ -70,10 +70,10 @@ In general, use value types and only reach for pointers when there's a real need
increase the risk of bugs, since a pointer can be nil and dereferencing a nil pointer leads to a panic (AKA segfault).
Valid reasons to use a pointer include (but not necessarily limited to):
- You might need to pass a modifiable argument to a function
- Copying an object might incur a performance hit (benchmark to check your assumptions, copying is often faster than
* You might need to pass a modifiable argument to a function
* Copying an object might incur a performance hit (benchmark to check your assumptions, copying is often faster than
allocating heap memory)
- You might _need_ `nil` to tell if a variable isn't set, although usually it's better to use the type's zero
* You might *need* `nil` to tell if a variable isn't set, although usually it's better to use the type's zero
value to tell instead
## Database
@@ -83,7 +83,7 @@ In database related code, we follow certain patterns.
### Foreign keys
While they can be useful, we don't generally use foreign key constraints in Grafana, for historical and
technical reasons. See this [comment](https://github.com/grafana/grafana/issues/3269#issuecomment-383328548) by Torkel
technical reasons. See this [comment](https://github.com/grafana/grafana/issues/3269#issuecomment-383328548) by Torkel
for context.
### Unique columns
@@ -93,7 +93,7 @@ If a column, or column combination, should be unique, add a corresponding unique
## JSON
The simplejson package is used a lot throughout the backend codebase, but it's legacy, so if at all possible
avoid using it in new code. Use [json-iterator](https://github.com/json-iterator/go) instead, which is a more performant
avoid using it in new code. Use [json-iterator](https://github.com/json-iterator/go) instead, which is a more performant
drop-in alternative to the standard [encoding/json](https://golang.org/pkg/encoding/json/) package. While encoding/json
is a fine choice, profiling shows that json-iterator may be 3-4 times more efficient for encoding. We haven't profiled
its parsing performance yet, but according to json-iterator's own benchmarks, it appears even more superior in this

View File

@@ -1,4 +1,4 @@
# Guidelines for code comments in grafana-\* packages
# Guidelines for code comments in grafana-* packages
This document aims to give you some recommendation on how to add code comments to the exported code in the grafana packages.
@@ -9,12 +9,11 @@ This document aims to give you some recommendation on how to add code comments t
1. [Deprecate an API](#deprecate-an-api)
1. [Specify parameters](#specify-parameters)
1. [Set return values](#set-return-values)
____
---
## Add package description
## Add package description
Each package has an overview explaining the overall responsibility and usage of the package.
Each package has an overview explaining the overall responsibility and usage of the package.
You can document this description with [`@packageDocumentation`](https://api-extractor.com/pages/tsdoc/tag_packagedocumentation/) tag.
@@ -33,34 +32,33 @@ All `exported` apis from the package should have a release tag to indicate its s
Add a tag to mark the stability of the whole exported `class/interface/function/type` etc.
Please place the `release tag` at the bottom of the comment to make it consistent among files and easier to read.
Please place the `release tag` at the bottom of the comment to make it consistent among files and easier to read.
**Do:**
````typescript
```typescript
/**
* Will help to create DataFrame objects and handle
* Will help to create DataFrame objects and handle
* the heavy lifting of creating a complex object.
*
*
* @example
* ```typescript
* const dataFrame = factory.create();
* ```
*
*
* @public
**/
export class DataFrameFactory {
create(): DataFrame {}
create(): DataFrame { }
}
````
```
**Don't**
````typescript
```typescript
/**
* Will help to create DataFrame objects and handle
* Will help to create DataFrame objects and handle
* the heavy lifting of creating a complex object.
*
*
* @public
* @example
* ```typescript
@@ -68,9 +66,9 @@ export class DataFrameFactory {
* ```
**/
export class DataFrameFactory {
create(): DataFrame {}
create(): DataFrame { }
}
````
```
### Partial stability of APIs
@@ -80,61 +78,59 @@ Then override the non-stable parts of the API with the proper [release tag](#rel
**Do:**
````typescript
```typescript
/**
* Will help to create DataFrame objects and handle
* Will help to create DataFrame objects and handle
* the heavy lifting of creating a complex object.
*
*
* @example
* ```typescript
* const dataFrame = factory.create();
* ```
*
*
* @public
**/
export class DataFrameFactory {
create(): DataFrame {}
create(): DataFrame { }
/**
* @beta
**/
createMany(): DataFrames[] {}
/**
* @beta
**/
createMany(): DataFrames[] {}
}
````
```
**Don't**
````typescript
```typescript
/**
* Will help to create DataFrame objects and handle
* Will help to create DataFrame objects and handle
* the heavy lifting of creating a complex object.
*
*
* @example
* ```typescript
* const dataFrame = factory.create();
* ```
**/
export class DataFrameFactory {
/**
* @public
**/
create(): DataFrame {}
/**
* @public
**/
create(): DataFrame { }
/**
* @beta
**/
createMany(): DataFrame[] {}
/**
* @beta
**/
createMany(): DataFrame[] {}
}
````
```
## Deprecate an API
If you want to mark an API as deprecated to signal that this API will be removed in the future, then add the [`@deprecated`](https://api-extractor.com/pages/tsdoc/tag_deprecated/) tag.
If applicable add a reason why the API is deprecated directly after the `@deprecated tag`.
## Specify parameters
If you want to specify the possible parameters that can be passed to an API, then add the [`@param`](https://api-extractor.com/pages/tsdoc/tag_param/) tag.
This attribute can be skipped if the type provided by `typescript` and the function comment or the function name is enough to explain what the parameters are.
@@ -145,17 +141,17 @@ This attribute can be skipped if the type provided by `typescript` and the funct
/**
* Will help to create a resource resolver depending
* on the current execution context.
*
*
* @param context - The current execution context.
* @returns FileResolver if executed on the server otherwise a HttpResolver.
* @public
**/
export const factory = (context: Context): IResolver => {
if (context.isServer) {
return new FileResolver();
}
return new HttpResolver();
};
if (context.isServer) {
return new FileResolver();
}
return new HttpResolver();
}
```
**Don't**
@@ -163,18 +159,18 @@ export const factory = (context: Context): IResolver => {
```typescript
/**
* Will compare two numbers to see if they are equal to each others.
*
*
* @param x - The first number
* @param y - The second number
* @public
**/
export const isEqual = (x: number, y: number): boolean => {
return x === y;
};
return x === y;
}
```
## Set return values
## Set return values
If you want to specify the return value from a function you can use the [`@returns`](https://api-extractor.com/pages/tsdoc/tag_returns/) tag.
This attribute can be skipped if the type provided by `typescript` and the function comment or the function name is enough to explain what the function returns.
@@ -185,17 +181,17 @@ This attribute can be skipped if the type provided by `typescript` and the funct
/**
* Will help to create a resource resolver depending
* on the current execution context.
*
*
* @param context - The current execution context.
* @returns FileResolver if executed on the server otherwise a HttpResolver.
* @public
**/
export const factory = (context: Context): IResolver => {
if (context.isServer) {
return new FileResolver();
}
return new HttpResolver();
};
if (context.isServer) {
return new FileResolver();
}
return new HttpResolver();
}
```
**Don't**
@@ -203,11 +199,11 @@ export const factory = (context: Context): IResolver => {
```typescript
/**
* Will compare two numbers to see if they are equal to each others.
*
*
* @returns true if values are equal
* @public
**/
export const isEqual = (x: number, y: number): boolean => {
return x === y;
};
return x === y;
}
```

View File

@@ -12,18 +12,19 @@ In Markdown, the number of "#" symbols creates different heading levels, similar
- \#\# is \<h2>.
- \#\#\# is \<h3>.
Start your document with a single `#` for the title of the page. Add the sub-headings with two `##`.
Start your document with a single ``#`` for the title of the page. Add the sub-headings with two ``##``.
## Bold and emphasis
- Make text **bold** using two asterisks.
**Example:** It is `**important**` to use GitHub-flavored Markdown emoji consistently.
**Example:** It is ``**important**`` to use GitHub-flavored Markdown emoji consistently.
- Make text `_emphasized_` using single ` _underscores_`. Do not use the single asterisk, it can be easily confused with bold.
- Make text ``_emphasized_`` using single `` _underscores_``. Do not use the single asterisk, it can be easily confused with bold.
**Example:** GitHub-flavored markdown emoji should _only_ appear in specific cases.
## Links and references
Create links to other website by wrapping the display text in square brackets, and the web URL in curved brackets.
@@ -61,13 +62,12 @@ Write the name of the language after the first set of back tics, no spaces, to s
```javascript
function testNum(a) {
if (a > 0) {
return 'positive';
return "positive";
} else {
return 'NOT positive';
return "NOT positive";
}
}
```
## Tables
Construct a table by typing the table headings, and separating them with a "|" character. Then, add a second line of dashes ("-") separated by another "|" character. When constructing the table cells, separate each cell data with another "|".
@@ -82,9 +82,9 @@ Cell one data| Cell two data
Will publish as:
| Heading one | Heading two |
| ------------- | ------------- |
| Cell one data | Cell two data |
Heading one | Heading two
------------|------------
Cell one data| Cell two data
## Lists
@@ -121,20 +121,19 @@ _Do not_ use image shortcodes at this time.
Include images in a document using the following syntax:
```
![Alt text](link to image, starting with /static/img/docs/ if it is to an internal image "Title of image in sentence case")
![Alt text](link to image, starting with /img/docs/ if it is to an internal image "Title of image in sentence case")
```
> **Note:** Alt text does not appear when the user hovers the mouse over the image, but title text does.
**Examples:**
**Examples:**
- \!\[Grafana logo](/link/to/grafanalogo/logo.png "Grafana logo")
- \!\[Example](/static/img/docs/folder_name/alert_test_rule.png "Example title")
- \!\[Grafana logo](/link/to/grafanalogo/logo.png)
- \!\[Example](/img/docs/folder_name/alert_test_rule.png)
This follows the format of "!", alt text wrapped in "[]" and the link URL wrapped in "()".
You can also use HTML such as the following:
```
<img src="example.png"
alt="Example image"

View File

@@ -4,13 +4,13 @@ This style guide applies to all documentation created for Grafana products.
For information about how to write technical documentation, refer to the following resources:
- [Google Technical Writing courses](https://developers.google.com/tech-writing)
- [Divio documentation system](https://documentation.divio.com/)
- [Vue writing principles](https://v3.vuejs.org/guide/contributing/writing-guide.html#principles)
* [Google Technical Writing courses](https://developers.google.com/tech-writing)
* [Divio documentation system](https://documentation.divio.com/)
* [Vue writing principles](https://v3.vuejs.org/guide/contributing/writing-guide.html#principles)
## Contributing
The _Documentation style guide_ is a living document. Add to it whenever a style decision is made or a question is answered regarding style, grammar, or word choice.
The *Documentation style guide* is a living document. Add to it whenever a style decision is made or a question is answered regarding style, grammar, or word choice.
## Published guides
@@ -46,14 +46,10 @@ Avoid _master_ or _slave_.
## Grafana-specific style
The following guidelines are specific to Grafana documentation. For the most part, these are _guidelines_ are not rigid rules. If you have questions, then please ask in the #docs channel of Grafana Slack.
The following guidelines are specific to Grafana documentation. For the most part, these are *guidelines* are not rigid rules. If you have questions, then please ask in the #docs channel of Grafana Slack.
### General
Per the [Voice and tone](https://developers.google.com/style/tone) section of the Google developer documentation style guide:
> In your documents, aim for a voice and tone that's conversational, friendly, and respectful without being overly colloquial or frivolous; a voice that's casual and natural and approachable, not pedantic or pushy. Try to sound like a knowledgeable friend who understands what the developer wants to do.
- Use active voice:
- Active: Grafana displays the heatmap visualization.
- Passive: The heatmap visualization is displayed.
@@ -108,7 +104,6 @@ However, sometimes we need to use headings as numbered steps. This is mostly in
If that is the case, then use the following format for headings:
##### Step 1. Install the software
##### Step 2. Run the software
### Images
@@ -154,7 +149,6 @@ In general, "integration" is not capitalized. Only capitalize it if it is capita
The first letter of the name of an integration is always capitalized, even if the original named source is lowercase.
**Examples:**
- MySQL Integration
- CockroachDB Integration
- Etcd Integration
@@ -218,20 +212,16 @@ Warnings tell the user not to do something. For example:
- Do not assume everyone is using Linux. Make sure instructions include enough information for Windows and Mac users to successfully complete procedures.
- Do not add `$` before commands. Make it easy for users to copy and paste commands.
- **Right:** `sudo yum install grafana`
- **Wrong:** `$ sudo yum install grafana`
- Include `sudo` before commands that require `sudo` to work.
For terminal examples and Grafana configuration, use a `bash` code block:
```bash
sudo yum install grafana
```
For HTTP request/response, use an `http` code block:
```http
GET /api/dashboards/id/1/permissions HTTP/1.1
Accept: application/json
@@ -269,7 +259,6 @@ Two words if used as a verb, one word if used as a noun.
Two words, not one.
**Exceptions:**
- "datasource" used as an identifier
- "datasource" in a URL
- Use "data source" instead of "datasource" unless used as an identifier, in code, or as part of a URL.
@@ -278,8 +267,7 @@ Two words, not one.
#### display (verb)
_Display_ is a transitive verb, which means it always needs a direct object.
*Display* is a transitive verb, which means it always needs a direct object.
- Correct, active voice: Grafana displays your list of active alarms.
- Correct, but passive voice: Your list of active alarms is displayed.
- Incorrect: The list of active alarms displays.
@@ -339,7 +327,6 @@ Two words, not one.
**Incorrect:** webserver
### MS SQL Server
Always use "MS SQL" when referring to MS SQL Server application.
Incorrect UI spellings will be corrected in a later version of Grafana.

View File

@@ -22,4 +22,4 @@ The above commands use some utils scripts under [_\<repo-root>/e2e_](../../e2e)
## Test suites
All the integration tests are located at _\<repo-root>/e2e/suite\<x>/specs_. The page objects and reusable flows are in the [_\<repo-root>/packages/grafana-e2e_](../../packages/grafana-e2e) package.
All the integration tests are located at _\<repo-root>/e2e/suite\<x>/specs_. The page objects and reusable flows are in the [_\<repo-root>/packages/grafana-e2e_](../../packages/grafana-e2e) package.

View File

@@ -23,13 +23,20 @@ Inspired by https://martinfowler.com/bliki/PageObject.html
Let's start with a simple [JSX](https://reactjs.org/docs/introducing-jsx.html) example containing a single input field that we want to populate during our E2E test:
```jsx
<input className="gf-form-input login-form-input" type="text" />
<input
className="gf-form-input login-form-input"
type="text"
/>
```
We _could_ target the field with a CSS selector like `.gf-form-input.login-form-input` but that would be brittle as style changes occur frequently. Furthermore there is nothing that signals to future developers that this input is part of an E2E test. At Grafana, we use `aria-label` attributes as our preferred way of defining selectors instead of [`data-*`](https://mdn.io/docs/Web/HTML/Global_attributes/data-*) as they also aid in [accessibility](https://mdn.io/docs/Learn/Accessibility/What_is_accessibility):
```jsx
<input aria-label="Username input field" className="gf-form-input login-form-input" type="text" />
<input
aria-label="Username input field"
className="gf-form-input login-form-input"
type="text"
/>
```
The next step is to create a `Page` representation in our E2E framework to glue the test with the real implementation using the `pageFactory` function. For that function we can supply a `url` and `selectors` like in the example below:
@@ -38,6 +45,7 @@ The next step is to create a `Page` representation in our E2E framework to glue
export const Login = {
// Called via `Login.visit()`
url: '/login',
// Called via `Login.username()`
username: 'Username input field',
};
@@ -59,7 +67,11 @@ Now that we have a `Page` called `Login` in our `Pages` const we can use that to
```jsx
import { selectors } from '@grafana/e2e-selectors';
<input aria-label={selectors.pages.Login.username} className="gf-form-input login-form-input" type="text" />;
<input
aria-label={selectors.pages.Login.username}
className="gf-form-input login-form-input"
type="text"
/>
```
The last step in our example is to use our `Login` page as part of a test.
@@ -74,7 +86,9 @@ describe('Login test', () => {
e2e.pages.Login.visit();
// To prevent flaky tests, always do a `.should` on any selector that you expect to be in the DOM.
// Read more here: https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions
e2e.pages.Login.username().should('be.visible').type('admin');
e2e.pages.Login.username()
.should('be.visible')
.type('admin');
});
});
```
@@ -140,28 +154,25 @@ describe('List test', () => {
e2e.pages.DataSources.visit();
// To prevent flaky tests, always do a .should on any selector that you expect to be in the DOM.
// Read more here: https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions
e2e.pages.DataSources.dataSources('B').should('be.visible').click();
e2e.pages.DataSources.dataSources('B')
.should('be.visible')
.click();
});
});
```
## Aria-Labels vs data-testid
Our selectors are set up to work with both aria-labels and data-testid attributes. Aria-labels help assistive technologies such as screenreaders identify interactive elements of a page for our users.
Our selectors are set up to work with both aria-labels and data-testid attributes. Aria-labels help assistive technologies such as screenreaders identify interactive elements of a page for our users.
A good example of a time to use an aria-label might be if you have a button with an X to close:
```
<button aria-label="close">X<button>
```
It might be clear visually that the X closes the modal, but audibly it would not be clear for example.
```
<button aria-label="close">Close<button>
```
The example might read aloud to a user as "Close, Close" or something similar.
The above example for example might read aloud to a user "Close, Close" or something similar.
However adding aria-labels to elements that are already clearly labeled or not interactive can be confusing and redundant for users with assistive technologies.
@@ -174,18 +185,16 @@ In such cases rather than adding unnecessary aria-labels to components so as to
We have added support for this in our selectors, to use:
Prefix your selector string with "data-testid":
```typescript
export const Components = {
Login: {
openButton: 'open-button', // this would look for an aria-label
closeButton: 'data-testid modal-close-button', // this would look for a data-testid
openButton: "data-testid-open", // this would look for a data-testid
closeButton: "close-button" // this would look for an aria-label
},
};
```
and in your component, import the selectors and add the data test id:
```
<button data-testid={Selectors.Components.Login.closeButton}>
```
<button data-testid={Selectors.Components.Login.openButton}>
```

View File

@@ -5,7 +5,6 @@ Generally we follow the Airbnb [React Style Guide](https://github.com/airbnb/jav
## Table of Contents
- [Frontend Style Guide](#frontend-style-guide)
- [Table of Contents](#table-of-contents)
- [Basic rules](#basic-rules)
- [Naming conventions](#naming-conventions)
@@ -29,12 +28,12 @@ Generally we follow the Airbnb [React Style Guide](https://github.com/airbnb/jav
- [Linting](#linting)
- [React](#react)
- [Props](#props)
- [Name callback props and handlers with an "on" prefix.](#name-callback-props-and-handlers-with-an-on-prefix)
- [React Component definitions](#react-component-definitions)
- [React Component constructor](#react-component-constructor)
- [React Component defaultProps](#react-component-defaultprops)
- [Name callback props and handlers with an "on" prefix.](#name-callback-props-and-handlers-with-an-on-prefix)
- [React Component definitions](#react-component-definitions)
- [React Component constructor](#react-component-constructor)
- [React Component defaultProps](#react-component-defaultprops)
- [State management](#state-management)
- [Proposal for removing or replacing Angular dependencies](https://github.com/grafana/grafana/pull/23048)
## Basic rules
@@ -195,12 +194,12 @@ _SASS styles are deprecated. Please migrate to Emotion whenever you need to modi
### Typing
In general, you should let Typescript infer the types so that there's no need to explicitly define type for each variable.
In general, you should let Typescript infer the types so that there's no need to explicitly define type for each variable.
There are some exceptions to this:
```typescript
// Typescript needs to know type of arrays or objects otherwise it would infer it as array of any
// Typescript needs to know type of arrays or objects otherwise it would infer it as array of any
// bad
const stringArray = [];
@@ -209,7 +208,7 @@ const stringArray = [];
const stringArray: string[] = [];
```
Specify function return types explicitly in new code. This improves readability by being able to tell what a function returns just by looking at the signature. It also prevents errors when a function's return type is broader than expected by the author.
Specify function return types explicitly in new code. This improves readability by being able to tell what a function returns just by looking at the signature. It also prevents errors when a function's return type is broader than expected by the author.
> **Note:** We don't have linting for this enabled because of lots of old code that needs to be fixed first.
@@ -217,18 +216,18 @@ Specify function return types explicitly in new code. This improves readability
// bad
function transform(value?: string) {
if (!value) {
return undefined;
return undefined
}
return applyTransform(value);
}
return applyTransform(value)
};
// good
function transform(value?: string): TransformedValue | undefined {
if (!value) {
return undefined;
return undefined
}
return applyTransform(value);
}
return applyTransform(value)
};
```
### File and directory naming conventions
@@ -245,8 +244,6 @@ For files exporting multiple utility functions, use the name that describes the
- Use `reducers.ts` Redux reducers.
- Use `*.test.ts(x)` for test files.
- Use kebab case for directory names: lowercase, words delimited by hyphen ( `-` ). For example, `features/new-important-feature/utils.ts`.
### Code organization
Organize your code in a directory that encloses feature code:
@@ -268,7 +265,6 @@ For code that needs to be used by external plugin:
- Use named exports for all code you want to export from a file.
- Use declaration exports (i.e. `export const foo = ...`).
- Avoid using default exports (for example, `export default foo`).
- Export only the code that is meant to be used outside the module.
### Comments
@@ -345,14 +341,6 @@ static defaultProps = { ... }
static defaultProps: Partial<Props> = { ... }
```
### How to declare functional components
We recommend using named regular functions when creating a new react functional component.
```typescript
export function Component(props: Props): ReactElement { ... }
```
## State management
- Don't mutate state in reducers or thunks.

View File

@@ -1,7 +1,6 @@
# Redux framework
Grafana uses [Redux Toolkit](https://redux-toolkit.js.org/) to handle Redux boilerplate code.
> Some of our Reducers are used by Angular and therefore state is to be considered as mutable for those reducers.
## Test functionality
@@ -20,7 +19,6 @@ reducerTester()
```
#### Complex usage
Sometimes you encounter a `resulting state` that contains properties that are hard to compare, such as `Dates`, but you still want to compare that other props in state are correct.
Then you can use `thenStatePredicateShouldEqual` function on `reducerTester` that will return the `resulting state` so that you can expect upon individual properties..
@@ -29,9 +27,9 @@ Then you can use `thenStatePredicateShouldEqual` function on `reducerTester` tha
reducerTester()
.givenReducer(someReducer, initialState)
.whenActionIsDispatched(someAction('reducer tests'))
.thenStatePredicateShouldEqual((resultingState) => {
.thenStatePredicateShouldEqual(resultingState => {
expect(resultingState.data).toEqual('reducer tests');
return true;
return true;
});
```
@@ -42,7 +40,9 @@ Fluent API that simplifies the testing of thunks.
#### Usage
```typescript
const dispatchedActions = await thunkTester(initialState).givenThunk(someThunk).whenThunkIsDispatched(arg1, arg2, arg3);
const dispatchedActions = await thunkTester(initialState)
.givenThunk(someThunk)
.whenThunkIsDispatched(arg1, arg2, arg3);
expect(dispatchedActions).toEqual([someAction('reducer tests')]);
```
@@ -52,7 +52,7 @@ expect(dispatchedActions).toEqual([someAction('reducer tests')]);
It is possible to infer connected props automatically from `mapStateToProps` and `mapDispatchToProps` using a helper type `ConnectedProps` from Redux. For this to work the `connect` call has to be split into two parts.
```typescript
import { connect, ConnectedProps } from 'react-redux';
import { connect, ConnectedProps } from 'react-redux'
const mapStateToProps = (state: StoreState) => {
return {
@@ -75,9 +75,8 @@ const connector = connect(mapStateToProps, mapDispatchToProps);
type Props = OwnProps & ConnectedProps<typeof connector>;
class PanelEditorUnconnected extends PureComponent<Props> {}
class PanelEditorUnconnected extends PureComponent<Props> {};
export const PanelEditor = connector(PanelEditorUnconnected);
```
For more examples, refer to the [Redux docs](https://react-redux.js.org/using-react-redux/static-typing#inferring-the-connected-props-automatically).

View File

@@ -120,7 +120,7 @@ Example use cases:
### Typography
For font family, font sizes and line heights use the variables under `theme.typography`.
For font family, font sizes and line heights use the variables under `theme.typography`.
#### Using `ThemeContext` directly

View File

@@ -15,37 +15,34 @@ Feel free to add templates to the `templates` folder. Try to make them as generi
## Documentation templates
In an ideal world, each topic will correspond to an information _type_ ([task](doc-task-template.md), [reference](doc-reference-template.md), [concept](doc-concept-template.md)) and contain only that type of information.
In an ideal world, each topic will correspond to an information *type* ([task](doc-task-template.md), [reference](doc-reference-template.md), [concept](doc-concept-template.md)) and contain only that type of information.
However, this is not always practical. For example, you have a series of short topics, you can group them into one topic.
Try to _chunk_ your content. This means you should organize the document so that the same kinds of content are grouped together.
Try to *chunk* your content. This means you should organize the document so that the same kinds of content are grouped together.
### Chunking example
If I was writing content for a site called _Doggie handbook_, I might organize it like this.
If I was writing content for a site called *Doggie handbook*, I might organize it like this.
**Concept**
- What a dog is
- Brief history of dogs
- Why you might want a dog
- Tasks dogs can be trained to do
**Tasks**
- Feed the dog
- Groom the dog
- Train the dog
**Reference**
- List of dog equipment you will need
- Table of breeds that includes breed name, size range, short or long hair, and type of dog
### Audience
Write for an audience that is computer literate and has general technical knowledge, but is not necessarily familiar with Grafana or the finer points of observability.
Write for an audience that is computer literate and has general technical knowledge, but is not necessarily familiar with Grafana or the finer points of observability.
Pretend you are explaining your topic to a brand new Grafana user or developer.
@@ -53,7 +50,7 @@ Pretend you are explaining your topic to a brand new Grafana user or developer.
Thanks to search engines, every page in the documentation might be a reader's entry point. This means that each page needs to be self-contained and make sense on its own. The reader should not need to read other topics in order to perform the task or understand the concept.
However, try to be helpful and link to related information. Using the _Doggie handbook_ example, the concept topic that explains what dogs can be trained to do might link to the Train the dog task.
However, try to be helpful and link to related information. Using the *Doggie handbook* example, the concept topic that explains what dogs can be trained to do might link to the Train the dog task.
## Code templates

View File

@@ -23,20 +23,20 @@ Concepts are topic types for any information that doesn't involve task lists or
## Idea
Concept topics or sections explain _what_ and _why_. They do not explain _how_. If you are a new user, you might look for concept information to learn about what Grafana is, why it might be useful to you, and what the general workflow is.
Concept topics or sections explain *what* and *why*. They do not explain *how*. If you are a new user, you might look for concept information to learn about what Grafana is, why it might be useful to you, and what the general workflow is.
## Workflow
Continuing the example in the previous section, here is a sample Grafana workflow.
Continuing the example in the previous section, here is a sample Grafana workflow.
1. Install Grafana. <link to task for installing Grafana>
1. Set up data sources. <link to data sources concept topic, which links to data source task topics>
1. Create panels. <link to panel concept topic, which links to tasks>
1. Create dashboards. <link to panel concept topic, which links to tasks>
1. Create dashboards. <link to panel concept topic, which links to tasks>
1. Enter queries. <link to query editor concept topic>
1. Add users. <link to user management concept topic, which links to tasks>
1. Create playlists. <link to Playlist topic that contains concept information and tasks>
## Next steps
Concept tasks often link to related information, including _tasks_ related to the concept and _reference_ topics related to the concept.
Concept tasks often link to related information, including *tasks* related to the concept and *reference* topics related to the concept.

View File

@@ -15,9 +15,9 @@ weight = 100
# Reference
The _reference_ topic type is for storing reference information, such as extensive tables, lists, or other information that is used as support for a task. Reference topics are also designed for API information.
The *reference* topic type is for storing reference information, such as extensive tables, lists, or other information that is used as support for a task. Reference topics are also designed for API information.
Often reference topics are linked from _task_ topics, because they contain information the user needs in order to perform a task.
Often reference topics are linked from *task* topics, because they contain information the user needs in order to perform a task.
[Grafana CLI](https://grafana.com/docs/grafana/latest/administration/cli/) is one example of a reference topic.
@@ -41,12 +41,12 @@ The [Glossary](https://grafana.com/docs/grafana/latest/guides/glossary/) provide
While you might not need a heading for each table, headings are a good way to chunk information if you have several tables. They also make the content easy to skim. Use headings or intro paragraphs like this one to explain to the reader what the information in the table is used for.
| | | | | | |
| :-- | :-- | :-: | :-: | --: | --: |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
|:---|:---|:--:|:--:|---:|---:|
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
### Empty HTML table

View File

@@ -14,7 +14,7 @@ weight = 100
# Task
A _task_ topic is intended for a procedure that describes how to accomplish a task. It lists a series of steps that users follow to produce an intended outcome. It tells the reader _how_ to do something. [Install Grafana plugins](https://grafana.com/docs/grafana/latest/plugins/installation/) and [Playlist](https://grafana.com/docs/grafana/latest/reference/playlist/) are examples of task topics. Playlist includes a small amount of concept information in the introduction, which is appropriate.
A *task* topic is intended for a procedure that describes how to accomplish a task. It lists a series of steps that users follow to produce an intended outcome. It tells the reader *how* to do something. [Install Grafana plugins](https://grafana.com/docs/grafana/latest/plugins/installation/) and [Playlist](https://grafana.com/docs/grafana/latest/reference/playlist/) are examples of task topics. Playlist includes a small amount of concept information in the introduction, which is appropriate.
Always include an introduction of a short paragraph or two to explain what the task is for, perhaps give the reader an idea of what the outcome will be.
@@ -52,6 +52,6 @@ Thanks to internet search engines, every page in the documentation could be page
## Testing
It is a good practice to have someone else test the task you have written. If they can successfully complete the task using _only_ what the steps you have written, not guessing or using their inherent knowledge, then your task has passed the test. However, it is very common to find you have skipped steps, because _you_ are very familiar with Grafana and the topic you are explaining.
It is a good practice to have someone else test the task you have written. If they can successfully complete the task using *only* what the steps you have written, not guessing or using their inherent knowledge, then your task has passed the test. However, it is very common to find you have skipped steps, because *you* are very familiar with Grafana and the topic you are explaining.
New users or people from other teams are very helpful for these tests.

212
cue/data/gen.cue Normal file
View File

@@ -0,0 +1,212 @@
package grafanaschema
import "github.com/grafana/grafana/cue/scuemata"
Family: scuemata.#Family & {
lineages: [
[
{ // 0.0
// Unique numeric identifier for the dashboard.
// TODO must isolate or remove identifiers local to a Grafana instance...?
id?: number
// Unique dashboard identifier that can be generated by anyone. string (8-40)
uid?: string
// Title of dashboard.
title?: string
// Description of dashboard.
description?: string
gnetId?: string
// Tags associated with dashboard.
tags?: [...string]
// Theme of dashboard.
style: *"light" | "dark"
// Timezone of dashboard,
timezone?: *"browser" | "utc"
// Whether a dashboard is editable or not.
editable: bool | *true
// 0 for no shared crosshair or tooltip (default).
// 1 for shared crosshair.
// 2 for shared crosshair AND shared tooltip.
graphTooltip: >=0 & <=2 | *0
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
time?: {
from: string | *"now-6h"
to: string | *"now"
}
// Timepicker metadata.
timepicker?: {
// Whether timepicker is collapsed or not.
collapse: bool | *false
// Whether timepicker is enabled or not.
enable: bool | *true
// Whether timepicker is visible or not.
hidden: bool | *false
// Selectable intervals for auto-refresh.
refresh_intervals: [...string] | *["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
}
// Templating.
templating?: list: [...{...}]
// Annotations.
annotations?: list: [...{
builtIn: number | *0
// Datasource to use for annotation.
datasource: string
// Whether annotation is enabled.
enable?: bool | *true
// Whether to hide annotation.
hide?: bool | *false
// Annotation icon color.
iconColor?: string
// Name of annotation.
name?: string
type: string | *"dashboard"
// Query for annotation data.
rawQuery?: string
showIn: number | *0
}]
// Auto-refresh interval.
refresh?: string
// Version of the JSON schema, incremented each time a Grafana update brings
// changes to said schema.
schemaVersion: number | *25
// Version of the dashboard, incremented each time the dashboard is updated.
version?: number
panels?: [...#Panel]
// Dashboard panels. Panels are canonically defined inline
// because they share a version timeline with the dashboard
// schema; they do not vary independently. We create a separate,
// synthetic Family to represent them in Go, for ease of generating
// e.g. JSON Schema.
#Panel: {
// The panel plugin type id.
type: !=""
// Internal - the exact major and minor versions of the panel plugin
// schema. Hidden and therefore not a part of the data model, but
// expected to be filled with panel plugin schema versions so that it's
// possible to figure out which schema version matched on a successful
// unification.
// _pv: { maj: int, min: int }
// The major and minor versions of the panel plugin for this schema.
// TODO 2-tuple list instead of struct?
panelSchema?: { maj: number, min: number }
// Panel title.
title?: string
// Description.
description?: string
// Whether to display the panel without a background.
transparent: bool | *false
// Name of default datasource.
datasource?: string
// Grid position.
gridPos?: {
// Panel
h: number & >0 | *9
// Panel
w: number & >0 & <=24 | *12
// Panel x
x: number & >=0 & <24 | *0
// Panel y
y: number & >=0 | *0
// true if fixed
static?: bool
}
// Panel links.
// links?: [..._panelLink]
// Name of template variable to repeat for.
repeat?: string
// Direction to repeat in if 'repeat' is set.
// "h" for horizontal, "v" for vertical.
repeatDirection: *"h" | "v"
// Schema for panel targets is specified by datasource
// plugins. We use a placeholder definition, which the Go
// schema loader either left open/as-is with the Base
// variant of the Dashboard and Panel families, or filled
// with types derived from plugins in the Instance variant.
// When working directly from CUE, importers can extend this
// type directly to achieve the same effect.
targets?: [...{...}]
// The values depend on panel type
options: {...}
fieldConfig: {
defaults: {
// The display value for this field. This supports template variables blank is auto
displayName?: string
// This can be used by data sources that return and explicit naming structure for values and labels
// When this property is configured, this value is used rather than the default naming strategy.
displayNameFromDS?: string
// Human readable field metadata
description?: string
// An explict path to the field in the datasource. When the frame meta includes a path,
// This will default to `${frame.meta.path}/${field.name}
//
// When defined, this value can be used as an identifier within the datasource scope, and
// may be used to update the results
path?: string
// True if data source can write a value to the path. Auth/authz are supported separately
writeable?: bool
// True if data source field supports ad-hoc filters
filterable?: bool
// Numeric Options
unit?: string
// Significant digits (for display)
decimals?: number
min?: number
max?: number
// // Convert input values into a display string
// mappings?: ValueMapping[];
// // Map numeric values to states
// thresholds?: ThresholdsConfig;
// // Map values to a display color
// color?: FieldColor;
// // Used when reducing field values
// nullValueMode?: NullValueMode;
// // The behavior when clicking on a result
links?: [...]
// Alternative to empty string
noValue?: string
// Can always exist. Valid fields within this are
// defined by the panel plugin - that's the
// PanelFieldConfig that comes from the plugin.
custom?: {}
}
overrides: [...{
matcher: {
id: string | *""
options?: _
}
properties: [...{
id: string | *""
value?: _
}]
}]
}
}
}
]
]
}
#Latest: {
#Dashboard: Family.latest
#Panel: Family.latest._Panel
}

View File

@@ -8,10 +8,10 @@ package scuemata
// the larger Dashboard schema.
#PanelSchema: {
// Defines plugin specific options for a panel
PanelOptions: {...} @cuetsy(kind="interface")
PanelOptions: {...}
// Define the custom properties that exist within standard field config
PanelFieldConfig?: {...} @cuetsy(kind="interface")
PanelFieldConfig?: {...}
// Panels may define their own types
...

View File

@@ -14,7 +14,6 @@ package scuemata
// its position in the list of lineages - e.g., 0.0 corresponds to the first
// schema in the first lineage.
#Family: {
compose?: {...}
lineages: [#Lineage, ...#Lineage]
migrations: [...#Migration]
let lseq = lineages[len(lineages)-1]

93
cue/ui/gen.cue Normal file
View File

@@ -0,0 +1,93 @@
package grafanaschema
TableCellDisplayMode: {
Auto: "auto",
ColorText: "color-text",
ColorBackground: "color-background",
GradientGauge: "gradient-gauge",
LcdGauge: "lcd-gauge",
JSONView: "json-view",
BasicGauge: "basic",
Image: "image",
} @cuetsy(targetType="enum")
TableFieldOptions: {
width?: number
align: FieldTextAlignment | *"auto"
displayMode: TableCellDisplayMode | *"auto"
hidden?: bool // ?? default is missing or false ??
} @cuetsy(targetType="interface")
TableSortByFieldState: {
displayName: string
desc?: bool
} @cuetsy(targetType="interface")
TooltipDisplayMode: "single" | "multi" | "none" @cuetsy(targetType="enum")
FieldTextAlignment: "auto" | "left" | "right" | "center" @cuetsy(targetType="type")
AxisPlacement: "auto" | "top" | "right" | "bottom" | "left" | "hidden" @cuetsy(targetType="enum")
PointVisibility: "auto" | "never" | "always" @cuetsy(targetType="enum")
DrawStyle: "line" | "bars" | "points" @cuetsy(targetType="enum")
LineInterpolation: "linear" | "smooth" | "stepBefore" | "stepAfter" @cuetsy(targetType="enum")
ScaleDistribution: "linear" | "log" @cuetsy(targetType="enum")
GraphGradientMode: "none" | "opacity" | "hue" | "scheme" @cuetsy(targetType="enum")
LineStyle: {
fill?: "solid" | "dash" | "dot" | "square"
dash?: [number]
} @cuetsy(targetType="interface")
LineConfig: {
lineColor?: string
lineWidth?: number
lineInterpolation?: LineInterpolation
lineStyle?: LineStyle
spanNulls?: bool
} @cuetsy(targetType="interface")
FillConfig: {
fillColor?: string
fillOpacity?: number
fillBelowTo?: string
} @cuetsy(targetType="interface")
PointsConfig: {
showPoints?: PointVisibility
pointSize?: number
pointColor?: string
pointSymbol?: string
} @cuetsy(targetType="interface")
ScaleDistributionConfig: {
type: ScaleDistribution
log?: number
} @cuetsy(targetType="interface")
AxisConfig: {
axisPlacement?: AxisPlacement
axisLabel?: string
axisWidth?: number
axisSoftMin?: number
axisSoftMax?: number
scaleDistribution?: ScaleDistributionConfig
} @cuetsy(targetType="interface")
HideSeriesConfig: {
tooltip: bool
legend: bool
graph: bool
} @cuetsy(targetType="interface")
LegendPlacement: "bottom" | "right" @cuetsy(targetType="type")
LegendDisplayMode: "list" | "table" | "hidden" @cuetsy(targetType="enum")
TableFieldOptions: {
width?: number
align: FieldTextAlignment | *"auto"
displayMode: TableCellDisplayMode | *"auto"
hidden?: bool
} @cuetsy(targetType="interface")
GraphFieldConfig: LineConfig & FillConfig & PointsConfig & AxisConfig & {
drawStyle?: DrawStyle
gradientMode?: GraphGradientMode
hideFrom?: HideSeriesConfig
} @cuetsy(targetType="interface")
VizLegendOptions: {
displayMode: LegendDisplayMode
placement: LegendPlacement
calcs: [string]
} @cuetsy(targetType="interface")
VizTooltipOptions: {
mode: TooltipDisplayMode
} @cuetsy(targetType="interface")

View File

@@ -55,9 +55,6 @@ Jaeger block runs both Jaeger and Loki container. Loki container sends traces to
| 1.0 | graphite1 | 8280 | 2203 | 2203 |
| 0.9 | graphite09 | 8380 | 2303 | 2303 |
## Debugging setup in VS Code
An example of launch.json is provided in `devenv/vscode/launch.json`. It basically does what Makefile and .bra.toml do. The 'program' field is set to the folder name so VS Code loads all *.go files in it instead of just main.go.
## Troubleshooting
### Containers that read from log files fail to start (Mac OS)

View File

@@ -34,15 +34,11 @@ datasources:
type: prometheus
access: proxy
url: http://localhost:9090
jsonData:
manageAlerts: false
- name: gdev-slow-prometheus
type: prometheus
access: proxy
url: http://localhost:3011
jsonData:
manageAlerts: false
- name: gdev-testdata
isDefault: true
@@ -297,7 +293,6 @@ datasources:
url: http://localhost:3100
editable: false
jsonData:
manageAlerts: false
derivedFields:
- name: "traceID"
matcherRegex: "traceID=(\\w+)"

View File

@@ -1,990 +0,0 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"graphTooltip": 0,
"iteration": 1629464729438,
"links": [
{
"asDropdown": true,
"icon": "external link",
"includeVars": false,
"keepTime": false,
"tags": [
"gdev",
"panel-tests"
],
"targetBlank": false,
"title": "Dropdown link",
"tooltip": "",
"type": "dashboards",
"url": ""
},
{
"asDropdown": false,
"icon": "external link",
"includeVars": false,
"keepTime": false,
"tags": [],
"targetBlank": false,
"title": "External link",
"tooltip": "localhost",
"type": "link",
"url": "localhost:3000"
}
],
"panels": [
{
"gridPos": {
"h": 3,
"w": 12,
"x": 0,
"y": 0
},
"id": 34,
"options": {
"content": "# All panels\n\nThis dashboard was created to quickly check accessiblity issues on a lot of panels at the same time ",
"mode": "markdown"
},
"pluginVersion": "8.1.0-pre",
"transparent": true,
"type": "text"
},
{
"gridPos": {
"h": 3,
"w": 12,
"x": 12,
"y": 0
},
"id": 35,
"options": {
"content": "# Another text panel\n\nBecause why not",
"mode": "markdown"
},
"pluginVersion": "8.1.0-pre",
"transparent": true,
"type": "text"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 3
},
"id": 32,
"panels": [],
"title": "Row title",
"type": "row"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"fillOpacity": 70,
"lineWidth": 1
},
"mappings": [
{
"options": {
"CRITICAL": {
"color": "red",
"index": 3
},
"HIGH": {
"color": "orange",
"index": 2
},
"LOW": {
"color": "blue",
"index": 0
},
"NORMAL": {
"color": "green",
"index": 1
}
},
"type": "value"
}
],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 24,
"x": 0,
"y": 4
},
"id": 41,
"options": {
"alignValue": "left",
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"mergeValues": true,
"rowHeight": 0.99,
"showValue": "auto",
"tooltip": {
"mode": "single"
}
},
"targets": [
{
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "LOW,HIGH,NORMAL,NORMAL,NORMAL,LOW,LOW,NORMAL,HIGH,CRITICAL"
},
{
"refId": "B",
"scenarioId": "csv_metric_values",
"stringInput": "NORMAL,LOW,LOW,CRITICAL,CRITICAL,LOW,LOW,NORMAL,HIGH,CRITICAL"
},
{
"refId": "C",
"scenarioId": "csv_metric_values",
"stringInput": "NORMAL,NORMAL,NORMAL,NORMAL,CRITICAL,LOW,NORMAL,NORMAL,NORMAL,LOW"
}
],
"title": "State timeline",
"type": "state-timeline"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "continuous-GrYlRd"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 11,
"w": 9,
"x": 0,
"y": 0
},
"id": 62,
"options": {
"basemap": {
"config": {},
"type": "default"
},
"controls": {
"mouseWheelZoom": true,
"showAttribution": true,
"showDebug": false,
"showScale": false,
"showZoom": true
},
"layers": [
{
"config": {
"color": {
"field": "Price",
"fixed": "dark-green"
},
"fillOpacity": 0.4,
"shape": "circle",
"showLegend": true,
"size": {
"field": "Count",
"fixed": 5,
"max": 15,
"min": 2
}
},
"location": {
"gazetteer": "public/gazetteer/usa-states.json",
"lookup": "State",
"mode": "auto"
},
"type": "markers"
}
],
"view": {
"id": "coords",
"lat": 38.297683,
"lon": -99.228359,
"shared": true,
"zoom": 3.98
}
},
"targets": [
{
"csvFileName": "flight_info_by_state.csv",
"refId": "A",
"scenarioId": "csv_file"
}
],
"title": "Size, color mapped to different fields + share view",
"type": "geomap"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"fillOpacity": 80,
"gradientMode": "hue",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineWidth": 1
},
"links": [
{
"title": "Data link",
"url": "/"
}
],
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 13
},
"id": 4,
"options": {
"bucketOffset": 0,
"combine": false,
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
}
},
"title": "Histogram",
"type": "histogram"
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 21
},
"id": 28,
"options": {
"dedupStrategy": "none",
"enableLogDetails": true,
"prettifyLogMessage": false,
"showCommonLabels": false,
"showLabels": false,
"showTime": false,
"sortOrder": "Descending",
"wrapLogMessage": false
},
"targets": [
{
"refId": "A",
"scenarioId": "logs"
}
],
"title": "Logs",
"type": "logs"
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 21
},
"id": 8,
"options": {
"maxItems": 10,
"query": "",
"showHeadings": true,
"showRecentlyViewed": true,
"showSearch": true,
"showStarred": true,
"tags": []
},
"pluginVersion": "8.1.0-pre",
"title": "Dashboard list",
"type": "dashlist"
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 29
},
"id": 30,
"title": "Panel list",
"type": "pluginlist"
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 29
},
"id": 6,
"options": {
"alertName": "",
"dashboardAlerts": false,
"maxItems": 20,
"showInstances": false,
"sortOrder": 1,
"stateFilter": {
"firing": true,
"inactive": false,
"pending": true
}
},
"title": "Alert list",
"type": "alertlist"
},
{
"cards": {
},
"color": {
"cardColor": "#b4ff00",
"colorScale": "sqrt",
"colorScheme": "interpolateOranges",
"exponent": 0.5,
"mode": "spectrum"
},
"dataFormat": "timeseries",
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 37
},
"heatmap": {},
"hideZeroBuckets": false,
"highlightCards": true,
"id": 26,
"legend": {
"show": false
},
"reverseYBuckets": false,
"targets": [
{
"refId": "A",
"scenarioId": "exponential_heatmap_bucket_data"
}
],
"title": "Heatmap",
"tooltip": {
"show": true,
"showHistogram": false
},
"type": "heatmap",
"xAxis": {
"show": true
},
"yAxis": {
"format": "short",
"logBase": 1,
"show": true
},
"yBucketBound": "auto"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 37
},
"id": 20,
"options": {
"displayMode": "gradient",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"showUnfilled": true,
"text": {}
},
"pluginVersion": "8.1.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk",
"seriesCount": 10
}
],
"title": "Bar gauge",
"type": "bargauge"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
}
},
"mappings": []
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 45
},
"id": 24,
"options": {
"legend": {
"displayMode": "list",
"placement": "bottom"
},
"pieType": "pie",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"tooltip": {
"mode": "single"
}
},
"targets": [
{
"refId": "A",
"scenarioId": "random_walk",
"seriesCount": 6
}
],
"title": "Pie chart",
"type": "piechart"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 45
},
"id": 18,
"options": {
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "auto",
"showValue": "auto",
"showThresholdLabels": false,
"showThresholdMarkers": true,
"text": {}
},
"pluginVersion": "8.1.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk",
"seriesCount": 3
}
],
"title": "Gauge",
"type": "gauge"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"displayMode": "auto"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 53
},
"id": 22,
"options": {
"showHeader": true
},
"pluginVersion": "8.1.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "table_static"
}
],
"title": "Tabel",
"type": "table"
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 53
},
"id": 10,
"options": {
"limit": 10,
"navigateAfter": "10m",
"navigateBefore": "10m",
"onlyFromThisDashboard": false,
"onlyInTimeRange": false,
"showTags": true,
"showTime": true,
"showUser": true
},
"title": "Annotation list",
"type": "annolist"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 61
},
"id": 16,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"text": {},
"textMode": "auto"
},
"pluginVersion": "8.1.0-pre",
"title": "Stat",
"type": "stat"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 12,
"x": 12,
"y": 61
},
"id": 2,
"links": [],
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single"
}
},
"targets": [
{
"refId": "A",
"scenarioId": "random_walk",
"seriesCount": 4,
"spread": 120
}
],
"title": "Graph NG",
"type": "timeseries"
},
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"axisSoftMin": 0,
"fillOpacity": 80,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineWidth": 1
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 69
},
"id": 14,
"options": {
"barWidth": 0.97,
"groupWidth": 0.7,
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"orientation": "auto",
"showValue": "auto",
"stacking": "none",
"text": {},
"tooltip": {
"mode": "single"
}
},
"targets": [
{
"csvContent": "Series, Value\nBar 2, 20\nBar 3, 25\nBar 3, 55.4",
"refId": "A",
"scenarioId": "csv_content"
}
],
"title": "Bar chart",
"type": "barchart"
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 77
},
"id": 12,
"options": {
"showImage": true
},
"title": "News panel",
"type": "news"
}
],
"refresh": "",
"schemaVersion": 30,
"style": "dark",
"tags": [
"gdev",
"panel-tests",
"all-panels"
],
"templating": {
"list": [
{
"current": {},
"datasource": "gdev-testdata",
"definition": "*",
"hide": 0,
"includeAll": true,
"multi": true,
"name": "query0",
"options": [],
"query": {
"query": "*",
"refId": "StandardVariableQuery"
},
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
},
{
"current": {
"selected": true,
"text": "7",
"value": "7"
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "query1",
"options": [
{
"selected": false,
"text": "1",
"value": "1"
},
{
"selected": false,
"text": "5",
"value": "5"
},
{
"selected": false,
"text": "6",
"value": "6"
},
{
"selected": true,
"text": "7",
"value": "7"
}
],
"query": "1,5,6,7",
"queryValue": "",
"skipUrlSync": false,
"type": "custom"
},
{
"current": {
"selected": false,
"text": "",
"value": ""
},
"description": "This is some descriptive text",
"hide": 0,
"label": "Plain text",
"name": "text",
"options": [
{
"selected": true,
"text": "",
"value": ""
}
],
"query": "",
"skipUrlSync": false,
"type": "textbox"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Panel tests - All panels",
"uid": "n1jR8vnnz",
"version": 24
}

Some files were not shown because too many files have changed in this diff Show More