Merge branch 'main' of https://github.com/grafana/grafana into #45498-fs-object-storage

pull/45534/head
Artur Wierzbicki 3 years ago
commit 0449a7d9f3
  1. 8
      .github/commands.json
  2. 10
      CHANGELOG.md
  3. 2
      docs/sources/administration/configuration.md
  4. 2
      docs/sources/alerting/unified-alerting/alerting-rules/alert-annotation-label.md
  5. 6
      docs/sources/alerting/unified-alerting/notifications/_index.md
  6. 2
      docs/sources/alerting/unified-alerting/notifications/mute-timings.md
  7. 19
      docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md
  8. 1
      docs/sources/release-notes/_index.md
  9. 12
      docs/sources/release-notes/release-notes-8-3-7.md
  10. 8
      package.json
  11. 2
      packages/grafana-data/package.json
  12. 2
      packages/grafana-e2e-selectors/package.json
  13. 2
      packages/grafana-e2e/package.json
  14. 2
      packages/grafana-runtime/package.json
  15. 2
      packages/grafana-schema/package.json
  16. 2
      packages/grafana-ui/package.json
  17. 22
      pkg/services/ngalert/models/alert_rule_test.go
  18. 202
      pkg/services/ngalert/notifier/channels/email_test.go
  19. 4
      pkg/services/ngalert/state/manager_test.go
  20. 2
      pkg/services/ngalert/state/state.go
  21. 4
      pkg/services/notifications/notifications.go
  22. 94
      public/app/plugins/datasource/prometheus/promql.ts
  23. 45
      public/app/plugins/datasource/prometheus/querybuilder/shared/OperationInfoButton.tsx
  24. 2
      public/app/plugins/datasource/prometheus/querybuilder/shared/OperationName.tsx
  25. 200
      yarn.lock

@ -209,5 +209,13 @@
"removeFromProject":{
"url":"https://github.com/grafana/grafana/projects/33"
}
},
{
"type": "label",
"name": "team/grafana-partners",
"action": "addToProject",
"addToProject": {
"url": "https://github.com/orgs/grafana/projects/87"
}
}
]

