Merge remote-tracking branch 'origin/main' into resource-store

This commit is contained in:
Ryan McKinley 2024-06-13 14:27:42 +03:00
commit c1798320d2
52 changed files with 775 additions and 69 deletions

1
.github/CODEOWNERS vendored
View File

@ -602,6 +602,7 @@ playwright.config.ts @grafana/plugins-platform-frontend
/pkg/services/anonymous/ @grafana/identity-access-team
/pkg/services/auth/ @grafana/identity-access-team
/pkg/services/authn/ @grafana/identity-access-team
/pkg/services/authz/ @grafana/identity-access-team
/pkg/services/signingkeys/ @grafana/identity-access-team
/pkg/services/dashboards/accesscontrol.go @grafana/identity-access-team
/pkg/services/datasources/guardian/ @grafana/identity-access-team

View File

@ -61,6 +61,7 @@ swagger-oss-gen: $(SWAGGER) ## Generate API Swagger specification
rm -f $(SPEC_TARGET)
SWAGGER_GENERATE_EXTENSION=false $(SWAGGER) generate spec -q -m -w pkg/server -o $(SPEC_TARGET) \
-x "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" \
-x "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" \
-x "github.com/prometheus/alertmanager" \
-i pkg/api/swagger_tags.json \
--exclude-tag=alpha \
@ -78,6 +79,7 @@ swagger-enterprise-gen: $(SWAGGER) ## Generate API Swagger specification
rm -f $(ENTERPRISE_SPEC_TARGET)
SWAGGER_GENERATE_EXTENSION=false $(SWAGGER) generate spec -q -m -w pkg/server -o $(ENTERPRISE_SPEC_TARGET) \
-x "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" \
-x "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" \
-x "github.com/prometheus/alertmanager" \
-i pkg/api/swagger_tags.json \
--exclude-tag=alpha \

View File

