mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 02:40:26 -06:00
Merge branch 'main' into drclau/unistor/replace-authenticators-3
This commit is contained in:
commit
2441cd8d53
@ -62,6 +62,7 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
|
||||
| `logRowsPopoverMenu` | Enable filtering menu displayed when text of a log line is selected | Yes |
|
||||
| `lokiQueryHints` | Enables query hints for Loki | Yes |
|
||||
| `alertingQueryOptimization` | Optimizes eligible queries in order to reduce load on datasources | |
|
||||
| `promQLScope` | In-development feature that will allow injection of labels into prometheus queries. | Yes |
|
||||
| `groupToNestedTableTransformation` | Enables the group to nested table transformation | Yes |
|
||||
| `tlsMemcached` | Use TLS-enabled memcached in the enterprise caching feature | Yes |
|
||||
| `cloudWatchNewLabelParsing` | Updates CloudWatch label parsing to be more accurate | Yes |
|
||||
@ -172,7 +173,6 @@ Experimental features might be changed or removed without prior notice.
|
||||
| `tableSharedCrosshair` | Enables shared crosshair in table panel |
|
||||
| `kubernetesFeatureToggles` | Use the kubernetes API for feature toggle management in the frontend |
|
||||
| `newFolderPicker` | Enables the nested folder picker without having nested folders enabled |
|
||||
| `promQLScope` | In-development feature that will allow injection of labels into prometheus queries. |
|
||||
| `sqlExpressions` | Enables using SQL and DuckDB functions as Expressions. |
|
||||
| `nodeGraphDotLayout` | Changed the layout algorithm for the node graph |
|
||||
| `kubernetesAggregator` | Enable grafana's embedded kube-aggregator |
|
||||
|
@ -608,6 +608,8 @@ github.com/dhui/dktest v0.3.0 h1:kwX5a7EkLcjo7VpsPQSYJcKGbXBXdjI9FGjuUj1jn6I=
|
||||
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
|
||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
|
||||
github.com/drone/drone-runtime v1.1.0 h1:IsKbwiLY6+ViNBzX0F8PERJVZZcEJm9rgxEh3uZP5IE=
|
||||
github.com/drone/drone-runtime v1.1.0/go.mod h1:+osgwGADc/nyl40J0fdsf8Z09bgcBZXvXXnLOY48zYs=
|
||||
|
@ -91,7 +91,7 @@
|
||||
"@rtk-query/codegen-openapi": "^1.2.0",
|
||||
"@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1",
|
||||
"@swc/core": "1.4.2",
|
||||
"@swc/helpers": "0.5.12",
|
||||
"@swc/helpers": "0.5.13",
|
||||
"@testing-library/dom": "10.0.0",
|
||||
"@testing-library/jest-dom": "6.4.2",
|
||||
"@testing-library/react": "15.0.2",
|
||||
@ -175,13 +175,13 @@
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jest": "28.8.1",
|
||||
"eslint-plugin-jest": "28.8.2",
|
||||
"eslint-plugin-jest-dom": "^5.4.0",
|
||||
"eslint-plugin-jsdoc": "48.11.0",
|
||||
"eslint-plugin-jsx-a11y": "6.9.0",
|
||||
"eslint-plugin-lodash": "7.4.0",
|
||||
"eslint-plugin-no-barrel-files": "^1.1.0",
|
||||
"eslint-plugin-react": "7.35.0",
|
||||
"eslint-plugin-react": "7.35.1",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-testing-library": "^6.2.2",
|
||||
"eslint-scope": "^8.0.0",
|
||||
@ -268,7 +268,7 @@
|
||||
"@grafana/prometheus": "workspace:*",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/saga-icons": "workspace:*",
|
||||
"@grafana/scenes": "^5.11.1",
|
||||
"@grafana/scenes": "5.12.0",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/sql": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
|
@ -81,7 +81,7 @@
|
||||
"@rollup/plugin-image": "3.0.3",
|
||||
"@rollup/plugin-node-resolve": "15.2.3",
|
||||
"@swc/core": "1.4.2",
|
||||
"@swc/helpers": "0.5.12",
|
||||
"@swc/helpers": "0.5.13",
|
||||
"@testing-library/dom": "10.0.0",
|
||||
"@testing-library/jest-dom": "6.4.2",
|
||||
"@testing-library/react": "15.0.2",
|
||||
@ -110,11 +110,11 @@
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jest": "28.8.1",
|
||||
"eslint-plugin-jest": "28.8.2",
|
||||
"eslint-plugin-jsdoc": "48.11.0",
|
||||
"eslint-plugin-jsx-a11y": "6.9.0",
|
||||
"eslint-plugin-lodash": "7.4.0",
|
||||
"eslint-plugin-react": "7.35.0",
|
||||
"eslint-plugin-react": "7.35.1",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-webpack-plugin": "4.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "9.0.2",
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { CSSInterpolation } from '@emotion/css';
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
@ -33,6 +34,27 @@ function buttonSizeMixin(paddingY: string, paddingX: string, fontSize: string, b
|
||||
};
|
||||
}
|
||||
|
||||
function widthMixin(theme: GrafanaTheme2, max: number) {
|
||||
let result: CSSInterpolation = {};
|
||||
for (let i = 1; i <= max; i++) {
|
||||
const width = `${theme.spacing(2 * i)} !important`;
|
||||
result[`.width-${i}`] = {
|
||||
width,
|
||||
};
|
||||
result[`.max-width-${i}`] = {
|
||||
maxWidth: width,
|
||||
flexGrow: 1,
|
||||
};
|
||||
result[`.min-width-${i}`] = {
|
||||
minWidth: width,
|
||||
};
|
||||
result[`.offset-width-${i}`] = {
|
||||
marginLeft: width,
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getUtilityClassStyles(theme: GrafanaTheme2) {
|
||||
return css({
|
||||
'.highlight-word': {
|
||||
@ -140,5 +162,6 @@ export function getUtilityClassStyles(theme: GrafanaTheme2) {
|
||||
'.typeahead': {
|
||||
zIndex: theme.zIndex.typeahead,
|
||||
},
|
||||
...widthMixin(theme, 30),
|
||||
});
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/ecr"
|
||||
"github.com/aws/aws-sdk-go/service/marketplacecatalog"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
@ -163,7 +164,7 @@ func (s *AwsMarketplacePublishingService) Login(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
authString := strings.Split(string(authData), ":")
|
||||
authData, err = json.Marshal(types.AuthConfig{
|
||||
authData, err = json.Marshal(registry.AuthConfig{
|
||||
Username: authString[0],
|
||||
Password: authString[1],
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ go 1.23.0
|
||||
// Override docker/docker to avoid:
|
||||
// go: github.com/drone-runners/drone-runner-docker@v1.8.2 requires
|
||||
// github.com/docker/docker@v0.0.0-00010101000000-000000000000: invalid version: unknown revision 000000000000
|
||||
replace github.com/docker/docker => github.com/moby/moby v23.0.4+incompatible
|
||||
replace github.com/docker/docker => github.com/moby/moby v25.0.2+incompatible
|
||||
|
||||
// contains openapi encoder fixes. remove ASAP
|
||||
replace cuelang.org/go => github.com/grafana/cue v0.0.0-20230926092038-971951014e3f // @grafana/grafana-as-code
|
||||
@ -61,7 +61,6 @@ require (
|
||||
github.com/buildkite/yaml v2.1.0+incompatible // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/drone-runners/drone-runner-docker v1.8.2 // indirect
|
||||
@ -102,6 +101,8 @@ require (
|
||||
github.com/Khan/genqlient v0.7.0 // indirect
|
||||
github.com/adrg/xdg v0.4.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
|
@ -54,6 +54,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
@ -62,9 +64,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
@ -168,8 +170,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/moby/moby v23.0.4+incompatible h1:A/pe8vi9KIKhNbzR0G3wW4ACKDsMgXILBveMqiJNa8M=
|
||||
github.com/moby/moby v23.0.4+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/moby/moby v25.0.2+incompatible h1:g2oKRI7vgWkiPHZbBghaPbcV/SuKP1g/YLx0I2nxFT4=
|
||||
github.com/moby/moby v25.0.2+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
@ -195,6 +197,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us=
|
||||
github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
@ -238,9 +238,11 @@ func Parse(span trace.Span, query backend.DataQuery, dsScrapeInterval string, in
|
||||
}()))
|
||||
}
|
||||
|
||||
expr, err = ApplyFiltersAndGroupBy(expr, scopeFilters, model.AdhocFilters, model.GroupByKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(scopeFilters) > 0 || len(model.AdhocFilters) > 0 || len(model.GroupByKeys) > 0 {
|
||||
expr, err = ApplyFiltersAndGroupBy(expr, scopeFilters, model.AdhocFilters, model.GroupByKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
|
||||
"github.com/grafana/authlib/claims"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
@ -241,32 +242,40 @@ func (s *Service) getCachedUserPermissions(ctx context.Context, user identity.Re
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.acimpl.getCachedUserPermissions")
|
||||
defer span.End()
|
||||
|
||||
permissions := []accesscontrol.Permission{}
|
||||
permissions, err := s.getCachedBasicRolesPermissions(ctx, user, options, permissions)
|
||||
cacheKey := accesscontrol.GetUserPermissionCacheKey(user)
|
||||
if cachedPermissions, ok := s.cache.Get(cacheKey); ok {
|
||||
return cachedPermissions.([]accesscontrol.Permission), nil
|
||||
}
|
||||
|
||||
permissions, err := s.getCachedBasicRolesPermissions(ctx, user, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissions, err = s.getCachedTeamsPermissions(ctx, user, options, permissions)
|
||||
teamsPermissions, err := s.getCachedTeamsPermissions(ctx, user, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
permissions = append(permissions, teamsPermissions...)
|
||||
|
||||
userManagedPermissions, err := s.getCachedUserDirectPermissions(ctx, user, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userPermissions, err := s.getCachedUserDirectPermissions(ctx, user, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissions = append(permissions, userPermissions...)
|
||||
permissions = append(permissions, userManagedPermissions...)
|
||||
s.cache.Set(cacheKey, permissions, cacheTTL)
|
||||
span.SetAttributes(attribute.Int("num_permissions", len(permissions)))
|
||||
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
func (s *Service) getCachedBasicRolesPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options, permissions []accesscontrol.Permission) ([]accesscontrol.Permission, error) {
|
||||
func (s *Service) getCachedBasicRolesPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.acimpl.getCachedBasicRolesPermissions")
|
||||
defer span.End()
|
||||
|
||||
// Viewer role has ~30 permissions, so we can pre-allocate memory
|
||||
permissions := make([]accesscontrol.Permission, 0, 50)
|
||||
basicRoles := accesscontrol.GetOrgRoles(user)
|
||||
span.SetAttributes(attribute.Int("roles", len(basicRoles)))
|
||||
for _, role := range basicRoles {
|
||||
@ -330,16 +339,20 @@ func (s *Service) getCachedPermissions(ctx context.Context, key string, getPermi
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options, permissions []accesscontrol.Permission) ([]accesscontrol.Permission, error) {
|
||||
func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.acimpl.getCachedTeamsPermissions")
|
||||
defer span.End()
|
||||
|
||||
teams := user.GetTeams()
|
||||
orgID := user.GetOrgID()
|
||||
miss := teams
|
||||
if len(teams) == 0 {
|
||||
return []accesscontrol.Permission{}, nil
|
||||
}
|
||||
|
||||
miss := make([]int64, 0)
|
||||
permissions := make([]accesscontrol.Permission, 0)
|
||||
|
||||
if !options.ReloadCache {
|
||||
miss = make([]int64, 0)
|
||||
for _, teamID := range teams {
|
||||
key := accesscontrol.GetTeamPermissionCacheKey(teamID, orgID)
|
||||
teamPermissions, ok := s.cache.Get(key)
|
||||
@ -351,6 +364,9 @@ func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.R
|
||||
miss = append(miss, teamID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// reload cache and fetch all teams permissions
|
||||
miss = teams
|
||||
}
|
||||
|
||||
if len(miss) > 0 {
|
||||
@ -373,7 +389,7 @@ func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.R
|
||||
}
|
||||
|
||||
func (s *Service) ClearUserPermissionCache(user identity.Requester) {
|
||||
s.cache.Delete(accesscontrol.GetPermissionCacheKey(user))
|
||||
s.cache.Delete(accesscontrol.GetUserPermissionCacheKey(user))
|
||||
s.cache.Delete(accesscontrol.GetUserDirectPermissionCacheKey(user))
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
)
|
||||
|
||||
func GetPermissionCacheKey(user identity.Requester) string {
|
||||
func GetUserPermissionCacheKey(user identity.Requester) string {
|
||||
return fmt.Sprintf("rbac-permissions-%s", user.GetCacheKey())
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/grafana/authlib/claims"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
@ -68,7 +69,7 @@ func TestPermissionCacheKey(t *testing.T) {
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.expected, GetPermissionCacheKey(tc.signedInUser))
|
||||
assert.Equal(t, tc.expected, GetUserPermissionCacheKey(tc.signedInUser))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1039,8 +1039,9 @@ var (
|
||||
{
|
||||
Name: "promQLScope",
|
||||
Description: "In-development feature that will allow injection of labels into prometheus queries.",
|
||||
Stage: FeatureStageExperimental,
|
||||
Stage: FeatureStageGeneralAvailability,
|
||||
Owner: grafanaObservabilityMetricsSquad,
|
||||
Expression: "true",
|
||||
},
|
||||
{
|
||||
Name: "sqlExpressions",
|
||||
|
@ -136,7 +136,7 @@ newFolderPicker,experimental,@grafana/grafana-frontend-platform,false,false,true
|
||||
jitterAlertRulesWithinGroups,preview,@grafana/alerting-squad,false,true,false
|
||||
onPremToCloudMigrations,preview,@grafana/grafana-operator-experience-squad,false,false,false
|
||||
alertingSaveStatePeriodic,privatePreview,@grafana/alerting-squad,false,false,false
|
||||
promQLScope,experimental,@grafana/observability-metrics,false,false,false
|
||||
promQLScope,GA,@grafana/observability-metrics,false,false,false
|
||||
sqlExpressions,experimental,@grafana/grafana-app-platform-squad,false,false,false
|
||||
nodeGraphDotLayout,experimental,@grafana/observability-traces-and-profiling,false,false,true
|
||||
groupToNestedTableTransformation,GA,@grafana/dataviz-squad,false,false,true
|
||||
|
|
@ -2188,13 +2188,17 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "promQLScope",
|
||||
"resourceVersion": "1718727528075",
|
||||
"creationTimestamp": "2024-01-29T20:22:17Z"
|
||||
"resourceVersion": "1724076197892",
|
||||
"creationTimestamp": "2024-01-29T20:22:17Z",
|
||||
"annotations": {
|
||||
"grafana.app/updatedTimestamp": "2024-08-19 14:03:17.892558375 +0000 UTC"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"description": "In-development feature that will allow injection of labels into prometheus queries.",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/observability-metrics"
|
||||
"stage": "GA",
|
||||
"codeowner": "@grafana/observability-metrics",
|
||||
"expression": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1,11 +1,18 @@
|
||||
import { VariableRefresh } from '@grafana/data';
|
||||
import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks';
|
||||
import { setPluginImportUtils } from '@grafana/runtime';
|
||||
import { SceneGridLayout, VizPanel } from '@grafana/scenes';
|
||||
import { SceneGridLayout, SceneVariableSet, TestVariable, VizPanel } from '@grafana/scenes';
|
||||
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from 'app/features/variables/constants';
|
||||
|
||||
import { activateFullSceneTree, buildPanelRepeaterScene } from '../utils/test-utils';
|
||||
|
||||
import { DashboardGridItem, DashboardGridItemState } from './DashboardGridItem';
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
getPluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
|
||||
}));
|
||||
|
||||
setPluginImportUtils({
|
||||
importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})),
|
||||
@ -85,6 +92,142 @@ describe('PanelRepeaterGridItem', () => {
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(1);
|
||||
});
|
||||
|
||||
it('Should redo the repeat when editing panel and then returning to dashboard', async () => {
|
||||
const panel = new DashboardGridItem({
|
||||
variableName: 'server',
|
||||
repeatedPanels: [],
|
||||
body: new VizPanel({
|
||||
title: 'Panel $server',
|
||||
}),
|
||||
});
|
||||
|
||||
const variable = new TestVariable({
|
||||
name: 'server',
|
||||
query: 'A.*',
|
||||
value: ALL_VARIABLE_VALUE,
|
||||
text: ALL_VARIABLE_TEXT,
|
||||
isMulti: true,
|
||||
includeAll: true,
|
||||
delayMs: 0,
|
||||
optionsToReturn: [
|
||||
{ label: 'A', value: '1' },
|
||||
{ label: 'B', value: '2' },
|
||||
{ label: 'C', value: '3' },
|
||||
{ label: 'D', value: '4' },
|
||||
{ label: 'E', value: '5' },
|
||||
],
|
||||
});
|
||||
|
||||
const scene = new DashboardScene({
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [variable],
|
||||
}),
|
||||
body: new SceneGridLayout({
|
||||
children: [panel],
|
||||
}),
|
||||
});
|
||||
|
||||
const deactivate = activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(panel.state.repeatedPanels?.length).toBe(5);
|
||||
|
||||
const vizPanel = panel.state.body as VizPanel;
|
||||
|
||||
expect(vizPanel.state.title).toBe('Panel $server');
|
||||
|
||||
// mimic going to panel edit
|
||||
deactivate();
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
vizPanel.setState({ title: 'Changed' });
|
||||
//mimic returning to dashboard from panel edit cloning panel
|
||||
panel.setState({ body: vizPanel.clone() });
|
||||
|
||||
// mimic returning to dashboard
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(panel.state.repeatedPanels?.length).toBe(5);
|
||||
expect((panel.state.repeatedPanels![0] as VizPanel).state.title).toBe('Changed');
|
||||
});
|
||||
|
||||
it('Should only redo the repeat of an edited panel, not all panels in dashboard', async () => {
|
||||
const panel = new DashboardGridItem({
|
||||
variableName: 'server',
|
||||
repeatedPanels: [],
|
||||
body: new VizPanel({
|
||||
title: 'Panel $server',
|
||||
}),
|
||||
});
|
||||
|
||||
const panel2 = new DashboardGridItem({
|
||||
variableName: 'server',
|
||||
repeatedPanels: [],
|
||||
body: new VizPanel({
|
||||
title: 'Panel $server 2',
|
||||
}),
|
||||
});
|
||||
|
||||
const variable = new TestVariable({
|
||||
name: 'server',
|
||||
query: 'A.*',
|
||||
value: ALL_VARIABLE_VALUE,
|
||||
text: ALL_VARIABLE_TEXT,
|
||||
isMulti: true,
|
||||
includeAll: true,
|
||||
delayMs: 0,
|
||||
optionsToReturn: [
|
||||
{ label: 'A', value: '1' },
|
||||
{ label: 'B', value: '2' },
|
||||
{ label: 'C', value: '3' },
|
||||
{ label: 'D', value: '4' },
|
||||
{ label: 'E', value: '5' },
|
||||
],
|
||||
});
|
||||
|
||||
const scene = new DashboardScene({
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [variable],
|
||||
}),
|
||||
body: new SceneGridLayout({
|
||||
children: [panel, panel2],
|
||||
}),
|
||||
});
|
||||
|
||||
const deactivate = activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(panel.state.repeatedPanels?.length).toBe(5);
|
||||
|
||||
const vizPanel = panel.state.body as VizPanel;
|
||||
|
||||
expect(vizPanel.state.title).toBe('Panel $server');
|
||||
|
||||
// mimic going to panel edit
|
||||
deactivate();
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
vizPanel.setState({ title: 'Changed' });
|
||||
//mimic returning to dashboard from panel edit cloning panel
|
||||
panel.setState({ body: vizPanel.clone() });
|
||||
|
||||
const performRepeatMock = jest.spyOn(panel, 'performRepeat');
|
||||
// mimic returning to dashboard
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(performRepeatMock).toHaveBeenCalledTimes(1); // only for the edited panel
|
||||
expect(panel.state.repeatedPanels?.length).toBe(5);
|
||||
expect((panel.state.repeatedPanels![0] as VizPanel).state.title).toBe('Changed');
|
||||
});
|
||||
|
||||
it('Should display a panel when there are variable errors', () => {
|
||||
const { scene, repeater } = buildPanelRepeaterScene({
|
||||
variableQueryTime: 0,
|
||||
|
@ -45,6 +45,7 @@ export type RepeatDirection = 'v' | 'h';
|
||||
export class DashboardGridItem extends SceneObjectBase<DashboardGridItemState> implements SceneGridItemLike {
|
||||
private _libPanelSubscription: Unsubscribable | undefined;
|
||||
private _prevRepeatValues?: VariableValueSingle[];
|
||||
private _oldBody?: VizPanel | LibraryVizPanel | AddLibraryPanelDrawer;
|
||||
|
||||
protected _variableDependency = new DashboardGridItemVariableDependencyHandler(this);
|
||||
|
||||
@ -57,6 +58,11 @@ export class DashboardGridItem extends SceneObjectBase<DashboardGridItemState> i
|
||||
private _activationHandler() {
|
||||
if (this.state.variableName) {
|
||||
this._subs.add(this.subscribeToState((newState, prevState) => this._handleGridResize(newState, prevState)));
|
||||
if (this._oldBody !== this.state.body) {
|
||||
this._prevRepeatValues = undefined;
|
||||
}
|
||||
|
||||
this._oldBody = this.state.body;
|
||||
this.performRepeat();
|
||||
}
|
||||
|
||||
|
@ -2602,3 +2602,7 @@ label.cr1 {
|
||||
input[type='checkbox'].cr1:checked + label {
|
||||
background: url($checkboxImageUrl) 0px -18px no-repeat;
|
||||
}
|
||||
|
||||
.max-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -3,8 +3,5 @@
|
||||
@import 'base/grid';
|
||||
@import 'base/font_awesome';
|
||||
|
||||
// UTILS
|
||||
@import 'utils/widths';
|
||||
|
||||
// ANGULAR
|
||||
@import 'angular';
|
||||
|
@ -1,32 +0,0 @@
|
||||
.max-width {
|
||||
width: 100%;
|
||||
}
|
||||
.width-auto {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
// widths
|
||||
@for $i from 1 through 30 {
|
||||
.width-#{$i} {
|
||||
width: ($spacer * $i) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 30 {
|
||||
.max-width-#{$i} {
|
||||
max-width: ($spacer * $i) !important;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 30 {
|
||||
.min-width-#{$i} {
|
||||
min-width: ($spacer * $i) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 30 {
|
||||
.offset-width-#{$i} {
|
||||
margin-left: ($spacer * $i) !important;
|
||||
}
|
||||
}
|
46
yarn.lock
46
yarn.lock
@ -3769,7 +3769,7 @@ __metadata:
|
||||
"@rollup/plugin-image": "npm:3.0.3"
|
||||
"@rollup/plugin-node-resolve": "npm:15.2.3"
|
||||
"@swc/core": "npm:1.4.2"
|
||||
"@swc/helpers": "npm:0.5.12"
|
||||
"@swc/helpers": "npm:0.5.13"
|
||||
"@testing-library/dom": "npm:10.0.0"
|
||||
"@testing-library/jest-dom": "npm:6.4.2"
|
||||
"@testing-library/react": "npm:15.0.2"
|
||||
@ -3801,11 +3801,11 @@ __metadata:
|
||||
eslint: "npm:8.57.0"
|
||||
eslint-config-prettier: "npm:9.1.0"
|
||||
eslint-plugin-import: "npm:^2.26.0"
|
||||
eslint-plugin-jest: "npm:28.8.1"
|
||||
eslint-plugin-jest: "npm:28.8.2"
|
||||
eslint-plugin-jsdoc: "npm:48.11.0"
|
||||
eslint-plugin-jsx-a11y: "npm:6.9.0"
|
||||
eslint-plugin-lodash: "npm:7.4.0"
|
||||
eslint-plugin-react: "npm:7.35.0"
|
||||
eslint-plugin-react: "npm:7.35.1"
|
||||
eslint-plugin-react-hooks: "npm:4.6.0"
|
||||
eslint-webpack-plugin: "npm:4.2.0"
|
||||
eventemitter3: "npm:5.0.1"
|
||||
@ -3932,9 +3932,9 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana/scenes@npm:^5.11.1":
|
||||
version: 5.11.2
|
||||
resolution: "@grafana/scenes@npm:5.11.2"
|
||||
"@grafana/scenes@npm:5.12.0":
|
||||
version: 5.12.0
|
||||
resolution: "@grafana/scenes@npm:5.12.0"
|
||||
dependencies:
|
||||
"@floating-ui/react": "npm:0.26.16"
|
||||
"@grafana/e2e-selectors": "npm:^11.0.0"
|
||||
@ -3951,7 +3951,7 @@ __metadata:
|
||||
"@grafana/ui": ">=10.4"
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
checksum: 10/1f6cded27acac813b1f039fa656efa476bcb2a444217c78c707441698d8d2dc053745fadcbad2dbe94a252d2613f1b32ac120fb11d887bb14f08a0bbea4c423b
|
||||
checksum: 10/17e1e1b2928c06ad9c898e1988ece2a2113ca3177f510036b42eb4032d6582e783ec28f1f3110dc67acda4ec56d2747ae23c2d57593bc2dac0ff60b2fffeda61
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -8822,12 +8822,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/helpers@npm:0.5.12, @swc/helpers@npm:^0.5.0":
|
||||
version: 0.5.12
|
||||
resolution: "@swc/helpers@npm:0.5.12"
|
||||
"@swc/helpers@npm:0.5.13, @swc/helpers@npm:^0.5.0":
|
||||
version: 0.5.13
|
||||
resolution: "@swc/helpers@npm:0.5.13"
|
||||
dependencies:
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 10/f04a4728c38a6e75a85b077408e175e1abbc1650a76e4b78008d6380ca1422d9f7f4f9fe61b42f8fb889140f05ced6a5a9983037a8d5d8086bf6bc80a0b2118b
|
||||
checksum: 10/6ba2f7e215d32d71fce139e2cfc426b3ed7eaa709febdeb07b97260a4c9eea4784cf047cc1271be273990b08220b576b94a42b5780947c0b3be84973a847a24d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -16588,9 +16588,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-jest@npm:28.8.1":
|
||||
version: 28.8.1
|
||||
resolution: "eslint-plugin-jest@npm:28.8.1"
|
||||
"eslint-plugin-jest@npm:28.8.2":
|
||||
version: 28.8.2
|
||||
resolution: "eslint-plugin-jest@npm:28.8.2"
|
||||
dependencies:
|
||||
"@typescript-eslint/utils": "npm:^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
peerDependencies:
|
||||
@ -16602,7 +16602,7 @@ __metadata:
|
||||
optional: true
|
||||
jest:
|
||||
optional: true
|
||||
checksum: 10/d148255d9e131103fc6be708874043f679c84137db140832523ab2481d17683d13ed41a15626f24b098ba5674520c1c316243a02d32d64f87cede57b0d84a46a
|
||||
checksum: 10/5868bc0f825fdb5c26ff5939a55baa6e6b9bf9c7de5a45388babb876b17e0253a1e8c4d343b404fd5fcd2b7ab1808b47e20b06fb193a4e73f145fe25473eada4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -16727,9 +16727,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-react@npm:7.35.0":
|
||||
version: 7.35.0
|
||||
resolution: "eslint-plugin-react@npm:7.35.0"
|
||||
"eslint-plugin-react@npm:7.35.1":
|
||||
version: 7.35.1
|
||||
resolution: "eslint-plugin-react@npm:7.35.1"
|
||||
dependencies:
|
||||
array-includes: "npm:^3.1.8"
|
||||
array.prototype.findlast: "npm:^1.2.5"
|
||||
@ -16751,7 +16751,7 @@ __metadata:
|
||||
string.prototype.repeat: "npm:^1.0.0"
|
||||
peerDependencies:
|
||||
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
|
||||
checksum: 10/fa0a54f9ea249cf89d92bb5983bf7df741da3709a0ebd6a885a67d05413ed302fd8b64c9dc819b33df8efa6d8b06f5e56b1f6965a9be7cc3e79054da4dbae5ed
|
||||
checksum: 10/5bbae54dcef5a84bd71277315238d63caaa23effecd1a376b83ccf1cf033770ee44b763300f9fb55c569d7688ebc93d12728018dcfe240423c6059cc7284ba3f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -18511,7 +18511,7 @@ __metadata:
|
||||
"@grafana/prometheus": "workspace:*"
|
||||
"@grafana/runtime": "workspace:*"
|
||||
"@grafana/saga-icons": "workspace:*"
|
||||
"@grafana/scenes": "npm:^5.11.1"
|
||||
"@grafana/scenes": "npm:5.12.0"
|
||||
"@grafana/schema": "workspace:*"
|
||||
"@grafana/sql": "workspace:*"
|
||||
"@grafana/tsconfig": "npm:^2.0.0"
|
||||
@ -18547,7 +18547,7 @@ __metadata:
|
||||
"@rtk-query/codegen-openapi": "npm:^1.2.0"
|
||||
"@rtsao/plugin-proposal-class-properties": "npm:7.0.1-patch.1"
|
||||
"@swc/core": "npm:1.4.2"
|
||||
"@swc/helpers": "npm:0.5.12"
|
||||
"@swc/helpers": "npm:0.5.13"
|
||||
"@testing-library/dom": "npm:10.0.0"
|
||||
"@testing-library/jest-dom": "npm:6.4.2"
|
||||
"@testing-library/react": "npm:15.0.2"
|
||||
@ -18657,13 +18657,13 @@ __metadata:
|
||||
eslint: "npm:8.57.0"
|
||||
eslint-config-prettier: "npm:9.1.0"
|
||||
eslint-plugin-import: "npm:^2.26.0"
|
||||
eslint-plugin-jest: "npm:28.8.1"
|
||||
eslint-plugin-jest: "npm:28.8.2"
|
||||
eslint-plugin-jest-dom: "npm:^5.4.0"
|
||||
eslint-plugin-jsdoc: "npm:48.11.0"
|
||||
eslint-plugin-jsx-a11y: "npm:6.9.0"
|
||||
eslint-plugin-lodash: "npm:7.4.0"
|
||||
eslint-plugin-no-barrel-files: "npm:^1.1.0"
|
||||
eslint-plugin-react: "npm:7.35.0"
|
||||
eslint-plugin-react: "npm:7.35.1"
|
||||
eslint-plugin-react-hooks: "npm:4.6.0"
|
||||
eslint-plugin-testing-library: "npm:^6.2.2"
|
||||
eslint-scope: "npm:^8.0.0"
|
||||
|
Loading…
Reference in New Issue
Block a user