@ -101,6 +101,16 @@ AngularJS plugin support is now in a deprecated state, meaning it will be remove
- **News:** Reload feed when changing the time range or refreshing. [#42217](https://github.com/grafana/grafana/pull/42217), [@ashharrison90](https://github.com/ashharrison90)
- **UI/Plot:** Implement keyboard controls for plot cursor. [#42244](https://github.com/grafana/grafana/pull/42244), [@kaydelaney](https://github.com/kaydelaney)
<!-- 8.3.7 START -->
# 8.3.7 (2022-03-01)
### Bug fixes
- **Provisioning:** Ensure that the default value for orgID is set when provisioning datasources to be deleted. [#44244](https://github.com/grafana/grafana/pull/44244), [@filewalkwithme](https://github.com/filewalkwithme)
<!-- 8.3.7 END -->
<!-- 8.3.6 START -->
# 8.3.6 (2022-02-09)

@ -14,7 +14,7 @@ Grafana has default and custom configuration files. You can customize your Grafa
## Configuration file location
The default settings for a Grafana instance are stored in the `$WORKING_DIR/conf/defaults.ini` file. _Do not_ change the location in this file.
The default settings for a Grafana instance are stored in the `$WORKING_DIR/conf/defaults.ini` file. _Do not_ change this file.
Depending on your OS, your custom configuration file is either the `$WORKING_DIR/conf/defaults.ini` file or the `/usr/local/etc/grafana/grafana.ini` file. The custom configuration file path can be overridden using the `--config` parameter.

@ -20,7 +20,7 @@ Labels are key-value pairs that contain information about, and are used to uniqu
### How are labels used?
- The complete set of labels for an alert is what uniquely identifies an alert within Grafana Alerts.
- The Alertmanager uses labels to match alerts for [silences]({{< relref "../silences/" >}}) and [alert groups]({{< relref "../alert-groups/" >}}) in [notification policies]({{< relref "../notification-policies/" >}}).
- The Alertmanager uses labels to match alerts for [silences]({{< relref "../silences/" >}}) and [alert groups]({{< relref "../alert-groups/" >}}) in [notification policies]({{< relref "../notifications/_index.md" >}}).
- The alerting UI displays labels for every alert instance generated by the evaluation of that rule.
- Contact points can access labels to dynamically generate notifications that contain information specific to the alert that is resulting in a notification.
- Labels can be added to an [alerting rule]({{< relref "../alerting-rules/" >}}). These manually configured labels are able to use template functions and reference other labels. Labels added to an alerting rule here take precedence in the event of a collision between labels.

@ -9,7 +9,7 @@ weight = 450
Notification policies determine how alerts are routed to contact points. Policies have a tree structure, where each policy can have one or more child policies. Each policy, except for the root policy, can also match specific alert labels. Each alert is evaluated by the root policy and subsequently by each child policy. If you enable the `Continue matching subsequent sibling nodes` option is enabled for a specific policy, then evaluation continues even after one or more matches. A parent policy’s configuration settings and contact point information govern the behavior of an alert that does not match any of the child policies. A root policy governs any alert that does not match a specific policy.
You can configure Grafana managed notification policies as well as notification policies for an [external Alertmanager data source]({{< relref "../../datasources/alertmanager.md" >}}). For more information, see [Alertmanager]({{< relref "./fundamentals/alertmanager.md" >}}).
You can configure Grafana managed notification policies as well as notification policies for an [external Alertmanager data source]({{< relref "../../../datasources/alertmanager.md" >}}). For more information, see [Alertmanager]({{< relref "../fundamentals/alertmanager.md" >}}).
## Grouping
@ -33,7 +33,7 @@ You can configure grouping to be `group_by: [alertname]` (take note that the `en
1. Click **Notification policies**.
1. From the **Alertmanager** dropdown, select an external Alertmanager. By default, the Grafana Alertmanager is selected.
1. In the Root policy section, click **Edit** (pen icon).
1. In **Default contact point**, update the [contact point]({{< relref "./contact-points.md" >}}) to whom notifications should be sent for rules when alert rules do not match any specific policy.
1. In **Default contact point**, update the [contact point]({{< relref "../contact-points.md" >}}) to whom notifications should be sent for rules when alert rules do not match any specific policy.
1. In **Group by**, choose labels to group alerts by. If multiple alerts are matched for this policy, then they are grouped by these labels. A notification is sent per group. If the field is empty (default), then all notifications are sent in a single group. Use a special label `...` to group alerts by all labels (which effectively disables grouping).
1. In **Timing options**, select from the following options:
- **Group wait** Time to wait to buffer alerts of the same group before sending an initial notification. Default is 30 seconds.
@ -48,7 +48,7 @@ You can configure grouping to be `group_by: [alertname]` (take note that the `en
1. From the **Alertmanager** dropdown, select an Alertmanager. By default, the Grafana Alertmanager is selected.
1. To add a top level specific policy, go to the **Specific routing** section and click **New specific policy**.
1. In **Matching labels** section, add one or more rules for matching alert labels. For more information, see ["How label matching works"](#how-label-matching-works).
1. In **Contact point**, add the [contact point]({{< relref "./contact-points.md" >}}) to send notification to if alert matches only this specific policy and not any of the nested policies.
1. In **Contact point**, add the [contact point]({{< relref "../contact-points.md" >}}) to send notification to if alert matches only this specific policy and not any of the nested policies.
1. Optionally, enable **Continue matching subsequent sibling nodes** to continue matching nested policies even after the alert matched the parent policy. When this option is enabled, you can get more than one notification. Use it to send notification to a catch-all contact point as well as to one of more specific contact points handled by nested policies.
1. Optionally, enable **Override grouping** to specify the same grouping as the root policy. If this option is not enabled, the root policy grouping is used.
1. Optionally, enable **Override general timings** to override the timing options configured in the group notification policy.

@ -11,7 +11,7 @@ A mute timing is a recurring interval of time when no new notifications for a po
Similar to silences, mute timings do not prevent alert rules from being evaluated, nor do they stop alert instances from being shown in the user interface. They only prevent notifications from being created.
You can configure Grafana managed mute timings as well as mute timings for an [external Alertmanager data source]({{< relref "../../datasources/alertmanager.md" >}}). For more information, see [Alertmanager]({{< relref "./fundamentals/alertmanager.md" >}}).
You can configure Grafana managed mute timings as well as mute timings for an [external Alertmanager data source]({{< relref "../../../datasources/alertmanager.md" >}}). For more information, see [Alertmanager]({{< relref "../fundamentals/alertmanager.md" >}}).
## Mute timings vs silences

@ -291,16 +291,15 @@ When configured, Grafana will pass the user's token to the plugin in an Authoriz
```go
func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
for _, q := range req.Queries {
token := strings.Fields(q.Headers.Get("Authorization"))
var (
tokenType = token[0]
accessToken = token[1]
)
// ...
}
token := strings.Fields(req.Headers["Authorization"])
var (
tokenType = token[0]
accessToken = token[1]
)
for _, q := range req.Queries {
// ...
}
}
```

@ -11,6 +11,7 @@ about deprecations, breaking changes as well as changes that relate to plugin de
- [Release notes for 8.4.2]({{< relref "release-notes-8-4-2" >}})
- [Release notes for 8.4.1]({{< relref "release-notes-8-4-1" >}})
- [Release notes for 8.4.0-beta1]({{< relref "release-notes-8-4-0-beta1" >}})
- [Release notes for 8.3.7]({{< relref "release-notes-8-3-7" >}})
- [Release notes for 8.3.6]({{< relref "release-notes-8-3-6" >}})
- [Release notes for 8.3.5]({{< relref "release-notes-8-3-5" >}})
- [Release notes for 8.3.4]({{< relref "release-notes-8-3-4" >}})

@ -0,0 +1,12 @@
+++
title = "Release notes for Grafana 8.3.7"
hide_menu = true
+++
<!-- Auto generated by update changelog github action -->
# Release notes for Grafana 8.3.7
### Bug fixes
- **Provisioning:** Ensure that the default value for orgID is set when provisioning datasources to be deleted. [#44244](https://github.com/grafana/grafana/pull/44244), [@filewalkwithme](https://github.com/filewalkwithme)

@ -155,8 +155,8 @@
"@types/testing-library__react-hooks": "^3.2.0",
"@types/tinycolor2": "1.4.3",
"@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.12.1",
"@typescript-eslint/parser": "5.12.1",
"@typescript-eslint/eslint-plugin": "5.13.0",
"@typescript-eslint/parser": "5.13.0",
"@wojtekmaj/enzyme-adapter-react-17": "0.6.6",
"autoprefixer": "10.4.2",
"axios": "0.26.0",
@ -176,7 +176,7 @@
"eslint-plugin-jsdoc": "37.9.1",
"eslint-plugin-lodash": "7.4.0",
"eslint-plugin-prettier": "4.0.0",
"eslint-plugin-react": "7.28.0",
"eslint-plugin-react": "7.29.2",
"eslint-plugin-react-hooks": "4.3.0",
"eslint-webpack-plugin": "3.1.1",
"expose-loader": "3.1.0",
@ -224,7 +224,7 @@
"testing-library-selector": "0.2.1",
"ts-jest": "27.1.3",
"ts-loader": "9.2.6",
"ts-node": "10.5.0",
"ts-node": "10.6.0",
"typescript": "4.4.4",
"wait-on": "6.0.0",
"webpack": "5.69.1",

@ -67,7 +67,7 @@
"@types/tinycolor2": "1.4.3",
"react-test-renderer": "17.0.2",
"rimraf": "3.0.2",
"rollup": "2.67.1",
"rollup": "2.68.0",
"rollup-plugin-sourcemaps": "0.6.3",
"rollup-plugin-terser": "7.0.2",
"sinon": "13.0.1",

@ -28,7 +28,7 @@
"@rollup/plugin-node-resolve": "13.1.3",
"@types/node": "16.11.22",
"rimraf": "3.0.2",
"rollup": "2.67.1",
"rollup": "2.68.0",
"rollup-plugin-sourcemaps": "0.6.3",
"rollup-plugin-terser": "7.0.2"
},

@ -37,7 +37,7 @@
"@types/lodash": "4.14.178",
"@types/node": "16.11.22",
"@types/uuid": "8.3.4",
"rollup": "2.67.1",
"rollup": "2.68.0",
"rollup-plugin-copy": "3.4.0",
"rollup-plugin-sourcemaps": "0.6.3",
"rollup-plugin-terser": "7.0.2",

@ -50,7 +50,7 @@
"@types/systemjs": "^0.20.6",
"lodash": "4.17.21",
"rimraf": "3.0.2",
"rollup": "2.67.1",
"rollup": "2.68.0",
"rollup-plugin-sourcemaps": "0.6.3",
"rollup-plugin-terser": "7.0.2",
"typescript": "4.4.4"

@ -28,7 +28,7 @@
"@rollup/plugin-node-resolve": "13.1.3",
"@swc/helpers": "0.3.2",
"rimraf": "3.0.2",
"rollup": "2.67.1",
"rollup": "2.68.0",
"rollup-plugin-sourcemaps": "0.6.3",
"rollup-plugin-terser": "7.0.2",
"typescript": "4.4.4"

@ -166,7 +166,7 @@
"react-docgen-typescript-loader": "3.7.2",
"react-test-renderer": "17.0.2",
"rimraf": "3.0.2",
"rollup": "2.67.1",
"rollup": "2.68.0",
"rollup-plugin-sourcemaps": "0.6.3",
"rollup-plugin-terser": "7.0.2",
"sass-loader": "12.6.0",

@ -319,33 +319,11 @@ func TestDiff(t *testing.T) {
if rule1.DashboardUID != rule2.DashboardUID {
diff := diffs.GetDiffsForField("DashboardUID")
assert.Len(t, diff, 1)
if rule1.DashboardUID == nil {
assert.True(t, diff[0].Left.IsNil())
} else {
assert.Equal(t, *rule1.DashboardUID, diff[0].Left.Elem().String())
}
if rule2.DashboardUID == nil {
assert.True(t, diff[0].Right.IsNil())
} else {
assert.Equal(t, *rule2.DashboardUID, diff[0].Right.Elem().String())
}
difCnt++
}
if rule1.PanelID != rule2.PanelID {
diff := diffs.GetDiffsForField("PanelID")
assert.Len(t, diff, 1)
if rule1.PanelID == nil {
assert.True(t, diff[0].Left.IsNil())
} else {
assert.Equal(t, *rule1.PanelID, diff[0].Left.Elem().Int())
}
if rule2.PanelID == nil {
assert.True(t, diff[0].Right.IsNil())
} else {
assert.Equal(t, *rule2.PanelID, diff[0].Right.Elem().Int())
}
difCnt++
}
if rule1.RuleGroup != rule2.RuleGroup {

@ -10,7 +10,10 @@ import (
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
func TestEmailNotifier(t *testing.T) {
@ -102,3 +105,202 @@ func TestEmailNotifier(t *testing.T) {
}, expected)
})
}
func TestEmailNotifierIntegration(t *testing.T) {
ns := createCoreEmailService(t)
emailTmpl := templateForTests(t)
externalURL, err := url.Parse("http://localhost/base")
require.NoError(t, err)
emailTmpl.ExternalURL = externalURL
cases := []struct {
name string
alerts []*types.Alert
messageTmpl string
expSubject string
expSnippets []string
}{
{
name: "single alert with templated message",
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "AlwaysFiring", "severity": "warning"},
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
},
},
},
messageTmpl: `Hi, this is a custom template.
{{ if gt (len .Alerts.Firing) 0 }}
You have {{ len .Alerts.Firing }} alerts firing.
{{ range .Alerts.Firing }} Firing: {{ .Labels.alertname }} at {{ .Labels.severity }} {{ end }}
{{ end }}`,
expSubject: "[FIRING:1] (AlwaysFiring warning)",
expSnippets: []string{
"Hi, this is a custom template.",
"You have 1 alerts firing.",
"Firing: AlwaysFiring at warning",
},
},
{
name: "multiple alerts with templated message",
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "FiringOne", "severity": "warning"},
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
},
},
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "FiringTwo", "severity": "critical"},
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
},
},
},
messageTmpl: `Hi, this is a custom template.
{{ if gt (len .Alerts.Firing) 0 }}
You have {{ len .Alerts.Firing }} alerts firing.
{{ range .Alerts.Firing }} Firing: {{ .Labels.alertname }} at {{ .Labels.severity }} {{ end }}
{{ end }}`,
expSubject: "[FIRING:2] ",
expSnippets: []string{
"Hi, this is a custom template.",
"You have 2 alerts firing.",
"Firing: FiringOne at warning",
"Firing: FiringTwo at critical",
},
},
{
name: "empty message with alerts uses default template content",
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "FiringOne", "severity": "warning"},
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
},
},
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "FiringTwo", "severity": "critical"},
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
},
},
},
messageTmpl: "",
expSubject: "[FIRING:2] ",
expSnippets: []string{
"Firing: 2 alerts",
"<li>alertname: FiringOne</li><li>severity: warning</li>",
"<li>alertname: FiringTwo</li><li>severity: critical</li>",
"<a href=\"http://fix.me\"",
"<a href=\"http://localhost/base/d/abc",
"<a href=\"http://localhost/base/d/abc?viewPanel=5",
},
},
{
name: "message containing HTML gets HTMLencoded",
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "AlwaysFiring", "severity": "warning"},
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
},
},
},
messageTmpl: `<marquee>Hi, this is a custom template.</marquee>
{{ if gt (len .Alerts.Firing) 0 }}
<ol>
{{range .Alerts.Firing }}<li>Firing: {{ .Labels.alertname }} at {{ .Labels.severity }} </li> {{ end }}
</ol>
{{ end }}`,
expSubject: "[FIRING:1] (AlwaysFiring warning)",
expSnippets: []string{
"&lt;marquee&gt;Hi, this is a custom template.&lt;/marquee&gt;",
"&lt;li&gt;Firing: AlwaysFiring at warning &lt;/li&gt;",
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
emailNotifier := createSut(t, c.messageTmpl, emailTmpl, ns)
ok, err := emailNotifier.Notify(context.Background(), c.alerts...)
require.NoError(t, err)
require.True(t, ok)
sentMsg := getSingleSentMessage(t, ns)
require.NotNil(t, sentMsg)
require.Equal(t, "\"Grafana Admin\" <from@address.com>", sentMsg.From)
require.Equal(t, sentMsg.To[0], "someops@example.com")
require.Equal(t, c.expSubject, sentMsg.Subject)
require.Contains(t, sentMsg.Body, "text/html")
html := sentMsg.Body["text/html"]
require.NotNil(t, html)
for _, s := range c.expSnippets {
require.Contains(t, html, s)
}
})
}
}
func createCoreEmailService(t *testing.T) *notifications.NotificationService {
t.Helper()
bus := bus.New()
cfg := setting.NewCfg()
cfg.StaticRootPath = "../../../../../public/"
cfg.BuildVersion = "4.0.0"
cfg.Smtp.Enabled = true
cfg.Smtp.TemplatesPatterns = []string{"emails/*.html", "emails/*.txt"}
cfg.Smtp.FromAddress = "from@address.com"
cfg.Smtp.FromName = "Grafana Admin"
cfg.Smtp.ContentTypes = []string{"text/html", "text/plain"}
cfg.Smtp.Host = "localhost:1234"
mailer := notifications.NewFakeMailer()
ns, err := notifications.ProvideService(bus, cfg, mailer)
require.NoError(t, err)
return ns
}
func createSut(t *testing.T, messageTmpl string, emailTmpl *template.Template, ns notifications.EmailSender) *EmailNotifier {
t.Helper()
json := `{
"addresses": "someops@example.com;somedev@example.com",
"singleEmail": true
}`
settingsJSON, err := simplejson.NewJson([]byte(json))
if messageTmpl != "" {
settingsJSON.Set("message", messageTmpl)
}
require.NoError(t, err)
emailNotifier, err := NewEmailNotifier(&NotificationChannelConfig{
Name: "ops",
Type: "email",
Settings: settingsJSON,
}, ns, emailTmpl)
require.NoError(t, err)
return emailNotifier
}
func getSingleSentMessage(t *testing.T, ns *notifications.NotificationService) *notifications.Message {
t.Helper()
mailer := ns.GetMailer().(*notifications.FakeMailer)
require.Len(t, mailer.Sent, 1)
sent := mailer.Sent[0]
mailer.Sent = []*notifications.Message{}
return sent
}