@ -79,7 +79,7 @@ cards:
## Overview
_Grafana Open Source Software (OSS)_ enables you to query, visualize, alert on, and explore your metrics, logs, and traces wherever they're stored. Grafana OSS provides you with tools to turn your time-series database (TSDB) data into insightful graphs and visualizations. The Grafana OSS plugin framework also enables you to connect other data sources like NoSQL/SQL databases, ticketing tools like Jira or ServiceNow, and CI/CD tooling like GitLab.
_Grafana Open Source Software (OSS)_ enables you to query, visualize, alert on, and explore your metrics, logs, and traces wherever they're stored. Grafana data source plugins enable you to query data sources including time series databases like Prometheus and CloudWatch, logging tools like Loki and Elasticsearch, NoSQL/SQL databases like Postgres, CI/CD tooling like GitHub, and many more. Grafana OSS provides you with tools to display that data on live dashboards with insightful graphs and visualizations.
_Grafana Enterprise_ is a commercial edition of Grafana that includes exclusive data source plugins and additional features not found in the open source version. You also get 24x7x365 support and training from the core Grafana team.
To learn more about these features, refer to [Enterprise features](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/introduction/grafana-enterprise/#enterprise-features-in-grafana-cloud).

View File

@ -33,7 +33,7 @@ refs:
# Group alert notifications
Grouping is an important feature of Grafana Alerting as it allows you to batch relevant alerts together into a smaller number of notifications. This is particularly important if notifications are delivered to first-responders, such as engineers on-call, where receiving lots of notifications in a short period of time can be overwhelming and in some cases can negatively impact a first-responders ability to respond to an incident. For example, consider a large outage where many of your systems are down. In this case, grouping can be the difference between receiving 1 phone call and 100 phone calls.
Grouping in Grafana Alerting allows you to batch relevant alerts together into a smaller number of notifications. This is particularly important if notifications are delivered to first-responders, such as engineers on-call, where receiving lots of notifications in a short period of time can be overwhelming. In some cases, it can negatively impact a first-responders ability to respond to an incident. For example, consider a large outage where many of your systems are down. In this case, grouping can be the difference between receiving 1 phone call and 100 phone calls.
## Group notifications
@ -42,7 +42,7 @@ Grouping combines similar alert instances within a specific period into a single
In the notification policy, you can configure how to group multiple alerts into a single notification:
- The `Group by` option specifies the criteria for grouping incoming alerts within the policy. The default is by alert rule.
- [Timing options](#timing-options) determine when to sent the notification.
- [Timing options](#timing-options) determine when and how often to send the notification.
{{< figure src="/media/docs/alerting/alerting-notification-policy-diagram-with-labels-v3.png" max-width="750px" alt="A diagram about the components of a notification policy, including labels and groups" >}}
@ -65,7 +65,7 @@ If you want to group all alerts handled by the notification policy in a single g
### Disable grouping
If you want to receive every alert as a separate notification, you can do so by grouping by a special label called `...`.
If you want to receive every alert as a separate notification, you can do so by grouping by a special label called `...`, ensuring that other labels are not present.
## Timing options
@ -101,7 +101,7 @@ The longer the group wait, the more time other alerts have to be included in the
Consider a notification policy that:
- Matches all alert instances with the `team` label—matching labels equals to `team=~".*"`.
- Matches all alert instances with the `team` label—matching labels equals to `team=~.+`.
- Groups notifications by the `team` label—one group for each distinct `team`.
- Sets the Group wait timer to `30s`.

View File

@ -88,7 +88,7 @@ The `team=security` policy is not a match and **Continue matching siblings** was
{{< /collapse >}}
This routing and tree structure make it easy to organize and handle alerts for dedicated teams, while also narrowing down specific cases within the team by applying additional labels.
This routing and tree structure makes it convenient to organize and handle alerts for dedicated teams, while also narrowing down specific cases within the team by applying additional labels.
## Inheritance

8
go.mod
View File

@ -87,7 +87,7 @@ require (
github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group
github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad
github.com/grafana/alerting v0.0.0-20240606211712-071c8609797a // @grafana/alerting-backend
github.com/grafana/authlib v0.0.0-20240515154731-fe4779055ef4 // @grafana/identity-access-team
github.com/grafana/authlib v0.0.0-20240611075137-331cbe4e840f // @grafana/identity-access-team
github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad
github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code
github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics
@ -320,7 +320,7 @@ require (
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect
github.com/grafana/sqlds/v3 v3.2.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect; @grafana/plugins-platform-backend
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-msgpack v0.5.5 // indirect
@ -437,8 +437,8 @@ require (
golang.org/x/term v0.21.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect; @grafana/grafana-backend-group
google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect

16
go.sum
View File

@ -2307,8 +2307,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grafana/alerting v0.0.0-20240606211712-071c8609797a h1:MvrEgxNxmUqaFWkBtRlbgxStbdD8FcmtjlRp98bmMJU=
github.com/grafana/alerting v0.0.0-20240606211712-071c8609797a/go.mod h1:U7Ta3K4T7jVgqGSYuPsfuPKHFiL2GbCZSHa3nHjmCos=
github.com/grafana/authlib v0.0.0-20240515154731-fe4779055ef4 h1:Bfa397TXkM0X97MhbCC+fNSwVtg21c0Mg5STes1dRug=
github.com/grafana/authlib v0.0.0-20240515154731-fe4779055ef4/go.mod h1:86rRD5P6u2JPWtNWTMOlqlU+YMv2fUvVz/DomA6L7w4=
github.com/grafana/authlib v0.0.0-20240611075137-331cbe4e840f h1:hvRCAv+TgcHu3i/Sd7lFJx84iEtgzDCYuk7OWeXatD0=
github.com/grafana/authlib v0.0.0-20240611075137-331cbe4e840f/go.mod h1:+MjD5sxxgLOIvw0ox18wJmjBzz8tOECo7quiiZAmgJY=
github.com/grafana/codejen v0.0.3 h1:tAWxoTUuhgmEqxJPOLtJoxlPBbMULFwKFOcRsPRPXDw=
github.com/grafana/codejen v0.0.3/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s=
github.com/grafana/cue v0.0.0-20230926092038-971951014e3f h1:TmYAMnqg3d5KYEAaT6PtTguL2GjLfvr6wnAX8Azw6tQ=
@ -2380,8 +2380,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4Zs
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=
github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc=
@ -4381,8 +4381,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go.
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y=
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w=
google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 h1:DTJM0R8LECCgFeUwApvcEJHz85HLagW8uRENYxHh1ww=
google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw=
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw=
@ -4427,8 +4427,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415141817-7cd4c1c1f9ec/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=

View File

@ -555,6 +555,7 @@ github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240612101930-58f7032b3983/g
github.com/grafana/grafana/pkg/promlib v0.0.3/go.mod h1:3El4NlsfALz8QQCbEGHGFvJUG+538QLMuALRhZ3pcoo=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
@ -959,12 +960,17 @@ google.golang.org/api v0.166.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas=
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20231120223509-83a465c0220f h1:hL+1ptbhFoeL1HcROQ8OGXaqH0jYRRibgWQWco0/Ugc=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20231212172506-995d672761c0 h1:Y6QQt9D/syZt/Qgnz5a1y2O3WunQeeVDfS9+Xr82iFA=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240125205218-1f4bbc51befe h1:weYsP+dNijSQVoLAb5bpUos3ciBpNU/NEVlHFKrk8pg=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240325203815-454cdb8f5daa h1:wBkzraZsSqhj1M4L/nMrljUU6XasJkgHvUsq8oRGwF0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/cheggaaa/pb.v1 v1.0.25 h1:Ev7yu1/f6+d+b3pi5vPdRPc6nNtP1umSfcWiEfRqv6I=

View File

@ -247,7 +247,7 @@
"@grafana/azure-sdk": "0.0.3",
"@grafana/data": "workspace:*",
"@grafana/e2e-selectors": "workspace:*",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/faro-core": "^1.3.6",
"@grafana/faro-web-sdk": "^1.3.6",
"@grafana/flamegraph": "workspace:*",

View File

@ -193,4 +193,5 @@ export interface FeatureToggles {
pluginProxyPreserveTrailingSlash?: boolean;
azureMonitorPrometheusExemplars?: boolean;
pinNavItems?: boolean;
authZGRPCServer?: boolean;
}

View File

@ -20,7 +20,7 @@
"@emotion/css": "11.11.2",
"@grafana/data": "11.0.0",
"@grafana/e2e-selectors": "11.0.0",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/runtime": "11.0.0",
"@grafana/schema": "11.0.0",
"@grafana/ui": "11.0.0",

View File

@ -39,7 +39,7 @@
"@emotion/css": "11.11.2",
"@floating-ui/react": "0.26.16",
"@grafana/data": "11.0.0",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/faro-web-sdk": "1.7.3",
"@grafana/runtime": "11.0.0",
"@grafana/schema": "11.0.0",

View File

@ -17,7 +17,7 @@
"@emotion/css": "11.11.2",
"@grafana/data": "11.0.0",
"@grafana/e2e-selectors": "11.0.0",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/runtime": "11.0.0",
"@grafana/ui": "11.0.0",
"@react-awesome-query-builder/ui": "6.5.2",

View File

@ -64,7 +64,7 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.6.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
@ -139,8 +139,8 @@ require (
golang.org/x/tools v0.22.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/grpc v1.64.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect

View File

@ -128,7 +128,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI=
@ -401,8 +401,8 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 h1:DTJM0R8LECCgFeUwApvcEJHz85HLagW8uRENYxHh1ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU=
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=

View File

@ -55,7 +55,7 @@ require (
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.6.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
@ -111,8 +111,8 @@ require (
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.22.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/grpc v1.64.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect

View File

@ -85,7 +85,7 @@ github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db h1:7aN5cccjIqCLTzed
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI=
@ -277,8 +277,8 @@ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSm
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o=
gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY=
google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 h1:DTJM0R8LECCgFeUwApvcEJHz85HLagW8uRENYxHh1ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU=
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -13,6 +13,7 @@ import (
grafanaapiserver "github.com/grafana/grafana/pkg/services/apiserver"
"github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/authn/authnimpl"
"github.com/grafana/grafana/pkg/services/authz"
"github.com/grafana/grafana/pkg/services/cleanup"
"github.com/grafana/grafana/pkg/services/cloudmigration"
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
@ -67,8 +68,8 @@ func ProvideBackgroundServiceRegistry(
_ dashboardsnapshots.Service,
_ serviceaccounts.Service, _ *guardian.Provider,
_ *plugindashboardsservice.DashboardUpdater, _ *sanitizer.Provider,
_ *grpcserver.HealthService, _ entity.EntityStoreServer, _ *grpcserver.ReflectionService, _ *ldapapi.Service,
_ *apiregistry.Service, _ auth.IDService, _ *teamapi.TeamAPI, _ ssosettings.Service,
_ *grpcserver.HealthService, _ entity.EntityStoreServer, _ authz.Client, _ *grpcserver.ReflectionService,
_ *ldapapi.Service, _ *apiregistry.Service, _ auth.IDService, _ *teamapi.TeamAPI, _ ssosettings.Service,
_ cloudmigration.Service, _ authnimpl.Registration,
) *BackgroundServiceRegistry {
return NewBackgroundServiceRegistry(

View File

@ -50,6 +50,7 @@ import (
"github.com/grafana/grafana/pkg/services/auth/idimpl"
"github.com/grafana/grafana/pkg/services/auth/jwt"
"github.com/grafana/grafana/pkg/services/authn/authnimpl"
"github.com/grafana/grafana/pkg/services/authz"
"github.com/grafana/grafana/pkg/services/cleanup"
"github.com/grafana/grafana/pkg/services/cloudmigration/cloudmigrationimpl"
"github.com/grafana/grafana/pkg/services/contexthandler"
@ -379,6 +380,7 @@ var wireBasicSet = wire.NewSet(
userimpl.ProvideVerifier,
connectors.ProvideOrgRoleMapper,
wire.Bind(new(user.Verifier), new(*userimpl.Verifier)),
authz.WireSet,
// Kubernetes API server
grafanaapiserver.WireSet,
apiregistry.WireSet,

View File

@ -707,7 +707,7 @@ func (s *store) createPermissions(sess *db.Session, roleID int64, cmd SetResourc
}
func (s *store) shouldStoreActionSet(permission string) bool {
return (s.features.IsEnabled(context.TODO(), featuremgmt.FlagAccessActionSets) && permission != "")
return (s.features.IsEnabled(context.TODO(), featuremgmt.FlagAccessActionSets) && permission != "" && isFolderOrDashboardAction(permission))
}
func deletePermissions(sess *db.Session, ids []int64) error {

View File

@ -0,0 +1,3 @@
# Authorization
This package contains the authorization server implementation.

View File

@ -0,0 +1,33 @@
package authz
import (
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/grpcserver"
"github.com/grafana/grafana/pkg/setting"
)
type Client interface {
// TODO
}
type LegacyClient struct {
}
func ProvideAuthZClient(
cfg *setting.Cfg, features featuremgmt.FeatureToggles, acSvc accesscontrol.Service,
grpcServer grpcserver.Provider, tracer tracing.Tracer,
) (Client, error) {
if !features.IsEnabledGlobally(featuremgmt.FlagAuthZGRPCServer) {
return nil, nil
}
_, err := newLegacyServer(acSvc, features, grpcServer, tracer)
if err != nil {
return nil, err
}
// TODO differentiate run local from run remote grpc
return &LegacyClient{}, nil
}

View File

@ -0,0 +1,66 @@
package authz
import (
"context"
authzv1 "github.com/grafana/authlib/authz/proto/v1"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/grpcserver"
)
var _ authzv1.AuthzServiceServer = (*legacyServer)(nil)
type legacyServer struct {
authzv1.UnimplementedAuthzServiceServer
acSvc accesscontrol.Service
logger log.Logger
tracer tracing.Tracer
}
func newLegacyServer(
acSvc accesscontrol.Service, features featuremgmt.FeatureToggles,
grpcServer grpcserver.Provider, tracer tracing.Tracer,
) (*legacyServer, error) {
if !features.IsEnabledGlobally(featuremgmt.FlagAuthZGRPCServer) {
return nil, nil
}
s := &legacyServer{
acSvc: acSvc,
logger: log.New("authz-grpc-server"),
tracer: tracer,
}
grpcServer.GetServer().RegisterService(&authzv1.AuthzService_ServiceDesc, s)
return s, nil
}
func (s *legacyServer) Read(ctx context.Context, req *authzv1.ReadRequest) (*authzv1.ReadResponse, error) {
ctx, span := s.tracer.Start(ctx, "authz.grpc.Read")
defer span.End()
action := req.GetAction()
subject := req.GetSubject()
stackID := req.GetStackId() // TODO can we consider the stackID as the orgID?
ctxLogger := s.logger.FromContext(ctx)
ctxLogger.Debug("Read", "action", action, "subject", subject, "stackID", stackID)
permissions, err := s.acSvc.SearchUserPermissions(ctx, stackID, accesscontrol.SearchOptions{NamespacedID: subject, Action: action})
if err != nil {
ctxLogger.Error("failed to search user permissions", "error", err)
return nil, tracing.Errorf(span, "failed to search user permissions: %w", err)
}
data := make([]*authzv1.ReadResponse_Data, 0, len(permissions))
for _, perm := range permissions {
data = append(data, &authzv1.ReadResponse_Data{Object: perm.Scope})
}
return &authzv1.ReadResponse{Data: data}, nil
}

View File

@ -0,0 +1,9 @@
package authz
import (
"github.com/google/wire"
)
var WireSet = wire.NewSet(
ProvideAuthZClient,
)

View File

@ -1308,6 +1308,14 @@ var (
Stage: FeatureStageExperimental,
Owner: grafanaFrontendPlatformSquad,
},
{
Name: "authZGRPCServer",
Description: "Enables the gRPC server for authorization",
Stage: FeatureStageExperimental,
Owner: identityAccessTeam,
HideFromAdminPage: true,
HideFromDocs: true,
},
}
)

View File

@ -174,3 +174,4 @@ alertingCentralAlertHistory,experimental,@grafana/alerting-squad,false,false,tru
pluginProxyPreserveTrailingSlash,GA,@grafana/plugins-platform-backend,false,false,false
azureMonitorPrometheusExemplars,experimental,@grafana/partner-datasources,false,false,false
pinNavItems,experimental,@grafana/grafana-frontend-platform,false,false,false
authZGRPCServer,experimental,@grafana/identity-access-team,false,false,false

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
174 pluginProxyPreserveTrailingSlash GA @grafana/plugins-platform-backend false false false
175 azureMonitorPrometheusExemplars experimental @grafana/partner-datasources false false false
176 pinNavItems experimental @grafana/grafana-frontend-platform false false false
177 authZGRPCServer experimental @grafana/identity-access-team false false false

View File

@ -706,4 +706,8 @@ const (
// FlagPinNavItems
// Enables pinning of nav items
FlagPinNavItems = "pinNavItems"
// FlagAuthZGRPCServer
// Enables the gRPC server for authorization
FlagAuthZGRPCServer = "authZGRPCServer"
)

View File

@ -2264,6 +2264,20 @@
"stage": "experimental",
"codeowner": "@grafana/grafana-frontend-platform"
}
},
{
"metadata": {
"name": "authZGRPCServer",
"resourceVersion": "1718093439898",
"creationTimestamp": "2024-06-11T08:10:39Z"
},
"spec": {
"description": "Enables the gRPC server for authorization",
"stage": "experimental",
"codeowner": "@grafana/identity-access-team",
"hideFromAdminPage": true,
"hideFromDocs": true
}
}
]
}

View File

@ -53,6 +53,10 @@ interface ImportOptions {
folderUid: string;
}
interface RestoreDashboardArgs {
dashboardUID: string;
}
function createBackendSrvBaseQuery({ baseURL }: { baseURL: string }): BaseQueryFn<RequestOptions> {
async function backendSrvBaseQuery(requestOptions: RequestOptions) {
try {
@ -148,6 +152,7 @@ export const browseDashboardsAPI = createApi({
});
},
}),
// move an *individual* folder. used in the folder actions menu.
moveFolder: builder.mutation<void, { folder: FolderDTO; destinationUID: string }>({
invalidatesTags: ['getFolder'],
@ -174,6 +179,7 @@ export const browseDashboardsAPI = createApi({
});
},
}),
// delete an *individual* folder. used in the folder actions menu.
deleteFolder: builder.mutation<void, FolderDTO>({
query: ({ uid }) => ({
@ -196,6 +202,7 @@ export const browseDashboardsAPI = createApi({
});
},
}),
// gets the descendant counts for a folder. used in the move/delete modals.
getAffectedItems: builder.query<DescendantCount, DashboardTreeSelection>({
queryFn: async (selectedItems) => {
@ -225,6 +232,7 @@ export const browseDashboardsAPI = createApi({
return { data: totalCounts };
},
}),
// move *multiple* items (folders and dashboards). used in the move modal.
moveItems: builder.mutation<void, MoveItemsArgs>({
invalidatesTags: ['getFolder'],
@ -276,6 +284,7 @@ export const browseDashboardsAPI = createApi({
});
},
}),
// delete *multiple* items (folders and dashboards). used in the delete modal.
deleteItems: builder.mutation<void, DeleteItemsArgs>({
queryFn: async ({ selectedItems }, _api, _extraOptions, baseQuery) => {
@ -313,6 +322,7 @@ export const browseDashboardsAPI = createApi({
});
},
}),
// save an existing dashboard
saveDashboard: builder.mutation<SaveDashboardResponseDTO, SaveDashboardCommand>({
query: ({ dashboard, folderUid, message, overwrite, showErrorAlert }) => ({
@ -339,6 +349,7 @@ export const browseDashboardsAPI = createApi({
});
},
}),
importDashboard: builder.mutation<ImportDashboardResponseDTO, ImportOptions>({
query: ({ dashboard, overwrite, inputs, folderUid }) => ({
method: 'POST',
@ -363,6 +374,19 @@ export const browseDashboardsAPI = createApi({
});
},
}),
// restore a dashboard that got soft deleted
restoreDashboard: builder.mutation<void, RestoreDashboardArgs>({
query: ({ dashboardUID }) => ({
url: `/dashboards/uid/${dashboardUID}/trash`,
method: 'PATCH',
}),
onQueryStarted: ({ dashboardUID }, { queryFulfilled, dispatch }) => {
queryFulfilled.then(() => {
dispatch(refreshParents([dashboardUID]));
});
},
}),
}),
});
@ -377,6 +401,7 @@ export const {
useNewFolderMutation,
useSaveDashboardMutation,
useSaveFolderMutation,
useRestoreDashboardMutation,
} = browseDashboardsAPI;
export { skipToken } from '@reduxjs/toolkit/query/react';

View File

@ -753,6 +753,20 @@ describe('DashboardScene', () => {
expect(gridItem.state.body!.state.key).toBe('panel-7');
});
it('Should maintain size of duplicated panel', () => {
const gItem = (scene.state.body as SceneGridLayout).state.children[0] as DashboardGridItem;
gItem.setState({ height: 1 });
const vizPanel = gItem.state.body;
scene.duplicatePanel(vizPanel as VizPanel);
const body = scene.state.body as SceneGridLayout;
const newGridItem = body.state.children[5] as DashboardGridItem;
expect(body.state.children.length).toBe(6);
expect(newGridItem.state.body!.state.key).toBe('panel-7');
expect(newGridItem.state.height).toBe(1);
});
it('Should duplicate a library panel', () => {
const libraryPanel = ((scene.state.body as SceneGridLayout).state.children[4] as DashboardGridItem).state.body;
const vizPanel = (libraryPanel as LibraryVizPanel).state.panel;

View File

@ -594,8 +594,8 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
newGridItem = new DashboardGridItem({
x: gridItem.state.x,
y: gridItem.state.y,
height: NEW_PANEL_HEIGHT,
width: NEW_PANEL_WIDTH,
height: gridItem.state.height,
width: gridItem.state.width,
body: new VizPanel({ ...panelState, $data: panelData, key: getVizPanelKeyForPanelId(newPanelId) }),
});
}

View File

@ -38,10 +38,25 @@ describe('inspector download', () => {
const filename = call[1];
const text = await blob.text();
// By default the BOM character should not be included
expect(await hasBOM(blob)).toBe(false);
expect(text).toEqual(expected);
expect(filename).toEqual(`${title}-data-${dateTimeFormat(1400000000000)}.csv`);
}
);
it('should include the BOM character when useExcelHeader is true', async () => {
downloadDataFrameAsCsv(dataFrameFromJSON(json), 'test', { useExcelHeader: true });
const call = (saveAs as unknown as jest.Mock).mock.calls[0];
const blob = call[0];
const filename = call[1];
const text = await blob.text();
expect(await hasBOM(blob)).toBe(true);
expect(text).toEqual('sep=,\r\n"time","name","value"\r\n100,a,1');
expect(filename).toEqual(`test-data-${dateTimeFormat(1400000000000)}.csv`);
});
});
describe('downloadAsJson', () => {
@ -104,3 +119,19 @@ describe('inspector download', () => {
});
});
});
async function hasBOM(blob: Blob) {
const reader = new FileReader();
return new Promise<boolean>((resolve, reject) => {
reader.onload = (event: ProgressEvent<FileReader>) => {
if (event.target?.result instanceof ArrayBuffer) {
const arr = new Uint8Array(event.target.result);
resolve(arr[0] === 0xef && arr[1] === 0xbb && arr[2] === 0xbf); // Check for UTF-8 BOM
} else {
reject(new Error('Unexpected FileReader result type'));
}
};
reader.onerror = reject;
reader.readAsArrayBuffer(blob.slice(0, 3)); // Read only the first 3 bytes
});
}

View File

@ -57,8 +57,9 @@ export function downloadDataFrameAsCsv(
transformId: DataTransformerID = DataTransformerID.noop
) {
const dataFrameCsv = toCSV([dataFrame], csvConfig);
const bomChar = csvConfig?.useExcelHeader ? String.fromCharCode(0xfeff) : '';
const blob = new Blob([String.fromCharCode(0xfeff), dataFrameCsv], {
const blob = new Blob([bomChar, dataFrameCsv], {
type: 'text/csv;charset=utf-8',
});

View File

@ -10,6 +10,7 @@ import { SearchView } from '../browse-dashboards/components/SearchView';
import { getFolderPermissions } from '../browse-dashboards/permissions';
import { setAllSelection } from '../browse-dashboards/state';
import { RecentlyDeletedActions } from './state/RecentlyDeletedActions';
import { useRecentlyDeletedStateManager } from './utils/useRecentlyDeletedStateManager';
const RecentlyDeletedPage = memo(() => {
@ -47,6 +48,7 @@ const RecentlyDeletedPage = memo(() => {
onPanelTypeChange={stateManager.onPanelTypeChange}
onSetIncludePanels={stateManager.onSetIncludePanels}
/>
<RecentlyDeletedActions />
<AutoSizer>
{({ width, height }) => (
<SearchView

View File

@ -0,0 +1,44 @@
import React from 'react';
import { ConfirmModal, Text } from '@grafana/ui';
import { Trans, t } from '../../../core/internationalization';
import { DashboardTreeSelection } from '../../browse-dashboards/types';
interface Props {
isOpen: boolean;
onConfirm: () => Promise<void>;
onDismiss: () => void;
selectedItems: DashboardTreeSelection;
isLoading: boolean;
}
export const RestoreModal = ({ onConfirm, onDismiss, selectedItems, isLoading, ...props }: Props) => {
const numberOfDashboards = selectedItems ? Object.keys(selectedItems.dashboard).length : 0;
const onRestore = async () => {
await onConfirm();
onDismiss();
};
return (
<ConfirmModal
body={
<Text element="p">
<Trans i18nKey="recently-deleted.restore-modal.text" count={numberOfDashboards}>
This action will restore {{ numberOfDashboards }} dashboards.
</Trans>
</Text>
// TODO: replace by list of dashboards (list up to 5 dashboards) or number (from 6 dashboards)?
}
confirmText={
isLoading
? t('recently-deleted.restore-modal.restore-loading', 'Restoring...')
: t('recently-deleted.restore-modal.restore-button', 'Restore')
}
confirmButtonVariant="primary"
onDismiss={onDismiss}
onConfirm={onRestore}
title={t('recently-deleted.restore-modal.title', 'Restore Dashboards')}
{...props}
/>
);
};

View File

@ -0,0 +1,65 @@
import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/';
import { Button, useStyles2 } from '@grafana/ui';
import appEvents from '../../../core/app_events';
import { Trans } from '../../../core/internationalization';
import { useDispatch } from '../../../types';
import { ShowModalReactEvent } from '../../../types/events';
import { useRestoreDashboardMutation } from '../../browse-dashboards/api/browseDashboardsAPI';
import { setAllSelection, useActionSelectionState } from '../../browse-dashboards/state';
import { RestoreModal } from '../components/RestoreModal';
import { useRecentlyDeletedStateManager } from '../utils/useRecentlyDeletedStateManager';
export function RecentlyDeletedActions() {
const styles = useStyles2(getStyles);
const dispatch = useDispatch();
const selectedItems = useActionSelectionState();
const [, stateManager] = useRecentlyDeletedStateManager();
const [restoreDashboard, { isLoading: isRestoreLoading }] = useRestoreDashboardMutation();
const onActionComplete = () => {
dispatch(setAllSelection({ isSelected: false, folderUID: undefined }));
stateManager.doSearchWithDebounce();
};
const onRestore = async () => {
const promises = Object.entries(selectedItems.dashboard)
.filter(([_, selected]) => selected)
.map(([uid]) => restoreDashboard({ dashboardUID: uid }));
await Promise.all(promises);
onActionComplete();
};
const showRestoreModal = () => {
appEvents.publish(
new ShowModalReactEvent({
component: RestoreModal,
props: {
selectedItems,
onConfirm: onRestore,
isLoading: isRestoreLoading,
},
})
);
};
return (
<div className={styles.row}>
<Button onClick={showRestoreModal} variant="secondary">
<Trans i18nKey="recently-deleted.buttons.restore">Restore</Trans>
</Button>
</div>
);
}
const getStyles = (theme: GrafanaTheme2) => ({
row: css({
marginBottom: theme.spacing(2),
}),
});

View File

@ -6,7 +6,7 @@
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.0.0",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/runtime": "11.0.0",
"@grafana/schema": "11.0.0",
"@grafana/ui": "11.0.0",

View File

@ -6,7 +6,7 @@
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.0.0",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/google-sdk": "0.1.2",
"@grafana/runtime": "11.0.0",
"@grafana/schema": "11.0.0",

View File

@ -6,7 +6,7 @@
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.0.0",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/runtime": "11.0.0",
"@grafana/sql": "11.0.0",
"@grafana/ui": "11.0.0",

View File

@ -6,7 +6,7 @@
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.0.0",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/runtime": "11.0.0",
"@grafana/schema": "11.0.0",
"@grafana/ui": "11.0.0",

View File

@ -7,7 +7,7 @@
"@emotion/css": "11.11.2",
"@grafana/data": "workspace:*",
"@grafana/e2e-selectors": "workspace:*",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/o11y-ds-frontend": "workspace:*",
"@grafana/runtime": "workspace:*",
"@grafana/ui": "workspace:*",

View File

@ -6,7 +6,7 @@
"dependencies": {
"@emotion/css": "11.11.2",
"@grafana/data": "11.0.0",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/runtime": "11.0.0",
"@grafana/sql": "11.0.0",
"@grafana/ui": "11.0.0",

View File

@ -7,7 +7,7 @@
"@emotion/css": "11.11.2",
"@grafana/data": "workspace:*",
"@grafana/e2e-selectors": "workspace:*",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/lezer-logql": "0.2.4",
"@grafana/lezer-traceql": "0.0.17",
"@grafana/monaco-logql": "^0.0.7",

View File

@ -7,7 +7,7 @@
"@emotion/css": "11.11.2",
"@grafana/data": "workspace:*",
"@grafana/e2e-selectors": "workspace:*",
"@grafana/experimental": "1.7.11",
"@grafana/experimental": "1.7.12",
"@grafana/o11y-ds-frontend": "workspace:*",
"@grafana/runtime": "workspace:*",
"@grafana/ui": "workspace:*",

View File

@ -1384,6 +1384,16 @@
"revoke-public-URL-button-title": "Öffentliche URL widerrufen",
"settings-title": "Einstellungen"
},
"configuration": {
"display-annotations-label": "",
"enable-time-range-label": "",
"settings-label": "",
"success-pause": "",
"success-resume": "",
"success-update": "",
"success-update-old": "",
"time-range-tooltip": ""
},
"create-page": {
"generate-public-url-button": "Öffentliche URL generieren",
"unsupported-features-desc": "Momentan unterstützen wir keine Template-Variablen oder Frontend-Datenquellen",
@ -1395,15 +1405,32 @@
"revoke-title": "Öffentliche URL widerrufen"
},
"email-sharing": {
"accept-button": "",
"alert-text": "",
"bill-ack": "",
"cancel-button": "",
"input-invalid-email-text": "Ungültige E-Mail",
"input-required-email-text": "E-Mail-Adresse ist erforderlich",
"invite-button": "Einladen",
"invite-field-desc": "Personen per E-Mail einladen",
"invite-field-label": "Einladen",
"learn-more-button": "",
"recipient-email-placeholder": "",
"recipient-invalid-email-text": "",
"recipient-invitation-button": "",
"recipient-invitation-description": "",
"recipient-invitation-tooltip": "",
"recipient-list-description": "",
"recipient-list-title": "",
"recipient-required-email-text": "",
"resend-button": "Erneut senden",
"resend-button-title": "Erneut senden",
"resend-invite-label": "",
"revoke-access-label": "",
"revoke-button": "Widerrufen",
"revoke-button-title": "Widerrufen"
"revoke-button-title": "Widerrufen",
"success-creation": "",
"success-share-type-change": ""
},
"modal-alerts": {
"no-upsert-perm-alert-desc": "Kontaktieren Sie Ihren Administrator, um die Berechtigung zu {{mode}} öffentlichen Dashboards zu erhalten",
@ -1415,6 +1442,15 @@
"unsupported-template-variable-alert-desc": "Dieses öffentliche Dashboard funktioniert möglicherweise nicht, da es Template-Variablen verwendet",
"unsupported-template-variable-alert-title": "Template-Variablen werden nicht unterstützt"
},
"public-sharing": {
"accept-button": "",
"alert-text": "",
"cancel-button": "",
"learn-more-button": "",
"public-ack": "",
"success-creation": "",
"success-share-type-change": ""
},
"settings-bar-header": {
"collapse-settings-tooltip": "Einstellungen einklappen",
"expand-settings-tooltip": "Einstellungen aufklappen"
@ -1433,6 +1469,28 @@
"time-range-picker-disabled-text": "Zeitraumauswahl = deaktiviert",
"time-range-picker-enabled-text": "Zeitraumauswahl = aktiviert",
"time-range-text": "Zeitraum = "
},
"share": {
"success-delete": "",
"success-delete-old": ""
},
"share-configuration": {
"access-label": "",
"share-type-label": ""
},
"share-externally": {
"copy-link-button": "",
"email-share-type-option-description": "",
"email-share-type-option-label": "",
"pause-access-button": "",
"pause-access-tooltip": "",
"public-share-type-option-description": "",
"public-share-type-option-label": "",
"resume-access-button": "",
"revoke-access-button": ""
},
"sharing": {
"success-creation": ""
}
},
"public-dashboard-list": {
@ -1495,6 +1553,18 @@
},
"query-editor-not-exported": "Datenquellen-Plugin exportiert keine Komponente des Abfrageeditors"
},
"recently-deleted": {
"buttons": {
"restore": ""
},
"restore-modal": {
"restore-button": "",
"restore-loading": "",
"title": "",
"text_one": "",
"text_other": ""
}
},
"refresh-picker": {
"aria-label": {
"choose-interval": "Automatische Aktualisierung ausgeschaltet. Aktualisierungszeitintervall auswählen",

View File

@ -1553,6 +1553,18 @@
},
"query-editor-not-exported": "Data source plugin does not export any Query Editor component"
},
"recently-deleted": {
"buttons": {
"restore": "Restore"
},
"restore-modal": {
"restore-button": "Restore",
"restore-loading": "Restoring...",
"text_one": "This action will restore {{numberOfDashboards}} dashboard.",
"text_other": "This action will restore {{numberOfDashboards}} dashboards.",
"title": "Restore Dashboards"
}
},
"refresh-picker": {
"aria-label": {
"choose-interval": "Auto refresh turned off. Choose refresh time interval",

View File

@ -1384,6 +1384,16 @@
"revoke-public-URL-button-title": "Revocar URL pública",
"settings-title": "Configuración"
},
"configuration": {
"display-annotations-label": "",
"enable-time-range-label": "",
"settings-label": "",
"success-pause": "",
"success-resume": "",
"success-update": "",
"success-update-old": "",
"time-range-tooltip": ""
},
"create-page": {
"generate-public-url-button": "Generar URL pública",
"unsupported-features-desc": "Actualmente, no son compatibles las variables de plantillas o las fuentes de datos de la interfaz",
@ -1395,15 +1405,32 @@
"revoke-title": "Revocar URL pública"
},
"email-sharing": {
"accept-button": "",
"alert-text": "",
"bill-ack": "",
"cancel-button": "",
"input-invalid-email-text": "Correo no válido",
"input-required-email-text": "El correo electrónico es obligatorio",
"invite-button": "Invitar",
"invite-field-desc": "Invitar a otras personas por correo electrónico",
"invite-field-label": "Invitar",
"learn-more-button": "",
"recipient-email-placeholder": "",
"recipient-invalid-email-text": "",
"recipient-invitation-button": "",
"recipient-invitation-description": "",
"recipient-invitation-tooltip": "",
"recipient-list-description": "",
"recipient-list-title": "",
"recipient-required-email-text": "",
"resend-button": "Reenviar",
"resend-button-title": "Reenviar",
"resend-invite-label": "",
"revoke-access-label": "",
"revoke-button": "Revocar",
"revoke-button-title": "Revocar"
"revoke-button-title": "Revocar",
"success-creation": "",
"success-share-type-change": ""
},
"modal-alerts": {
"no-upsert-perm-alert-desc": "Ponte en contacto con tu administrador para obtener permiso para {{mode}} los tableros públicos",
@ -1415,6 +1442,15 @@
"unsupported-template-variable-alert-desc": "Este tablero público puede que no funcione, ya que utiliza variables de plantillas",
"unsupported-template-variable-alert-title": "Las variables de plantillas no son compatibles"
},
"public-sharing": {
"accept-button": "",
"alert-text": "",
"cancel-button": "",
"learn-more-button": "",
"public-ack": "",
"success-creation": "",
"success-share-type-change": ""
},
"settings-bar-header": {
"collapse-settings-tooltip": "Contraer ajustes",
"expand-settings-tooltip": "Expandir ajustes"
@ -1433,6 +1469,28 @@
"time-range-picker-disabled-text": "Selector de rango de tiempo = desactivado",
"time-range-picker-enabled-text": "Selector de rango de tiempo = activado",
"time-range-text": "Rango de tiempo = "
},
"share": {
"success-delete": "",
"success-delete-old": ""
},
"share-configuration": {
"access-label": "",
"share-type-label": ""
},
"share-externally": {
"copy-link-button": "",
"email-share-type-option-description": "",
"email-share-type-option-label": "",
"pause-access-button": "",
"pause-access-tooltip": "",
"public-share-type-option-description": "",
"public-share-type-option-label": "",
"resume-access-button": "",
"revoke-access-button": ""
},
"sharing": {
"success-creation": ""
}
},
"public-dashboard-list": {
@ -1495,6 +1553,18 @@
},
"query-editor-not-exported": "El complemento de la fuente de datos no exporta ningún componente del editor de consultas"
},
"recently-deleted": {
"buttons": {
"restore": ""
},
"restore-modal": {
"restore-button": "",
"restore-loading": "",
"title": "",
"text_one": "",
"text_other": ""
}
},
"refresh-picker": {
"aria-label": {
"choose-interval": "Actualización automática desactivada. Elija un intervalo de tiempo de actualización",

View File

@ -1384,6 +1384,16 @@
"revoke-public-URL-button-title": "Désactiver l'URL publique",
"settings-title": "Paramètres"
},
"configuration": {
"display-annotations-label": "",
"enable-time-range-label": "",
"settings-label": "",
"success-pause": "",
"success-resume": "",
"success-update": "",
"success-update-old": "",
"time-range-tooltip": ""
},
"create-page": {
"generate-public-url-button": "Générer une URL publique",
"unsupported-features-desc": "Actuellement, nous ne prenons pas en charge les variables de modèle ou les données provenant des utilisateurs",
@ -1395,15 +1405,32 @@
"revoke-title": "Désactiver l'URL publique"
},
"email-sharing": {
"accept-button": "",
"alert-text": "",
"bill-ack": "",
"cancel-button": "",
"input-invalid-email-text": "E-mail non valide",
"input-required-email-text": "Une adresse e-mail est obligatoire",
"invite-button": "Inviter",
"invite-field-desc": "Invitez des personnes par e-mail",
"invite-field-label": "Inviter",
"learn-more-button": "",
"recipient-email-placeholder": "",
"recipient-invalid-email-text": "",
"recipient-invitation-button": "",
"recipient-invitation-description": "",
"recipient-invitation-tooltip": "",
"recipient-list-description": "",
"recipient-list-title": "",
"recipient-required-email-text": "",
"resend-button": "Renvoyer",
"resend-button-title": "Renvoyer",
"resend-invite-label": "",
"revoke-access-label": "",
"revoke-button": "Retirer",
"revoke-button-title": "Retirer"
"revoke-button-title": "Retirer",
"success-creation": "",
"success-share-type-change": ""
},
"modal-alerts": {
"no-upsert-perm-alert-desc": "Contactez votre administrateur pour obtenir la permission d'accéder aux tableaux de bord publics {{mode}}",
@ -1415,6 +1442,15 @@
"unsupported-template-variable-alert-desc": "Ce tableau de bord public peut ne pas fonctionner car il utilise des variables de modèle",
"unsupported-template-variable-alert-title": "Les variables de modèle ne sont pas prises en charge"
},
"public-sharing": {
"accept-button": "",
"alert-text": "",
"cancel-button": "",
"learn-more-button": "",
"public-ack": "",
"success-creation": "",
"success-share-type-change": ""
},
"settings-bar-header": {
"collapse-settings-tooltip": "Réduire les paramètres",
"expand-settings-tooltip": "Développer les paramètres"
@ -1433,6 +1469,28 @@
"time-range-picker-disabled-text": "Sélecteur de plage de temps = désactivé",
"time-range-picker-enabled-text": "Sélecteur de plage de temps = activé",
"time-range-text": "Plage de temps = "
},
"share": {
"success-delete": "",
"success-delete-old": ""
},
"share-configuration": {
"access-label": "",
"share-type-label": ""
},
"share-externally": {
"copy-link-button": "",
"email-share-type-option-description": "",
"email-share-type-option-label": "",
"pause-access-button": "",
"pause-access-tooltip": "",
"public-share-type-option-description": "",
"public-share-type-option-label": "",
"resume-access-button": "",
"revoke-access-button": ""
},
"sharing": {
"success-creation": ""
}
},
"public-dashboard-list": {
@ -1495,6 +1553,18 @@
},
"query-editor-not-exported": "Le plugin source de données n'exporte aucun composant de l'éditeur de requête"
},
"recently-deleted": {
"buttons": {
"restore": ""
},
"restore-modal": {
"restore-button": "",
"restore-loading": "",
"title": "",
"text_one": "",
"text_other": ""
}
},
"refresh-picker": {
"aria-label": {
"choose-interval": "Actualisation automatique désactivée. Choisir un intervalle de temps d'actualisation",

View File

@ -1553,6 +1553,18 @@
},
"query-editor-not-exported": "Đäŧä şőūřčę pľūģįʼn đőęş ʼnőŧ ęχpőřŧ äʼny Qūęřy Ēđįŧőř čőmpőʼnęʼnŧ"
},
"recently-deleted": {
"buttons": {
"restore": "Ŗęşŧőřę"
},
"restore-modal": {
"restore-button": "Ŗęşŧőřę",
"restore-loading": "Ŗęşŧőřįʼnģ...",
"text_one": "Ŧĥįş äčŧįőʼn ŵįľľ řęşŧőřę {{numberOfDashboards}} đäşĥþőäřđ.",
"text_other": "Ŧĥįş äčŧįőʼn ŵįľľ řęşŧőřę {{numberOfDashboards}} đäşĥþőäřđş.",
"title": "Ŗęşŧőřę Đäşĥþőäřđş"
}
},
"refresh-picker": {
"aria-label": {
"choose-interval": "Åūŧő řęƒřęşĥ ŧūřʼnęđ őƒƒ. Cĥőőşę řęƒřęşĥ ŧįmę įʼnŧęřväľ",

View File

@ -1384,6 +1384,16 @@
"revoke-public-URL-button-title": "Revogar URL público",
"settings-title": "Configurações"
},
"configuration": {
"display-annotations-label": "",
"enable-time-range-label": "",
"settings-label": "",
"success-pause": "",
"success-resume": "",
"success-update": "",
"success-update-old": "",
"time-range-tooltip": ""
},
"create-page": {
"generate-public-url-button": "Gerar URL público",
"unsupported-features-desc": "Atualmente, não oferecemos suporte a variáveis de modelo ou fontes de dados frontend",
@ -1395,15 +1405,32 @@
"revoke-title": "Revogar URL público"
},
"email-sharing": {
"accept-button": "",
"alert-text": "",
"bill-ack": "",
"cancel-button": "",
"input-invalid-email-text": "E-mail inválido",
"input-required-email-text": "O e-mail é obrigatório",
"invite-button": "Convidar",
"invite-field-desc": "Convidar pessoas por e-mail",
"invite-field-label": "Convidar",
"learn-more-button": "",
"recipient-email-placeholder": "",
"recipient-invalid-email-text": "",
"recipient-invitation-button": "",
"recipient-invitation-description": "",
"recipient-invitation-tooltip": "",
"recipient-list-description": "",
"recipient-list-title": "",
"recipient-required-email-text": "",
"resend-button": "Reenviar",
"resend-button-title": "Reenviar",
"resend-invite-label": "",
"revoke-access-label": "",
"revoke-button": "Revogar",
"revoke-button-title": "Revogar"
"revoke-button-title": "Revogar",
"success-creation": "",
"success-share-type-change": ""
},
"modal-alerts": {
"no-upsert-perm-alert-desc": "Entre em contato com seu administrador para obter permissão para painéis de controle {{mode}} públicos",
@ -1415,6 +1442,15 @@
"unsupported-template-variable-alert-desc": "Este painel de controle público pode não funcionar, pois ele usa variáveis de modelo",
"unsupported-template-variable-alert-title": "As variáveis de modelo não são suportadas"
},
"public-sharing": {
"accept-button": "",
"alert-text": "",
"cancel-button": "",
"learn-more-button": "",
"public-ack": "",
"success-creation": "",
"success-share-type-change": ""
},
"settings-bar-header": {
"collapse-settings-tooltip": "Recolher configurações",
"expand-settings-tooltip": "Expandir configurações"
@ -1433,6 +1469,28 @@
"time-range-picker-disabled-text": "Seletor de intervalo de tempo = desativado",
"time-range-picker-enabled-text": "Seletor de intervalo de tempo = ativado",
"time-range-text": "Intervalo de tempo = "
},
"share": {
"success-delete": "",
"success-delete-old": ""
},
"share-configuration": {
"access-label": "",
"share-type-label": ""
},
"share-externally": {
"copy-link-button": "",
"email-share-type-option-description": "",
"email-share-type-option-label": "",
"pause-access-button": "",
"pause-access-tooltip": "",
"public-share-type-option-description": "",
"public-share-type-option-label": "",
"resume-access-button": "",
"revoke-access-button": ""
},
"sharing": {
"success-creation": ""
}
},
"public-dashboard-list": {
@ -1495,6 +1553,18 @@
},
"query-editor-not-exported": "O plug-in de origem de dados não exporta nenhum componente de editor de consulta"
},
"recently-deleted": {
"buttons": {
"restore": ""
},
"restore-modal": {
"restore-button": "",
"restore-loading": "",
"title": "",
"text_one": "",
"text_other": ""
}
},
"refresh-picker": {
"aria-label": {
"choose-interval": "Atualização automática desativada. Escolha o intervalo de tempo de atualização",

View File

@ -1378,6 +1378,16 @@
"revoke-public-URL-button-title": "注销公共网址",
"settings-title": "设置"
},
"configuration": {
"display-annotations-label": "",
"enable-time-range-label": "",
"settings-label": "",
"success-pause": "",
"success-resume": "",
"success-update": "",
"success-update-old": "",
"time-range-tooltip": ""
},
"create-page": {
"generate-public-url-button": "生成公共网址",
"unsupported-features-desc": "目前,我们不支持模板变量或前端数据源",
@ -1389,15 +1399,32 @@
"revoke-title": "注销公共网址"
},
"email-sharing": {
"accept-button": "",
"alert-text": "",
"bill-ack": "",
"cancel-button": "",
"input-invalid-email-text": "无效电子邮箱",
"input-required-email-text": "电子邮箱是必填项",
"invite-button": "邀请",
"invite-field-desc": "通过电子邮件邀请人员",
"invite-field-label": "邀请",
"learn-more-button": "",
"recipient-email-placeholder": "",
"recipient-invalid-email-text": "",
"recipient-invitation-button": "",
"recipient-invitation-description": "",
"recipient-invitation-tooltip": "",
"recipient-list-description": "",
"recipient-list-title": "",
"recipient-required-email-text": "",
"resend-button": "重新发送",
"resend-button-title": "重新发送",
"resend-invite-label": "",
"revoke-access-label": "",
"revoke-button": "注销",
"revoke-button-title": "注销"
"revoke-button-title": "注销",
"success-creation": "",
"success-share-type-change": ""
},
"modal-alerts": {
"no-upsert-perm-alert-desc": "请联系您的管理员以获得{{mode}}公共仪表板的权限",
@ -1409,6 +1436,15 @@
"unsupported-template-variable-alert-desc": "此公共仪表板可能无法工作,因为其使用了模板变量",
"unsupported-template-variable-alert-title": "模板变量不受支持"
},
"public-sharing": {
"accept-button": "",
"alert-text": "",
"cancel-button": "",
"learn-more-button": "",
"public-ack": "",
"success-creation": "",
"success-share-type-change": ""
},
"settings-bar-header": {
"collapse-settings-tooltip": "折叠设置",
"expand-settings-tooltip": "展开设置"
@ -1427,6 +1463,28 @@
"time-range-picker-disabled-text": "时间范围选择器 = 已禁用",
"time-range-picker-enabled-text": "时间范围选择器 = 已启用",
"time-range-text": "时间范围 = "
},
"share": {
"success-delete": "",
"success-delete-old": ""
},
"share-configuration": {
"access-label": "",
"share-type-label": ""
},
"share-externally": {
"copy-link-button": "",
"email-share-type-option-description": "",
"email-share-type-option-label": "",
"pause-access-button": "",
"pause-access-tooltip": "",
"public-share-type-option-description": "",
"public-share-type-option-label": "",
"resume-access-button": "",
"revoke-access-button": ""
},
"sharing": {
"success-creation": ""
}
},
"public-dashboard-list": {
@ -1489,6 +1547,17 @@
},
"query-editor-not-exported": "数据源插件不导出任何查询编辑器组件"
},
"recently-deleted": {
"buttons": {
"restore": ""
},
"restore-modal": {
"restore-button": "",
"restore-loading": "",
"title": "",
"text_other": ""
}
},
"refresh-picker": {
"aria-label": {
"choose-interval": "自动刷新已关闭。选择刷新时间间隔",

View File

@ -2573,7 +2573,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.0.0"
"@grafana/e2e-selectors": "npm:11.0.0"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/plugin-configs": "npm:11.0.0"
"@grafana/runtime": "npm:11.0.0"
"@grafana/schema": "npm:11.0.0"
@ -2617,7 +2617,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.0.0"
"@grafana/e2e-selectors": "npm:11.0.0"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/plugin-configs": "npm:11.0.0"
"@grafana/runtime": "npm:11.0.0"
"@grafana/sql": "npm:11.0.0"
@ -2689,7 +2689,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.0.0"
"@grafana/e2e-selectors": "npm:11.0.0"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/plugin-configs": "npm:11.0.0"
"@grafana/runtime": "npm:11.0.0"
"@grafana/schema": "npm:11.0.0"
@ -2730,7 +2730,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "workspace:*"
"@grafana/e2e-selectors": "workspace:*"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/o11y-ds-frontend": "workspace:*"
"@grafana/plugin-configs": "workspace:*"
"@grafana/runtime": "workspace:*"
@ -2772,7 +2772,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.0.0"
"@grafana/e2e-selectors": "npm:11.0.0"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/plugin-configs": "npm:11.0.0"
"@grafana/runtime": "npm:11.0.0"
"@grafana/sql": "npm:11.0.0"
@ -2835,7 +2835,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.0.0"
"@grafana/e2e-selectors": "npm:11.0.0"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/google-sdk": "npm:0.1.2"
"@grafana/plugin-configs": "npm:11.0.0"
"@grafana/runtime": "npm:11.0.0"
@ -2883,7 +2883,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "workspace:*"
"@grafana/e2e-selectors": "workspace:*"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/lezer-logql": "npm:0.2.4"
"@grafana/lezer-traceql": "npm:0.0.17"
"@grafana/monaco-logql": "npm:^0.0.7"
@ -2943,7 +2943,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "workspace:*"
"@grafana/e2e-selectors": "workspace:*"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/o11y-ds-frontend": "workspace:*"
"@grafana/plugin-configs": "workspace:*"
"@grafana/runtime": "workspace:*"
@ -3121,9 +3121,9 @@ __metadata:
languageName: node
linkType: hard
"@grafana/experimental@npm:1.7.11":
version: 1.7.11
resolution: "@grafana/experimental@npm:1.7.11"
"@grafana/experimental@npm:1.7.12":
version: 1.7.12
resolution: "@grafana/experimental@npm:1.7.12"
dependencies:
"@types/uuid": "npm:^8.3.3"
lodash: "npm:^4.17.21"
@ -3143,7 +3143,7 @@ __metadata:
react-dom: 17.0.2
react-select: ^5.2.1
rxjs: 7.8.0
checksum: 10/c0950b943f10b490f768046a081cc29a3dc8103d0154574a36beaa2af6fab4e429bbfb0767c5c89b5fd8ac3f3fc5936997b62e9db4e75ceaeb40837b234bb84e
checksum: 10/fd70c6925ce31fca8508c17c1722481f9649ce65383be166a05825e66a7ff47401fef84b55e74db5714be63e5c1cdf0f571fddec186669b74d0e2b005f4bf829
languageName: node
linkType: hard
@ -3262,7 +3262,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.0.0"
"@grafana/e2e-selectors": "npm:11.0.0"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/runtime": "npm:11.0.0"
"@grafana/schema": "npm:11.0.0"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
@ -3333,7 +3333,7 @@ __metadata:
"@floating-ui/react": "npm:0.26.16"
"@grafana/data": "npm:11.0.0"
"@grafana/e2e-selectors": "npm:11.0.0"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/faro-web-sdk": "npm:1.7.3"
"@grafana/runtime": "npm:11.0.0"
"@grafana/schema": "npm:11.0.0"
@ -3559,7 +3559,7 @@ __metadata:
"@emotion/css": "npm:11.11.2"
"@grafana/data": "npm:11.0.0"
"@grafana/e2e-selectors": "npm:11.0.0"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/runtime": "npm:11.0.0"
"@grafana/tsconfig": "npm:^1.3.0-rc1"
"@grafana/ui": "npm:11.0.0"
@ -16969,7 +16969,7 @@ __metadata:
"@grafana/e2e-selectors": "workspace:*"
"@grafana/eslint-config": "npm:7.0.0"
"@grafana/eslint-plugin": "link:./packages/grafana-eslint-rules"
"@grafana/experimental": "npm:1.7.11"
"@grafana/experimental": "npm:1.7.12"
"@grafana/faro-core": "npm:^1.3.6"
"@grafana/faro-web-sdk": "npm:^1.3.6"
"@grafana/flamegraph": "workspace:*"