@ -552,7 +552,7 @@ func TestProcessEvalResults(t *testing.T) {
},
},
},
expectedAnnotations: 2,
expectedAnnotations: 3,
expectedStates: map[string]*state.State{
`[["__alert_rule_namespace_uid__","test_namespace_uid"],["__alert_rule_uid__","test_alert_rule_uid_2"],["alertname","test_title"],["instance_label","test"],["label","test"]]`: {
AlertRuleUID: "test_alert_rule_uid_2",
@ -578,7 +578,7 @@ func TestProcessEvalResults(t *testing.T) {
Values: make(map[string]*float64),
},
},
StartsAt: evaluationTime,
StartsAt: evaluationTime.Add(20 * time.Second),
EndsAt: evaluationTime.Add(30 * time.Second).Add(state.ResendDelay * 3),
LastEvaluationTime: evaluationTime.Add(30 * time.Second),
EvaluationDuration: evaluationDuration,

@ -64,7 +64,7 @@ func (a *State) resultAlerting(alertRule *ngModels.AlertRule, result eval.Result
case eval.Alerting:
a.setEndsAt(alertRule, result)
case eval.Pending:
if result.EvaluatedAt.Sub(a.StartsAt) > alertRule.For {
if result.EvaluatedAt.Sub(a.StartsAt) >= alertRule.For {
a.State = eval.Alerting
a.StartsAt = result.EvaluatedAt
a.setEndsAt(alertRule, result)

@ -118,6 +118,10 @@ func (ns *NotificationService) Run(ctx context.Context) error {
}
}
func (ns *NotificationService) GetMailer() Mailer {
return ns.mailer
}
func (ns *NotificationService) SendWebhookSync(ctx context.Context, cmd *models.SendWebhookSync) error {
return ns.sendWebRequestSync(ctx, &Webhook{
Url: cmd.Url,

@ -18,6 +18,81 @@ export const RATE_RANGES: CompletionItem[] = [
export const OPERATORS = ['by', 'group_left', 'group_right', 'ignoring', 'on', 'offset', 'without'];
export const LOGICAL_OPERATORS = ['or', 'and', 'unless'];
const TRIGONOMETRIC_FUNCTIONS: CompletionItem[] = [
{
label: 'acos',
insertText: 'acos',
detail: 'acos(v instant-vector)',
documentation: 'calculates the arccosine of all elements in v',
},
{
label: 'acosh',
insertText: 'acosh',
detail: 'acosh(v instant-vector)',
documentation: 'calculates the inverse hyperbolic cosine of all elements in v',
},
{
label: 'asin',
insertText: 'asin',
detail: 'asin(v instant-vector)',
documentation: 'calculates the arcsine of all elements in v',
},
{
label: 'asinh',
insertText: 'asinh',
detail: 'asinh(v instant-vector)',
documentation: 'calculates the inverse hyperbolic sine of all elements in v',
},
{
label: 'atan',
insertText: 'atan',
detail: 'atan(v instant-vector)',
documentation: 'calculates the arctangent of all elements in v',
},
{
label: 'atanh',
insertText: 'atanh',
detail: 'atanh(v instant-vector)',
documentation: 'calculates the inverse hyperbolic tangent of all elements in v',
},
{
label: 'cos',
insertText: 'cos',
detail: 'cos(v instant-vector)',
documentation: 'calculates the cosine of all elements in v',
},
{
label: 'cosh',
insertText: 'cosh',
detail: 'cosh(v instant-vector)',
documentation: 'calculates the hyperbolic cosine of all elements in v',
},
{
label: 'sin',
insertText: 'sin',
detail: 'sin(v instant-vector)',
documentation: 'calculates the sine of all elements in v',
},
{
label: 'sinh',
insertText: 'sinh',
detail: 'sinh(v instant-vector)',
documentation: 'calculates the hyperbolic sine of all elements in v',
},
{
label: 'tan',
insertText: 'tan',
detail: 'tan(v instant-vector)',
documentation: 'calculates the tangent of all elements in v',
},
{
label: 'tanh',
insertText: 'tanh',
detail: 'tanh(v instant-vector)',
documentation: 'calculates the hyperbolic tangent of all elements in v',
},
];
const AGGREGATION_OPERATORS: CompletionItem[] = [
{
label: 'sum',
@ -83,6 +158,7 @@ const AGGREGATION_OPERATORS: CompletionItem[] = [
export const FUNCTIONS = [
...AGGREGATION_OPERATORS,
...TRIGONOMETRIC_FUNCTIONS,
{
insertText: 'abs',
label: 'abs',
@ -142,6 +218,12 @@ export const FUNCTIONS = [
documentation:
'Returns the number of elements in a time series vector as a scalar. This is in contrast to the `count()` aggregation operator, which always returns a vector (an empty one if the input vector is empty) and allows grouping by labels via a `by` clause.',
},
{
insertText: 'deg',
label: 'deg',
detail: 'deg(v instant-vector)',
documentation: 'Converts radians to degrees for all elements in v',
},
{
insertText: 'day_of_month',
label: 'day_of_month',
@ -286,6 +368,12 @@ export const FUNCTIONS = [
documentation:
'Returns the month of the year for each of the given times in UTC. Returned values are from 1 to 12, where 1 means January etc.',
},
{
insertText: 'pi',
label: 'pi',
detail: 'pi()',
documentation: 'Returns pi',
},
{
insertText: 'predict_linear',
label: 'predict_linear',
@ -293,6 +381,12 @@ export const FUNCTIONS = [
documentation:
'Predicts the value of time series `t` seconds from now, based on the range vector `v`, using simple linear regression.',
},
{
insertText: 'rad',
label: 'rad',
detail: 'rad(v instant-vector)',
documentation: 'Converts degrees to radians for all elements in v',
},
{
insertText: 'rate',
label: 'rate',

@ -3,8 +3,7 @@ import { GrafanaTheme2, renderMarkdown } from '@grafana/data';
import { FlexItem } from '@grafana/experimental';
import { Button, Portal, useStyles2 } from '@grafana/ui';
import React, { useState } from 'react';
import { usePopper } from 'react-popper';
import { useToggle } from 'react-use';
import { usePopperTooltip } from 'react-popper-tooltip';
import { QueryBuilderOperation, QueryBuilderOperationDef } from './types';
export interface Props {
@ -14,41 +13,39 @@ export interface Props {
export const OperationInfoButton = React.memo<Props>(({ def, operation }) => {
const styles = useStyles2(getStyles);
const [popperTrigger, setPopperTrigger] = useState<HTMLButtonElement | null>(null);
const [popover, setPopover] = useState<HTMLDivElement | null>(null);
const [isOpen, toggleIsOpen] = useToggle(false);
const popper = usePopper(popperTrigger, popover, {
const [show, setShow] = useState(false);
const { getTooltipProps, setTooltipRef, setTriggerRef, visible } = usePopperTooltip({
placement: 'top',
modifiers: [
{ name: 'arrow', enabled: true },
{
name: 'preventOverflow',
enabled: true,
options: {
rootBoundary: 'viewport',
},
},
],
visible: show,
offset: [0, 16],
onVisibleChange: setShow,
interactive: true,
trigger: ['click'],
});
return (
<>
<Button
ref={setPopperTrigger}
title="Click to show description"
ref={setTriggerRef}
icon="info-circle"
size="sm"
variant="secondary"
fill="text"
onClick={toggleIsOpen}
/>
{isOpen && (
{visible && (
<Portal>
<div ref={setPopover} style={popper.styles.popper} {...popper.attributes.popper} className={styles.docBox}>
<div ref={setTooltipRef} {...getTooltipProps()} className={styles.docBox}>
<div className={styles.docBoxHeader}>
<span>{def.renderer(operation, def, '<expr>')}</span>
<FlexItem grow={1} />
<Button icon="times" onClick={toggleIsOpen} fill="text" variant="secondary" title="Remove operation" />
<Button
icon="times"
onClick={() => setShow(false)}
fill="text"
variant="secondary"
title="Remove operation"
/>
</div>
<div
className={styles.docBoxBody}
@ -67,9 +64,9 @@ const getStyles = (theme: GrafanaTheme2) => {
return {
docBox: css({
overflow: 'hidden',
background: theme.colors.background.canvas,
background: theme.colors.background.primary,
border: `1px solid ${theme.colors.border.strong}`,
boxShadow: theme.shadows.z2,
boxShadow: theme.shadows.z3,
maxWidth: '600px',
padding: theme.spacing(1),
borderRadius: theme.shape.borderRadius(),

@ -47,7 +47,7 @@ export const OperationName = React.memo<Props>(({ operation, def, index, onChang
title={'Click to replace with alternative function'}
>
{nameElement}
<Icon className={`${styles.dropdown} operation-header-show-on-hover`} name="arrow-down" size="sm" />
<Icon className={`${styles.dropdown} operation-header-show-on-hover`} name="angle-down" size="md" />
</button>
)}
{state.isOpen && (

@ -4042,7 +4042,7 @@ __metadata:
react-test-renderer: 17.0.2
regenerator-runtime: 0.13.9
rimraf: 3.0.2
rollup: 2.67.1
rollup: 2.68.0
rollup-plugin-sourcemaps: 0.6.3
rollup-plugin-terser: 7.0.2
rxjs: 7.5.2
@ -4064,7 +4064,7 @@ __metadata:
"@rollup/plugin-node-resolve": 13.1.3
"@types/node": 16.11.22
rimraf: 3.0.2
rollup: 2.67.1
rollup: 2.68.0
rollup-plugin-sourcemaps: 0.6.3
rollup-plugin-terser: 7.0.2
tslib: 2.3.1
@ -4100,7 +4100,7 @@ __metadata:
mocha: 9.2.0
resolve-as-bin: 2.1.0
rimraf: 3.0.2
rollup: 2.67.1
rollup: 2.68.0
rollup-plugin-copy: 3.4.0
rollup-plugin-sourcemaps: 0.6.3
rollup-plugin-terser: 7.0.2
@ -4181,7 +4181,7 @@ __metadata:
react: 17.0.2
react-dom: 17.0.2
rimraf: 3.0.2
rollup: 2.67.1
rollup: 2.68.0
rollup-plugin-sourcemaps: 0.6.3
rollup-plugin-terser: 7.0.2
rxjs: 7.5.2
@ -4201,7 +4201,7 @@ __metadata:
"@rollup/plugin-node-resolve": 13.1.3
"@swc/helpers": 0.3.2
rimraf: 3.0.2
rollup: 2.67.1
rollup: 2.68.0
rollup-plugin-sourcemaps: 0.6.3
rollup-plugin-terser: 7.0.2
tslib: 2.3.1
@ -4462,7 +4462,7 @@ __metadata:
react-use: 17.3.2
react-window: 1.8.6
rimraf: 3.0.2
rollup: 2.67.1
rollup: 2.68.0
rollup-plugin-sourcemaps: 0.6.3
rollup-plugin-terser: 7.0.2
rxjs: 7.5.2
@ -11384,13 +11384,13 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/eslint-plugin@npm:5.12.1":
version: 5.12.1
resolution: "@typescript-eslint/eslint-plugin@npm:5.12.1"
"@typescript-eslint/eslint-plugin@npm:5.13.0":
version: 5.13.0
resolution: "@typescript-eslint/eslint-plugin@npm:5.13.0"
dependencies:
"@typescript-eslint/scope-manager": 5.12.1
"@typescript-eslint/type-utils": 5.12.1
"@typescript-eslint/utils": 5.12.1
"@typescript-eslint/scope-manager": 5.13.0
"@typescript-eslint/type-utils": 5.13.0
"@typescript-eslint/utils": 5.13.0
debug: ^4.3.2
functional-red-black-tree: ^1.0.1
ignore: ^5.1.8
@ -11403,7 +11403,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 007f89f6ce8744a15cbdb1953efd41fcb4af84357070d8e13ea5d0fbbca0c9c6cfdc0598fd00a793100a0c37104e68dd61d5b7cada7abbcc5dfec50ea480b8ba
checksum: ff8863b8c414eeed874c7ef4e5d540c918f9ee9be2e44fe30c6c22f2f59529a61e71afb3d7a90bff9a8f894098f11373989df91b11ef67a424c12f703021c174
languageName: node
linkType: hard
@ -11457,20 +11457,20 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:5.12.1":
version: 5.12.1
resolution: "@typescript-eslint/parser@npm:5.12.1"
"@typescript-eslint/parser@npm:5.13.0":
version: 5.13.0
resolution: "@typescript-eslint/parser@npm:5.13.0"
dependencies:
"@typescript-eslint/scope-manager": 5.12.1
"@typescript-eslint/types": 5.12.1
"@typescript-eslint/typescript-estree": 5.12.1
"@typescript-eslint/scope-manager": 5.13.0
"@typescript-eslint/types": 5.13.0
"@typescript-eslint/typescript-estree": 5.13.0
debug: ^4.3.2
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
typescript:
optional: true
checksum: d2995b00937de1d289d0a5742ad0744cfa8fbaed1a1a965eaa5dc8dca6e36e18f5c3802148c4bde0ab014a91330ebe186d01b0871ee30f36ac41361dc1d525d4
checksum: 9ca74f891df82f4f93150f0b69fcd2d9fb138c75a4629a154256108fbaa1248a96f69627cb472423890ff291e7cec30c20da25a87a21ef53fc1149ac9c18bfac
languageName: node
linkType: hard
@ -11504,13 +11504,13 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:5.12.1":
version: 5.12.1
resolution: "@typescript-eslint/scope-manager@npm:5.12.1"
"@typescript-eslint/scope-manager@npm:5.13.0":
version: 5.13.0
resolution: "@typescript-eslint/scope-manager@npm:5.13.0"
dependencies:
"@typescript-eslint/types": 5.12.1
"@typescript-eslint/visitor-keys": 5.12.1
checksum: b6e7f45b4fe39397430149ad005f7d28aa75a063dacfc947514abd52ba5235fecf937784416dfb7e8c168025b1bc74611332ceb214045cc362922e4b311bcb11
"@typescript-eslint/types": 5.13.0
"@typescript-eslint/visitor-keys": 5.13.0
checksum: 43fade6759e751387ee91f85033c036f122b5051f7ad7baf35fe5db68e2129afc1cc1c12c2b0b8a25eb206092ad1073d8e640b21f6b04824413f40751d8e0d42
languageName: node
linkType: hard
@ -11530,11 +11530,11 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/type-utils@npm:5.12.1":
version: 5.12.1
resolution: "@typescript-eslint/type-utils@npm:5.12.1"
"@typescript-eslint/type-utils@npm:5.13.0":
version: 5.13.0
resolution: "@typescript-eslint/type-utils@npm:5.13.0"
dependencies:
"@typescript-eslint/utils": 5.12.1
"@typescript-eslint/utils": 5.13.0
debug: ^4.3.2
tsutils: ^3.21.0
peerDependencies:
@ -11542,7 +11542,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 3f25e650f3be2af93d9cb1b26120b306af11c7cf36b3bd13f1c97f5c875a4abd282f8a0ae0daff0b90b4734c0dae3828b9ec508d46f65fd6cf6389a5b037fe26
checksum: 454a2fe6c5faa211fec9d7992b44f377b9d492c3a18b8ce6d6da0077f0ea92320c7ee430cc33dcce8f0ec7afab7f8db59f39f9433be5358715754e64d7fbdef2
languageName: node
linkType: hard
@ -11567,10 +11567,10 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/types@npm:5.12.1":
version: 5.12.1
resolution: "@typescript-eslint/types@npm:5.12.1"
checksum: 753cb4b0f266500298f07c0386d72e7d9570f26e2deb7017fd677d21bb8bca7f2ca01d3f4b43d86fbb7337a76f0c9da86657de96f107dba92632d726b4e7797e
"@typescript-eslint/types@npm:5.13.0":
version: 5.13.0
resolution: "@typescript-eslint/types@npm:5.13.0"
checksum: 2228935a9f7e80264a554ffadc458ee184259b56cd987bf10f12754183e032953fb93b7b31f8261dd0a40dbac4f341d4904ae7aa1f1aba9f2a92b1062f05c8dc
languageName: node
linkType: hard
@ -11628,12 +11628,12 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:5.12.1":
version: 5.12.1
resolution: "@typescript-eslint/typescript-estree@npm:5.12.1"
"@typescript-eslint/typescript-estree@npm:5.13.0":
version: 5.13.0
resolution: "@typescript-eslint/typescript-estree@npm:5.13.0"
dependencies:
"@typescript-eslint/types": 5.12.1
"@typescript-eslint/visitor-keys": 5.12.1
"@typescript-eslint/types": 5.13.0
"@typescript-eslint/visitor-keys": 5.13.0
debug: ^4.3.2
globby: ^11.0.4
is-glob: ^4.0.3
@ -11642,7 +11642,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 5677f5550fdc24879b51b3bc4c7551a5b241f70cf8f4cfe0fa2dc270dcd858c6d5085bf784c0bd471bb71da5abbbcf1ec44dc84a688ce61107d5ddba21d235ae
checksum: bcf2f94eb4b8e0a5f47fa1e04478aa3f36c8d2b629300bf3d3a375f87e8046cd7f2364cd7df8fceb97855e7789721de5c66dafcf17cfd93552a93a7d7733dfdb
languageName: node
linkType: hard
@ -11662,19 +11662,19 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/utils@npm:5.12.1":
version: 5.12.1
resolution: "@typescript-eslint/utils@npm:5.12.1"
"@typescript-eslint/utils@npm:5.13.0":
version: 5.13.0
resolution: "@typescript-eslint/utils@npm:5.13.0"
dependencies:
"@types/json-schema": ^7.0.9
"@typescript-eslint/scope-manager": 5.12.1
"@typescript-eslint/types": 5.12.1
"@typescript-eslint/typescript-estree": 5.12.1
"@typescript-eslint/scope-manager": 5.13.0
"@typescript-eslint/types": 5.13.0
"@typescript-eslint/typescript-estree": 5.13.0
eslint-scope: ^5.1.1
eslint-utils: ^3.0.0
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
checksum: 0eb277ad4e60fa46b586d5df8e05be6e0d3963a59cf409a348e2c512d5e88d657a56026754ee10c31ee1333794e145f7ffe33e08d28aa1bed4b4ab4b02a95712
checksum: cb93cddc83bd5f9cee7fc72ab64c509b285392a005fb1315522374991f18a1cb8f233ee0d1e828cc18570c3fe27e81cc28471c36142284bd39351b8a3f8a83bd
languageName: node
linkType: hard
@ -11724,13 +11724,13 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:5.12.1":
version: 5.12.1
resolution: "@typescript-eslint/visitor-keys@npm:5.12.1"
"@typescript-eslint/visitor-keys@npm:5.13.0":
version: 5.13.0
resolution: "@typescript-eslint/visitor-keys@npm:5.13.0"
dependencies:
"@typescript-eslint/types": 5.12.1
"@typescript-eslint/types": 5.13.0
eslint-visitor-keys: ^3.0.0
checksum: ada52c77dc42d055a6cefb294b9a893d680d125eb0fc5cc0daf2f85007c603ef688f4f5a865893758e00e89739850409bb748e26bb8c834372409d24ea820677
checksum: 3987217053e22a86f9105efe6250ca028ef437483b79d0dad45850edacfc273835b82178e77e5012a3c045df18561fef3eb4417cc26c328c901fbaa0da09e922
languageName: node
linkType: hard
@ -18620,6 +18620,30 @@ __metadata:
languageName: node
linkType: hard
"eslint-plugin-react@npm:7.29.2":
version: 7.29.2
resolution: "eslint-plugin-react@npm:7.29.2"
dependencies:
array-includes: ^3.1.4
array.prototype.flatmap: ^1.2.5
doctrine: ^2.1.0
estraverse: ^5.3.0
jsx-ast-utils: ^2.4.1 || ^3.0.0
minimatch: ^3.1.2
object.entries: ^1.1.5
object.fromentries: ^2.0.5
object.hasown: ^1.1.0
object.values: ^1.1.5
prop-types: ^15.8.1
resolve: ^2.0.0-next.3
semver: ^6.3.0
string.prototype.matchall: ^4.0.6
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
checksum: fcd793c0fd8e4570dcf8f70dd4afae9882303f4a4b650e09dac2f85fdc0b28747cb97b79832f4b8f4eabdbfb9edf69dc0ff04e8b7f33e0bb8e3f024185f4b037
languageName: node
linkType: hard
"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1":
version: 5.1.1
resolution: "eslint-scope@npm:5.1.1"
@ -20747,8 +20771,8 @@ __metadata:
"@types/testing-library__react-hooks": ^3.2.0
"@types/tinycolor2": 1.4.3
"@types/uuid": 8.3.4
"@typescript-eslint/eslint-plugin": 5.12.1
"@typescript-eslint/parser": 5.12.1
"@typescript-eslint/eslint-plugin": 5.13.0
"@typescript-eslint/parser": 5.13.0
"@visx/event": 2.6.0
"@visx/gradient": 2.1.0
"@visx/group": 2.1.0
@ -20795,7 +20819,7 @@ __metadata:
eslint-plugin-jsdoc: 37.9.1
eslint-plugin-lodash: 7.4.0
eslint-plugin-prettier: 4.0.0
eslint-plugin-react: 7.28.0
eslint-plugin-react: 7.29.2
eslint-plugin-react-hooks: 4.3.0
eslint-webpack-plugin: 3.1.1
eventemitter3: 4.0.7
@ -20916,7 +20940,7 @@ __metadata:
tinycolor2: 1.4.2
ts-jest: 27.1.3
ts-loader: 9.2.6
ts-node: 10.5.0
ts-node: 10.6.0
tslib: 2.3.1
typescript: 4.4.4
uplot: 1.6.19
@ -26150,6 +26174,15 @@ __metadata:
languageName: node
linkType: hard
"minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
dependencies:
brace-expansion: ^1.1.7
checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a
languageName: node
linkType: hard
"minimist-options@npm:4.1.0":
version: 4.1.0
resolution: "minimist-options@npm:4.1.0"
@ -32418,9 +32451,9 @@ __metadata:
languageName: node
linkType: hard
"rollup@npm:2.67.1":
version: 2.67.1
resolution: "rollup@npm:2.67.1"
"rollup@npm:2.68.0":
version: 2.68.0
resolution: "rollup@npm:2.68.0"
dependencies:
fsevents: ~2.3.2
dependenciesMeta:
@ -32428,7 +32461,7 @@ __metadata:
optional: true
bin:
rollup: dist/bin/rollup
checksum: 4320927ae9d42abf0a72ccdfd14303f7b6d6908ec94be953900a41bd4c0bbba3131887c3925dec65361a3e394cb572a4fa8e1f1be4db587a775068ad71d42acd
checksum: c883f6fb2e10e1c79a32527da0c50ef47a7beb8ddacfdae4197ff2d1911fb8d10bb2704496cf878d3048fbf3524d613bc87f25c5be0afc667fe30b7d04fa8092
languageName: node
linkType: hard
@ -35343,9 +35376,9 @@ __metadata:
languageName: node
linkType: hard
"ts-node@npm:10.5.0, ts-node@npm:^10.2.1":
version: 10.5.0
resolution: "ts-node@npm:10.5.0"
"ts-node@npm:10.6.0":
version: 10.6.0
resolution: "ts-node@npm:10.6.0"
dependencies:
"@cspotcode/source-map-support": 0.7.0
"@tsconfig/node10": ^1.0.7
@ -35376,7 +35409,7 @@ __metadata:
ts-node-script: dist/bin-script.js
ts-node-transpile-only: dist/bin-transpile.js
ts-script: dist/bin-script-deprecated.js
checksum: d51ac8a9b3582ce3705cef8d35f3372e40caa277dbd7c7baeb651961538f13d2f11f22402614348f78d9b10501bd1cb5f05ec4f2ec9a74bd0e288de769c32335
checksum: bc7589d8c38dc75a2a6f832ac43faaac7edd3d0ef4643f46a9deeaabcdd35722e8c89e729fcd39a16069b30d09e297c2fb3eec917a82dd3f1e7da8b352bbd447
languageName: node
linkType: hard
@ -35400,6 +35433,43 @@ __metadata:
languageName: node
linkType: hard
"ts-node@npm:^10.2.1":
version: 10.5.0
resolution: "ts-node@npm:10.5.0"
dependencies:
"@cspotcode/source-map-support": 0.7.0
"@tsconfig/node10": ^1.0.7
"@tsconfig/node12": ^1.0.7
"@tsconfig/node14": ^1.0.0
"@tsconfig/node16": ^1.0.2
acorn: ^8.4.1
acorn-walk: ^8.1.1
arg: ^4.1.0
create-require: ^1.1.0
diff: ^4.0.1
make-error: ^1.1.1
v8-compile-cache-lib: ^3.0.0
yn: 3.1.1
peerDependencies:
"@swc/core": ">=1.2.50"
"@swc/wasm": ">=1.2.50"
"@types/node": "*"
typescript: ">=2.7"
peerDependenciesMeta:
"@swc/core":
optional: true
"@swc/wasm":
optional: true
bin:
ts-node: dist/bin.js
ts-node-cwd: dist/bin-cwd.js
ts-node-script: dist/bin-script.js
ts-node-transpile-only: dist/bin-transpile.js
ts-script: dist/bin-script-deprecated.js
checksum: d51ac8a9b3582ce3705cef8d35f3372e40caa277dbd7c7baeb651961538f13d2f11f22402614348f78d9b10501bd1cb5f05ec4f2ec9a74bd0e288de769c32335
languageName: node
linkType: hard
"ts-node@npm:^9":
version: 9.1.1
resolution: "ts-node@npm:9.1.1"

Loading…
Cancel
Save