+
{body}
) : (
@@ -148,16 +157,14 @@ const getStyles = (theme: GrafanaTheme2) => {
alignItems: 'center',
height: theme.spacing(theme.components.height.md),
padding: theme.spacing(0, 1),
- borderRadius: theme.shape.radius.default,
+ borderRadius: theme.shape.borderRadius(),
lineHeight: `${theme.components.height.md * theme.spacing.gridSize - 2}px`,
fontWeight: theme.typography.fontWeightMedium,
border: `1px solid ${theme.colors.secondary.border}`,
whiteSpace: 'nowrap',
- [theme.transitions.handleMotion('no-preference', 'reduce')]: {
- transition: theme.transitions.create(['background', 'box-shadow', 'border-color', 'color'], {
- duration: theme.transitions.duration.short,
- }),
- },
+ transition: theme.transitions.create(['background', 'box-shadow', 'border-color', 'color'], {
+ duration: theme.transitions.duration.short,
+ }),
'&:focus, &:focus-visible': {
...getFocusStyles(theme),
@@ -185,7 +192,7 @@ const getStyles = (theme: GrafanaTheme2) => {
}),
default: css({
color: theme.colors.text.secondary,
- background: 'transparent',
+ background: theme.colors.background.primary,
border: `1px solid transparent`,
'&:hover': {
diff --git a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx
index 54b6648efefbc..3e916bc8e1ebb 100644
--- a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx
+++ b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx
@@ -1,7 +1,6 @@
import { css, cx } from '@emotion/css';
import { useLayoutEffect, useRef, useReducer, CSSProperties } from 'react';
import * as React from 'react';
-import { createPortal } from 'react-dom';
import uPlot from 'uplot';
import { GrafanaTheme2 } from '@grafana/data';
@@ -9,7 +8,7 @@ import { DashboardCursorSync } from '@grafana/schema';
import { useStyles2 } from '../../../themes';
import { RangeSelection1D, RangeSelection2D, OnSelectRangeCallback } from '../../PanelChrome';
-import { getPortalContainer } from '../../Portal/Portal';
+import { getPortalContainer, Portal } from '../../Portal/Portal';
import { UPlotConfigBuilder } from '../config/UPlotConfigBuilder';
import { CloseButton } from './CloseButton';
@@ -651,18 +650,18 @@ export const TooltipPlugin2 = ({
}, [isHovering]);
if (plot && isHovering) {
- return createPortal(
-
- {isPinned && }
- {contents}
-
,
- portalRoot.current
+ return (
+
+
+ {isPinned && }
+ {contents}
+
+
);
}
diff --git a/packages/grafana-ui/src/themes/GlobalStyles/forms.ts b/packages/grafana-ui/src/themes/GlobalStyles/forms.ts
index 2cc1b03e94a23..317d92b3a075e 100644
--- a/packages/grafana-ui/src/themes/GlobalStyles/forms.ts
+++ b/packages/grafana-ui/src/themes/GlobalStyles/forms.ts
@@ -10,14 +10,12 @@ export function getFormElementStyles(theme: GrafanaTheme2) {
fontWeight: theme.typography.body.fontWeight,
lineHeight: theme.typography.body.lineHeight,
},
-
'input, select': {
backgroundColor: theme.components.input.background,
color: theme.components.input.text,
border: 'none',
boxShadow: 'none',
},
-
textarea: {
height: 'auto',
},
diff --git a/packages/grafana-ui/src/themes/ThemeContext.tsx b/packages/grafana-ui/src/themes/ThemeContext.tsx
index e83401a04deee..a9508dba300f4 100644
--- a/packages/grafana-ui/src/themes/ThemeContext.tsx
+++ b/packages/grafana-ui/src/themes/ThemeContext.tsx
@@ -36,6 +36,7 @@ export const withTheme = (Component: Rea
};
WithTheme.displayName = `WithTheme(${Component.displayName})`;
+ // @ts-ignore
hoistNonReactStatics(WithTheme, Component);
type Hoisted = typeof WithTheme & S;
return WithTheme as Hoisted;
@@ -56,6 +57,7 @@ export const withTheme2 =
(Component: R
};
WithTheme.displayName = `WithTheme(${Component.displayName})`;
+ // @ts-ignore
hoistNonReactStatics(WithTheme, Component);
type Hoisted = typeof WithTheme & S;
return WithTheme as Hoisted;
diff --git a/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts
index 75a8ad0d4af3d..3f6b60eed7fa5 100644
--- a/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts
+++ b/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts
@@ -75,10 +75,10 @@ $grid-breakpoints: (
// Define the maximum width of \`.container\` for different screen sizes.
$container-max-widths: (
- sm: 576px,
- md: 720px,
- lg: 940px,
- xl: 1080px,
+ sm: 640px,
+ md: 768px,
+ lg: 1024px,
+ xl: 1536px,
) !default;
// Grid columns
diff --git a/packages/grafana-ui/src/themes/default.ts b/packages/grafana-ui/src/themes/default.ts
index f5490b72c0bc7..78fb03350cacf 100644
--- a/packages/grafana-ui/src/themes/default.ts
+++ b/packages/grafana-ui/src/themes/default.ts
@@ -31,8 +31,8 @@ const theme: GrafanaThemeCommons = {
name: 'Grafana Default',
typography: {
fontFamily: {
- sansSerif: '"Inter", "Helvetica", "Arial", sans-serif',
- monospace: "'Roboto Mono', monospace",
+ sansSerif: '"Poppins", Inter, Satoshi, sans-serif',
+ monospace: '"SatoshiLight", "FigtreeLight", monospace',
},
size: {
base: '14px',
diff --git a/packages/grafana-ui/tsconfig.json b/packages/grafana-ui/tsconfig.json
index 7601a6e1e18a4..e0d37b754df8e 100644
--- a/packages/grafana-ui/tsconfig.json
+++ b/packages/grafana-ui/tsconfig.json
@@ -5,7 +5,8 @@
"declarationDir": "./compiled",
"emitDeclarationOnly": true,
"isolatedModules": true,
- "rootDirs": ["."]
+ "rootDirs": ["."],
+ "moduleResolution": "node"
},
"exclude": ["dist/**/*"],
"extends": "@grafana/tsconfig",
diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod
index 55398f00f5e60..60f1d9187cfbe 100644
--- a/pkg/aggregator/go.mod
+++ b/pkg/aggregator/go.mod
@@ -3,89 +3,92 @@ module github.com/grafana/grafana/pkg/aggregator
go 1.23.0
require (
- github.com/emicklei/go-restful/v3 v3.11.0
- github.com/grafana/grafana-plugin-sdk-go v0.244.0
+ github.com/emicklei/go-restful/v3 v3.12.1
+ github.com/grafana/grafana-plugin-sdk-go v0.245.0
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808213237-f4d2e064f435
github.com/grafana/grafana/pkg/semconv v0.0.0-20240808213237-f4d2e064f435
github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38
github.com/stretchr/testify v1.9.0
- go.opentelemetry.io/otel v1.28.0
+ go.opentelemetry.io/otel v1.29.0
k8s.io/api v0.31.0
k8s.io/apimachinery v0.31.0
k8s.io/apiserver v0.31.0
k8s.io/client-go v0.31.0
k8s.io/component-base v0.31.0
k8s.io/klog/v2 v2.130.1
- k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340
+ k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2
sigs.k8s.io/structured-merge-diff/v4 v4.4.1
)
require (
- github.com/BurntSushi/toml v1.3.2 // indirect
+ github.com/BurntSushi/toml v1.4.0 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
- github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
+ github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/apache/arrow/go/v15 v15.0.2 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
+ github.com/bufbuild/protocompile v0.14.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
- github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071 // indirect
+ github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // 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/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 // indirect
+ github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
- github.com/fatih/color v1.16.0 // indirect
+ github.com/fatih/color v1.17.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
- github.com/getkin/kin-openapi v0.125.0 // indirect
+ github.com/getkin/kin-openapi v0.127.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/jsonreference v0.20.4 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
+ github.com/goccy/go-json v0.10.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
- github.com/google/btree v1.1.2 // indirect
- github.com/google/cel-go v0.20.1 // indirect
+ github.com/google/btree v1.1.3 // indirect
+ github.com/google/cel-go v0.21.0 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
+ github.com/gorilla/websocket v1.5.3 // indirect
github.com/grafana/otel-profiling-go v0.5.1 // indirect
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // 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/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.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
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/invopop/yaml v0.3.1 // indirect
+ github.com/jhump/protoreflect v1.16.0 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
github.com/klauspost/compress v1.17.9 // indirect
- github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/magefile/mage v1.15.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattetti/filebuffer v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -97,9 +100,9 @@ require (
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/prometheus/client_golang v1.20.0 // indirect
+ github.com/prometheus/client_golang v1.20.2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
- github.com/prometheus/common v0.55.0 // indirect
+ github.com/prometheus/common v0.57.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
@@ -114,25 +117,25 @@ require (
github.com/urfave/cli v1.22.15 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
- go.etcd.io/etcd/api/v3 v3.5.14 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
- go.etcd.io/etcd/client/v3 v3.5.14 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
- go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 // indirect
- go.opentelemetry.io/contrib/samplers/jaegerremote v0.22.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
- go.opentelemetry.io/otel/metric v1.28.0 // indirect
- go.opentelemetry.io/otel/sdk v1.28.0 // indirect
- go.opentelemetry.io/otel/trace v1.28.0 // indirect
+ go.etcd.io/etcd/api/v3 v3.5.15 // indirect
+ go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect
+ go.etcd.io/etcd/client/v3 v3.5.15 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.54.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
+ go.opentelemetry.io/contrib/propagators/jaeger v1.29.0 // indirect
+ go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
+ go.opentelemetry.io/otel/metric v1.29.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.29.0 // indirect
+ go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
- golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
- golang.org/x/mod v0.18.0 // indirect
+ golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
+ golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect
golang.org/x/sync v0.8.0 // indirect
@@ -140,20 +143,20 @@ require (
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.6.0 // indirect
- golang.org/x/tools v0.22.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
- gonum.org/v1/gonum v0.14.0 // indirect
- google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/grpc v1.65.0 // indirect
+ gonum.org/v1/gonum v0.15.1 // indirect
+ google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/grpc v1.66.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
+ k8s.io/utils v0.0.0-20240821151609-f90d01438635 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum
index 365a5e0f8df2f..7907a6718b8cb 100644
--- a/pkg/aggregator/go.sum
+++ b/pkg/aggregator/go.sum
@@ -1,11 +1,12 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
+github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
-github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
-github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
+github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
+github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE=
github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
@@ -16,8 +17,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
-github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
-github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
+github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU=
+github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -25,8 +26,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
-github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071 h1:RdCf9hH3xq5vJifrjGB7zQlFkdRB3pAppcX2helDq2U=
-github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
+github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 h1:VnjHsRXCRti7Av7E+j4DCha3kf68echfDzQ+wD11SBU=
+github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
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/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
@@ -42,13 +43,12 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 h1:m62nsMU279qRD9PQSWD1l66kmkXzuYcnVJqL4XLeV2M=
-github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
-github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
+github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380 h1:1NyRx2f4W4WBRyg0Kys0ZbaNmDDzZ2R/C7DTi+bbsJ0=
+github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380/go.mod h1:thX175TtLTzLj3p7N/Q9IiKZ7NF+p72cvL91emV0hzo=
github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc0ytWPASlaPwQfQMQYnRf0RSDe1XvHw0Q=
github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
-github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
-github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
+github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -56,8 +56,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
-github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
-github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
+github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -65,8 +65,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
-github.com/getkin/kin-openapi v0.125.0 h1:jyQCyf2qXS1qvs2U00xQzkGCqYPhEhZDmSmVt65fXno=
-github.com/getkin/kin-openapi v0.125.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
+github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=
+github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -79,8 +79,8 @@ github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
-github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -88,8 +88,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
+github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -104,10 +104,10 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
-github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
-github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84=
-github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
+github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
+github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI=
+github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@@ -119,8 +119,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -128,10 +128,10 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grafana/grafana-plugin-sdk-go v0.244.0 h1:ZZxHbiiF6QcsnlbPFyZGmzNDoTC1pLeHXUQYoskWt5c=
-github.com/grafana/grafana-plugin-sdk-go v0.244.0/go.mod h1:H3FXrJMUlwocQ6UYj8Ds5I9EzRAVOcdRcgaRE3mXQqk=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grafana/grafana-plugin-sdk-go v0.245.0 h1:2KCKA86//O20ffL6WKzHGx5scBbdV7GyEFGnH8Hdv7M=
+github.com/grafana/grafana-plugin-sdk-go v0.245.0/go.mod h1:1X8Kgo/SK91Qo1WBCKjPSKrfgjpQys1OkQsHhA78TLg=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808213237-f4d2e064f435 h1:lmw60EW7JWlAEvgggktOyVkH4hF1m/+LSF/Ap0NCyi8=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808213237-f4d2e064f435/go.mod h1:ORVFiW/KNRY52lNjkGwnFWCxNVfE97bJG2jr2fetq0I=
github.com/grafana/grafana/pkg/semconv v0.0.0-20240808213237-f4d2e064f435 h1:SNEeqY22DrGr5E9kGF1mKSqlOom14W9+b1u4XEGJowA=
@@ -150,8 +150,8 @@ 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.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
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=
@@ -164,8 +164,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
-github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
-github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
+github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
+github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -181,8 +181,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
-github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
-github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
+github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -211,8 +211,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
@@ -247,23 +247,22 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
-github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
-github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
+github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
-github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
+github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -329,46 +328,46 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
-go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0=
-go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU=
-go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ=
-go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
+go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk=
+go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM=
+go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA=
+go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU=
go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8=
go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg=
-go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
-go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
+go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4=
+go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU=
go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M=
go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0=
go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw=
go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok=
go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0 h1:IVtyPth4Rs5P8wIf0mP2KVKFNTJ4paX9qQ4Hkh5gFdc=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0/go.mod h1:ImRBLMJv177/pwiLZ7tU7HDGNdBv7rS0HQ99eN/zBl8=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
-go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 h1:xQ3ktSVS128JWIaN1DiPGIjcH+GsvkibIAVRWFjS9eM=
-go.opentelemetry.io/contrib/propagators/jaeger v1.28.0/go.mod h1:O9HIyI2kVBrFoEwQZ0IN6PHXykGoit4mZV2aEjkTRH4=
-go.opentelemetry.io/contrib/samplers/jaegerremote v0.22.0 h1:OYxqumWcd1yaV/qvCt1B7Sru9OeUNGjeXq/oldx3AGk=
-go.opentelemetry.io/contrib/samplers/jaegerremote v0.22.0/go.mod h1:2tZTRqCbvx7nG57wUwd5NQpNVujOWnR84iPLllIH0Ok=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.54.0 h1:U9ge/19g8pkNXL+0eqeWgiJAd8nSmmvbvwehqyxU/Lc=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.54.0/go.mod h1:dmNhUi0Tl5v/3e0QNp7/3KLMvAPoHh4lMbZU319UkM0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/contrib/propagators/jaeger v1.29.0 h1:+YPiqF5rR6PqHBlmEFLPumbSP0gY0WmCGFayXRcCLvs=
+go.opentelemetry.io/contrib/propagators/jaeger v1.29.0/go.mod h1:6PD7q7qquWSp3Z4HeM3e/2ipRubaY1rXZO8NIHVDZjs=
+go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0 h1:qKi9ntCcronqWqfuKxqrxZlZd82jXJEgGiAWH1+phxo=
+go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0/go.mod h1:1kbAgQa5lgYC3rC6cE3jSxQ/Q13l33wv/WI8U+htwag=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
-go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
-go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
+go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
-go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
-go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
+go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
+go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
-go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
-go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
+go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
+go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
-go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
-go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
+go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -387,16 +386,16 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
-golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
+golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -455,35 +454,35 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
-gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
-gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
+gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
+gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
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-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
-google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c h1:TYOEhrQMrNDTAd2rX9m+WgGr8Ku6YNuj1D7OX6rWSok=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
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=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
-google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
+google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -521,10 +520,10 @@ k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs=
k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
diff --git a/pkg/api/dtos/dashboard.go b/pkg/api/dtos/dashboard.go
index 9d8f96f8c7aa6..66a8922a4f1a3 100644
--- a/pkg/api/dtos/dashboard.go
+++ b/pkg/api/dtos/dashboard.go
@@ -35,6 +35,7 @@ type DashboardMeta struct {
ProvisionedExternalId string `json:"provisionedExternalId"`
AnnotationsPermissions *dashboardsV0.AnnotationPermission `json:"annotationsPermissions"`
PublicDashboardEnabled bool `json:"publicDashboardEnabled,omitempty"`
+ HasPublicDashboard bool `json:"hasPublicDashboard,omitempty"`
}
type DashboardFullWithMeta struct {
diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go
index 9f5ac6b79fd9c..c3742b15dad4c 100644
--- a/pkg/api/http_server.go
+++ b/pkg/api/http_server.go
@@ -602,7 +602,7 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {
m.UseMiddleware(hs.Csrf.Middleware())
hs.mapStatic(m, hs.Cfg.StaticRootPath, "build", "public/build")
- hs.mapStatic(m, hs.Cfg.StaticRootPath, "", "public", "/public/views/swagger.html")
+ hs.mapStatic(m, hs.Cfg.StaticRootPath, "", "public", "/public/views/swagger-template.html")
hs.mapStatic(m, hs.Cfg.StaticRootPath, "robots.txt", "robots.txt")
if hs.Cfg.ImageUploadProvider == "local" {
diff --git a/pkg/api/plugin_resource_test.go b/pkg/api/plugin_resource_test.go
index a83a9400cc504..9ac339edbde17 100644
--- a/pkg/api/plugin_resource_test.go
+++ b/pkg/api/plugin_resource_test.go
@@ -51,7 +51,7 @@ func TestCallResource(t *testing.T) {
cfg.Azure = &azsettings.AzureSettings{}
coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), nil, &cloudwatch.CloudWatchService{}, nil, nil, nil, nil,
- nil, nil, nil, nil, testdatasource.ProvideService(), nil, nil, nil, nil, nil, nil)
+ nil, nil, nil, nil, testdatasource.ProvideService(), nil, nil, nil, nil, nil, nil, nil)
testCtx := pluginsintegration.CreateIntegrationTestCtx(t, cfg, coreRegistry)
diff --git a/pkg/api/static/static.go b/pkg/api/static/static.go
index 786cc5c55ba0a..eacbf10a29f3a 100644
--- a/pkg/api/static/static.go
+++ b/pkg/api/static/static.go
@@ -149,6 +149,7 @@ func staticHandler(ctx *web.Context, log log.Logger, opt StaticOptions) bool {
log.Error("Failed to close file", "error", err)
}
}()
+ httpFile := f
fi, err := f.Stat()
if err != nil {
@@ -183,10 +184,11 @@ func staticHandler(ctx *web.Context, log log.Logger, opt StaticOptions) bool {
}
}()
- fi, err = f.Stat()
+ fi, err = indexFile.Stat()
if err != nil || fi.IsDir() {
return true
}
+ httpFile = indexFile
}
if !opt.SkipLogging {
@@ -198,7 +200,7 @@ func staticHandler(ctx *web.Context, log log.Logger, opt StaticOptions) bool {
opt.AddHeaders(ctx)
}
- http.ServeContent(ctx.Resp, ctx.Req, file, fi.ModTime(), f)
+ http.ServeContent(ctx.Resp, ctx.Req, file, fi.ModTime(), httpFile)
return true
}
diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod
index 418e3beab91d6..7cae5389a2ccb 100644
--- a/pkg/apimachinery/go.mod
+++ b/pkg/apimachinery/go.mod
@@ -3,22 +3,22 @@ module github.com/grafana/grafana/pkg/apimachinery
go 1.23.0
require (
- github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db // @grafana/identity-access-team
- github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db // @grafana/identity-access-team
+ github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2 // @grafana/identity-access-team
+ github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2 // @grafana/identity-access-team
github.com/stretchr/testify v1.9.0
k8s.io/apimachinery v0.31.0
k8s.io/apiserver v0.31.0
- k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340
+ k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2
)
require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/emicklei/go-restful/v3 v3.11.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/jsonreference v0.20.4 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
@@ -37,14 +37,14 @@ require (
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/grpc v1.65.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/grpc v1.66.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
- k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
+ k8s.io/utils v0.0.0-20240821151609-f90d01438635 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)
diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum
index 66b4df6cb6c4a..46c32b3e12732 100644
--- a/pkg/apimachinery/go.sum
+++ b/pkg/apimachinery/go.sum
@@ -2,8 +2,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
-github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
+github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
@@ -12,8 +12,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
-github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -28,10 +28,10 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db h1:z++X4DdoX+aNlZNT1ZY4cykiFay4+f077pa0AG48SGg=
-github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db/go.mod h1:ptt910z9KFfpVSIbSbXvTRR7tS19mxD7EtmVbbJi/WE=
-github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db h1:mDk0bwRV6rDrLSmKXftcPf9kLA9uH6EvxJvzpPW9bso=
-github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
+github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2 h1:SU+p1ck8037cz6F8W38PIL9MzRb6YMeNqc7+GHDuqiU=
+github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY=
+github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2 h1:YTF1Y1BYCDkD7ssmbhzRqXlxevsYpXPmOnoO8qbOue8=
+github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -131,10 +131,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
-google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
-google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
+google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -154,10 +154,10 @@ k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY=
k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
diff --git a/pkg/apimachinery/identity/wrapper.go b/pkg/apimachinery/identity/wrapper.go
index 299a977a3cac0..a8171dc17ac06 100644
--- a/pkg/apimachinery/identity/wrapper.go
+++ b/pkg/apimachinery/identity/wrapper.go
@@ -102,3 +102,8 @@ func (i *IDClaimsWrapper) Scopes() []string {
func (i *IDClaimsWrapper) Subject() string {
return ""
}
+
+// IsNil implements claims.AccessClaims.
+func (i *IDClaimsWrapper) IsNil() bool {
+ return i.Source == nil
+}
diff --git a/pkg/apiserver/go.mod b/pkg/apiserver/go.mod
index 5e7937c7e4c00..10d0f6a42cd6c 100644
--- a/pkg/apiserver/go.mod
+++ b/pkg/apiserver/go.mod
@@ -4,16 +4,16 @@ go 1.23.0
require (
github.com/google/go-cmp v0.6.0
- github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db
+ github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240701135906-559738ce6ae1
- github.com/prometheus/client_golang v1.20.0
+ github.com/prometheus/client_golang v1.20.2
github.com/stretchr/testify v1.9.0
- go.opentelemetry.io/otel/trace v1.28.0
+ go.opentelemetry.io/otel/trace v1.29.0
k8s.io/apimachinery v0.31.0
k8s.io/apiserver v0.31.0
k8s.io/component-base v0.31.0
k8s.io/klog/v2 v2.130.1
- k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
+ k8s.io/utils v0.0.0-20240821151609-f90d01438635
)
require (
@@ -23,18 +23,19 @@ require (
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/emicklei/go-restful/v3 v3.11.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/jsonreference v0.20.4 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
- github.com/google/btree v1.1.2 // indirect
+ github.com/google/btree v1.1.3 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
@@ -48,16 +49,19 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
- github.com/prometheus/common v0.55.0 // indirect
+ github.com/prometheus/common v0.57.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
- go.etcd.io/etcd/api/v3 v3.5.14 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
- go.etcd.io/etcd/client/v3 v3.5.14 // indirect
- go.opentelemetry.io/otel v1.28.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
+ go.etcd.io/etcd/api/v3 v3.5.15 // indirect
+ go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect
+ go.etcd.io/etcd/client/v3 v3.5.15 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
+ go.opentelemetry.io/otel v1.29.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/net v0.28.0 // indirect
@@ -66,18 +70,17 @@ require (
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.6.0 // indirect
- golang.org/x/tools v0.22.0 // indirect
- google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/grpc v1.65.0 // indirect
+ google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/grpc v1.66.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.31.0 // indirect
k8s.io/client-go v0.31.0 // indirect
- k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
+ k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
diff --git a/pkg/apiserver/go.sum b/pkg/apiserver/go.sum
index 66724337e95cd..39766e6c64f9c 100644
--- a/pkg/apiserver/go.sum
+++ b/pkg/apiserver/go.sum
@@ -23,8 +23,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
-github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
+github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -41,8 +41,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
-github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -60,8 +60,8 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
-github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
+github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -71,14 +71,14 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db h1:mDk0bwRV6rDrLSmKXftcPf9kLA9uH6EvxJvzpPW9bso=
-github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2 h1:YTF1Y1BYCDkD7ssmbhzRqXlxevsYpXPmOnoO8qbOue8=
+github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240701135906-559738ce6ae1 h1:ItDcDxUjVLPKja+hogpqgW/kj8LxUL2qscelXIsN1Bs=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240701135906-559738ce6ae1/go.mod h1:DkxMin+qOh1Fgkxfbt+CUfBqqsCQJMG9op8Os/irBPA=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
@@ -87,8 +87,8 @@ 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.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -131,16 +131,16 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
-github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
-github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
+github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
-github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
+github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
@@ -173,36 +173,36 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
-go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0=
-go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU=
-go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ=
-go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
+go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk=
+go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM=
+go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA=
+go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU=
go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8=
go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg=
-go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
-go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
+go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4=
+go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU=
go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M=
go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0=
go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw=
go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok=
go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
-go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
-go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
-go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
-go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
-go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
-go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
-go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
-go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
+go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
+go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
+go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
+go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
+go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
+go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -272,8 +272,8 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -283,20 +283,20 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
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-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
-google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c h1:TYOEhrQMrNDTAd2rX9m+WgGr8Ku6YNuj1D7OX6rWSok=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
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=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
-google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
+google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -332,10 +332,10 @@ k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs=
k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
diff --git a/pkg/build/go.mod b/pkg/build/go.mod
index c547676f24c2d..852fc46d1ed4e 100644
--- a/pkg/build/go.mod
+++ b/pkg/build/go.mod
@@ -17,7 +17,7 @@ replace github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.
require (
cloud.google.com/go/storage v1.43.0 // @grafana/grafana-backend-group
- github.com/Masterminds/semver/v3 v3.2.0 // @grafana/grafana-release-guild
+ github.com/Masterminds/semver/v3 v3.3.0 // @grafana/grafana-release-guild
github.com/aws/aws-sdk-go v1.55.5 // @grafana/aws-datasources
github.com/blang/semver/v4 v4.0.0 // @grafana/grafana-release-guild
github.com/docker/docker v26.0.2+incompatible // @grafana/grafana-release-guild
@@ -32,27 +32,27 @@ require (
github.com/stretchr/testify v1.9.0 // @grafana/grafana-backend-group
github.com/urfave/cli v1.22.15 // @grafana/grafana-backend-group
github.com/urfave/cli/v2 v2.27.1 // @grafana/grafana-backend-group
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect; @grafana/plugins-platform-backend
- go.opentelemetry.io/otel v1.28.0 // indirect; @grafana/grafana-backend-group
- go.opentelemetry.io/otel/sdk v1.28.0 // indirect; @grafana/grafana-backend-group
- go.opentelemetry.io/otel/trace v1.28.0 // indirect; @grafana/grafana-backend-group
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect; @grafana/plugins-platform-backend
+ go.opentelemetry.io/otel v1.29.0 // indirect; @grafana/grafana-backend-group
+ go.opentelemetry.io/otel/sdk v1.29.0 // indirect; @grafana/grafana-backend-group
+ go.opentelemetry.io/otel/trace v1.29.0 // indirect; @grafana/grafana-backend-group
golang.org/x/crypto v0.26.0 // indirect; @grafana/grafana-backend-group
- golang.org/x/mod v0.18.0 // @grafana/grafana-backend-group
+ golang.org/x/mod v0.20.0 // @grafana/grafana-backend-group
golang.org/x/net v0.28.0 // indirect; @grafana/oss-big-tent @grafana/partner-datasources
golang.org/x/oauth2 v0.22.0 // @grafana/identity-access-team
golang.org/x/sync v0.8.0 // indirect; @grafana/alerting-backend
golang.org/x/text v0.17.0 // indirect; @grafana/grafana-backend-group
golang.org/x/time v0.6.0 // indirect; @grafana/grafana-backend-group
- golang.org/x/tools v0.22.0 // indirect; @grafana/grafana-as-code
- google.golang.org/api v0.191.0 // @grafana/grafana-backend-group
- google.golang.org/grpc v1.65.0 // indirect; @grafana/plugins-platform-backend
+ golang.org/x/tools v0.24.0 // indirect; @grafana/grafana-as-code
+ google.golang.org/api v0.195.0 // @grafana/grafana-backend-group
+ google.golang.org/grpc v1.66.0 // indirect; @grafana/plugins-platform-backend
google.golang.org/protobuf v1.34.2 // indirect; @grafana/plugins-platform-backend
gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-backend
)
require (
- cloud.google.com/go v0.115.0 // indirect
- cloud.google.com/go/auth v0.8.1 // indirect
+ cloud.google.com/go v0.115.1 // indirect
+ cloud.google.com/go/auth v0.9.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
cloud.google.com/go/iam v1.1.13 // indirect
@@ -83,39 +83,38 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opencensus.io v0.24.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
- go.opentelemetry.io/otel/metric v1.28.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
+ go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/sys v0.24.0 // indirect
- google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect; @grafana/grafana-backend-group
- google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect
+ google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c // indirect; @grafana/grafana-backend-group
+ google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
require dagger.io/dagger v0.11.8-rc.2
require (
- cloud.google.com/go/longrunning v0.5.12 // indirect
github.com/99designs/gqlgen v0.17.44 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
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/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/sosodev/duration v1.2.0 // indirect
github.com/vektah/gqlparser/v2 v2.5.11 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.2.0-alpha // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 // indirect
go.opentelemetry.io/otel/log v0.2.0-alpha // indirect
go.opentelemetry.io/otel/sdk/log v0.2.0-alpha // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
- golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
+ golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
gotest.tools/v3 v3.5.1 // indirect
)
diff --git a/pkg/build/go.sum b/pkg/build/go.sum
index 5eef149b39b6c..b30a2f78a38ae 100644
--- a/pkg/build/go.sum
+++ b/pkg/build/go.sum
@@ -1,8 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
-cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
-cloud.google.com/go/auth v0.8.1 h1:QZW9FjC5lZzN864p13YxvAtGUlQ+KgRL+8Sg45Z6vxo=
-cloud.google.com/go/auth v0.8.1/go.mod h1:qGVp/Y3kDRSDZ5gFD/XPUfYQ9xW1iI7q8RIRoCyBbJc=
+cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ=
+cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc=
+cloud.google.com/go/auth v0.9.1 h1:+pMtLEV2k0AXKvs/tGZojuj6QaioxfUjOpMsG5Gtx+w=
+cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk=
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
@@ -26,8 +26,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/Khan/genqlient v0.7.0 h1:GZ1meyRnzcDTK48EjqB8t3bcfYvHArCUUvgOwpz1D4w=
github.com/Khan/genqlient v0.7.0/go.mod h1:HNyy3wZvuYwmW3Y7mkoQLZsa/R5n5yIRajS1kPBvSFM=
-github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
-github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
+github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
@@ -145,8 +145,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksP
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-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/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
@@ -223,32 +223,32 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
-go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
-go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 h1:oM0GTNKGlc5qHctWeIGTVyda4iFFalOzMZ3Ehj5rwB4=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88/go.mod h1:JGG8ebaMO5nXOPnvKEl+DiA4MGwFjCbjsxT1WHIEBPY=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.2.0-alpha h1:z2s6Zba+OUyayRv5m1AXWNUTGh57K1iMhy6emU5QT5Y=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.2.0-alpha/go.mod h1:paOXXyUgPW6jYxYkP0pB47H2zHE1fPvMJ4E4G9LHOi0=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 h1:1wp/gyxsuYtuE/JFxsQRtcCDtMrO2qMvlfXALU5wkzI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0/go.mod h1:gbTHmghkGgqxMomVQQMur1Nba4M0MQ8AYThXDUjsJ38=
go.opentelemetry.io/otel/log v0.2.0-alpha h1:ixOPvMzserpqA07SENHvRzkZOsnG0XbPr74hv1AQ+n0=
go.opentelemetry.io/otel/log v0.2.0-alpha/go.mod h1:vbFZc65yq4c4ssvXY43y/nIqkNJLxORrqw0L85P59LA=
-go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
-go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
-go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
-go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
+go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
+go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
+go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
+go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk/log v0.2.0-alpha h1:jGTkL/jroJ31jnP6jDl34N/mDOfRGGYZHcHsCM+5kWA=
go.opentelemetry.io/otel/sdk/log v0.2.0-alpha/go.mod h1:Hd8Lw9FPGUM3pfY7iGMRvFaC2Nyau4Ajb5WnQ9OdIho=
-go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
-go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
+go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
@@ -262,15 +262,15 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
-golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
+golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -320,33 +320,33 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.191.0 h1:cJcF09Z+4HAB2t5qTQM1ZtfL/PemsLFkcFG67qq2afk=
-google.golang.org/api v0.191.0/go.mod h1:tD5dsFGxFza0hnQveGfVk9QQYKcfp+VzgRqyXFxE0+E=
+google.golang.org/api v0.195.0 h1:Ude4N8FvTKnnQJHU48RFI40jOBgIrL8Zqr3/QeST6yU=
+google.golang.org/api v0.195.0/go.mod h1:DOGRWuv3P8TU8Lnz7uQc4hyNqrBpMtD9ppW3wBJurgc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
-google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c h1:TYOEhrQMrNDTAd2rX9m+WgGr8Ku6YNuj1D7OX6rWSok=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
-google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
+google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
diff --git a/pkg/build/wire/go.mod b/pkg/build/wire/go.mod
index 9d3457f15bd33..0c5c674272f22 100644
--- a/pkg/build/wire/go.mod
+++ b/pkg/build/wire/go.mod
@@ -6,10 +6,10 @@ require (
github.com/google/go-cmp v0.6.0
github.com/google/subcommands v1.2.0
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
- golang.org/x/tools v0.22.0
+ golang.org/x/tools v0.24.0
)
require (
- golang.org/x/mod v0.18.0 // indirect
+ golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
)
diff --git a/pkg/build/wire/go.sum b/pkg/build/wire/go.sum
index 11eeab6f14af4..d5bd1d0d841ce 100644
--- a/pkg/build/wire/go.sum
+++ b/pkg/build/wire/go.sum
@@ -4,9 +4,9 @@ github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
diff --git a/pkg/plugins/backendplugin/coreplugin/registry.go b/pkg/plugins/backendplugin/coreplugin/registry.go
index 23dc4524f75bb..e9faacbb5dc47 100644
--- a/pkg/plugins/backendplugin/coreplugin/registry.go
+++ b/pkg/plugins/backendplugin/coreplugin/registry.go
@@ -20,6 +20,7 @@ import (
"github.com/grafana/grafana/pkg/tsdb/azuremonitor"
cloudmonitoring "github.com/grafana/grafana/pkg/tsdb/cloud-monitoring"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch"
+ "github.com/grafana/grafana/pkg/tsdb/druid"
"github.com/grafana/grafana/pkg/tsdb/elasticsearch"
postgres "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource"
pyroscope "github.com/grafana/grafana/pkg/tsdb/grafana-pyroscope-datasource"
@@ -45,6 +46,7 @@ const (
InfluxDB = "influxdb"
Loki = "loki"
OpenTSDB = "opentsdb"
+ Druid = "grafadruid-druid-datasource"
Prometheus = "prometheus"
Tempo = "tempo"
TestData = "grafana-testdata-datasource"
@@ -93,8 +95,8 @@ func NewRegistry(store map[string]backendplugin.PluginFactoryFunc) *Registry {
func ProvideCoreRegistry(tracer tracing.Tracer, am *azuremonitor.Service, cw *cloudwatch.CloudWatchService, cm *cloudmonitoring.Service,
es *elasticsearch.Service, grap *graphite.Service, idb *influxdb.Service, lk *loki.Service, otsdb *opentsdb.Service,
pr *prometheus.Service, t *tempo.Service, td *testdatasource.Service, pg *postgres.Service, my *mysql.Service,
- ms *mssql.Service, graf *grafanads.Service, pyroscope *pyroscope.Service, parca *parca.Service) *Registry {
- // Non-optimal global solution to replace plugin SDK default tracer for core plugins.
+ ms *mssql.Service, graf *grafanads.Service, pyroscope *pyroscope.Service, parca *parca.Service, dr *druid.Service) *Registry {
+
sdktracing.InitDefaultTracer(tracer)
return NewRegistry(map[string]backendplugin.PluginFactoryFunc{
@@ -115,6 +117,7 @@ func ProvideCoreRegistry(tracer tracing.Tracer, am *azuremonitor.Service, cw *cl
Grafana: asBackendPlugin(graf),
Pyroscope: asBackendPlugin(pyroscope),
Parca: asBackendPlugin(parca),
+ Druid: asBackendPlugin(dr),
})
}
diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod
index f3aea762a82a2..d78a49aaa90e0 100644
--- a/pkg/promlib/go.mod
+++ b/pkg/promlib/go.mod
@@ -3,50 +3,51 @@ module github.com/grafana/grafana/pkg/promlib
go 1.23.0
require (
- github.com/grafana/dskit v0.0.0-20240805174438-dfa83b4ed2d3
- github.com/grafana/grafana-plugin-sdk-go v0.244.0
+ github.com/grafana/dskit v0.0.0-20240827093408-28506cdffe6a
+ github.com/grafana/grafana-plugin-sdk-go v0.245.0
github.com/json-iterator/go v1.1.12
github.com/patrickmn/go-cache v2.1.0+incompatible
- github.com/prometheus/client_golang v1.20.0
- github.com/prometheus/common v0.55.0
+ github.com/prometheus/client_golang v1.20.2
+ github.com/prometheus/common v0.57.0
github.com/prometheus/prometheus v1.8.2-0.20221021121301-51a44e6657c3
github.com/stretchr/testify v1.9.0
- go.opentelemetry.io/otel v1.28.0
- go.opentelemetry.io/otel/trace v1.28.0
- golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
+ go.opentelemetry.io/otel v1.29.0
+ go.opentelemetry.io/otel/trace v1.29.0
+ golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
k8s.io/apimachinery v0.31.0
)
require (
- github.com/BurntSushi/toml v1.3.2 // indirect
- github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect
+ github.com/BurntSushi/toml v1.4.0 // indirect
+ github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 // indirect
github.com/apache/arrow/go/v15 v15.0.2 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go v1.55.5 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
+ github.com/bufbuild/protocompile v0.14.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
- github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071 // indirect
+ github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 // 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/dennwc/varint v1.0.0 // indirect
- github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 // indirect
- github.com/emicklei/go-restful/v3 v3.11.0 // indirect
- github.com/fatih/color v1.16.0 // indirect
+ github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380 // indirect
+ github.com/emicklei/go-restful/v3 v3.12.1 // indirect
+ github.com/fatih/color v1.17.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
- github.com/getkin/kin-openapi v0.125.0 // indirect
+ github.com/getkin/kin-openapi v0.127.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/jsonreference v0.20.4 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
+ github.com/goccy/go-json v0.10.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
@@ -57,26 +58,27 @@ require (
github.com/gorilla/mux v1.8.1 // indirect
github.com/grafana/otel-profiling-go v0.5.1 // indirect
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
- github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect
+ github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // 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.20.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.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
github.com/invopop/jsonschema v0.12.0 // indirect
github.com/invopop/yaml v0.3.1 // indirect
+ github.com/jhump/protoreflect v1.16.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
github.com/klauspost/compress v1.17.9 // indirect
- github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/magefile/mage v1.15.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattetti/filebuffer v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -101,36 +103,36 @@ require (
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0 // indirect
- go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 // indirect
- go.opentelemetry.io/contrib/samplers/jaegerremote v0.22.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
- go.opentelemetry.io/otel/metric v1.28.0 // indirect
- go.opentelemetry.io/otel/sdk v1.28.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.54.0 // indirect
+ go.opentelemetry.io/contrib/propagators/jaeger v1.29.0 // indirect
+ go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
+ go.opentelemetry.io/otel/metric v1.29.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/goleak v1.3.0 // indirect
- golang.org/x/mod v0.18.0 // indirect
+ golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
- golang.org/x/tools v0.22.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
- gonum.org/v1/gonum v0.14.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/grpc v1.65.0 // indirect
+ gonum.org/v1/gonum v0.15.1 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/grpc v1.66.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
- k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
- k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
+ k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 // indirect
+ k8s.io/utils v0.0.0-20240821151609-f90d01438635 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)
diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum
index 8a3cfef31d138..dd2864aaec3b4 100644
--- a/pkg/promlib/go.sum
+++ b/pkg/promlib/go.sum
@@ -1,8 +1,9 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs=
-github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
+github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
+github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg=
+github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE=
github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
@@ -13,8 +14,8 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
-github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
+github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU=
+github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@@ -23,8 +24,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
-github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071 h1:RdCf9hH3xq5vJifrjGB7zQlFkdRB3pAppcX2helDq2U=
-github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
+github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 h1:VnjHsRXCRti7Av7E+j4DCha3kf68echfDzQ+wD11SBU=
+github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
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=
@@ -34,16 +35,15 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
-github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 h1:m62nsMU279qRD9PQSWD1l66kmkXzuYcnVJqL4XLeV2M=
-github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
-github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
+github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380 h1:1NyRx2f4W4WBRyg0Kys0ZbaNmDDzZ2R/C7DTi+bbsJ0=
+github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380/go.mod h1:thX175TtLTzLj3p7N/Q9IiKZ7NF+p72cvL91emV0hzo=
github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc0ytWPASlaPwQfQMQYnRf0RSDe1XvHw0Q=
github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
-github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
-github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
+github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
-github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
-github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
+github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -51,8 +51,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
-github.com/getkin/kin-openapi v0.125.0 h1:jyQCyf2qXS1qvs2U00xQzkGCqYPhEhZDmSmVt65fXno=
-github.com/getkin/kin-openapi v0.125.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
+github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=
+github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
@@ -65,14 +65,14 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
-github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
+github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -96,22 +96,22 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/grafana/dskit v0.0.0-20240805174438-dfa83b4ed2d3 h1:as4PmrFoYI1byS5JjsgPC7uSGTMh+SgS0ePv6hOyDGU=
-github.com/grafana/dskit v0.0.0-20240805174438-dfa83b4ed2d3/go.mod h1:lcjGB6SuaZ2o44A9nD6p/tR4QXSPbzViRY520Gy6pTQ=
-github.com/grafana/grafana-plugin-sdk-go v0.244.0 h1:ZZxHbiiF6QcsnlbPFyZGmzNDoTC1pLeHXUQYoskWt5c=
-github.com/grafana/grafana-plugin-sdk-go v0.244.0/go.mod h1:H3FXrJMUlwocQ6UYj8Ds5I9EzRAVOcdRcgaRE3mXQqk=
+github.com/grafana/dskit v0.0.0-20240827093408-28506cdffe6a h1:W8y+Tcv22oamhXX9auACKIwLu7y3XmT/v1oF30g/vbE=
+github.com/grafana/dskit v0.0.0-20240827093408-28506cdffe6a/go.mod h1:wJbJeQ2ygiGuBKsur7BPPNe+3pSyHEDPtKa7IU3I8ZA=
+github.com/grafana/grafana-plugin-sdk-go v0.245.0 h1:2KCKA86//O20ffL6WKzHGx5scBbdV7GyEFGnH8Hdv7M=
+github.com/grafana/grafana-plugin-sdk-go v0.245.0/go.mod h1:1X8Kgo/SK91Qo1WBCKjPSKrfgjpQys1OkQsHhA78TLg=
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
-github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db h1:7aN5cccjIqCLTzedH7MZzRZt5/lsAHch6Z3L2ZGn5FA=
-github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
+github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=
+github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
-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/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
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=
@@ -122,8 +122,8 @@ github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10C
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
-github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
-github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
+github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
+github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -141,8 +141,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
-github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
-github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
+github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -165,8 +165,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
@@ -199,12 +199,12 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
-github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
+github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
-github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
-github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
+github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4=
github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
@@ -214,7 +214,6 @@ github.com/prometheus/prometheus v1.8.2-0.20221021121301-51a44e6657c3/go.mod h1:
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -234,7 +233,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -263,32 +261,32 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0 h1:IVtyPth4Rs5P8wIf0mP2KVKFNTJ4paX9qQ4Hkh5gFdc=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0/go.mod h1:ImRBLMJv177/pwiLZ7tU7HDGNdBv7rS0HQ99eN/zBl8=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
-go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 h1:xQ3ktSVS128JWIaN1DiPGIjcH+GsvkibIAVRWFjS9eM=
-go.opentelemetry.io/contrib/propagators/jaeger v1.28.0/go.mod h1:O9HIyI2kVBrFoEwQZ0IN6PHXykGoit4mZV2aEjkTRH4=
-go.opentelemetry.io/contrib/samplers/jaegerremote v0.22.0 h1:OYxqumWcd1yaV/qvCt1B7Sru9OeUNGjeXq/oldx3AGk=
-go.opentelemetry.io/contrib/samplers/jaegerremote v0.22.0/go.mod h1:2tZTRqCbvx7nG57wUwd5NQpNVujOWnR84iPLllIH0Ok=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.54.0 h1:U9ge/19g8pkNXL+0eqeWgiJAd8nSmmvbvwehqyxU/Lc=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.54.0/go.mod h1:dmNhUi0Tl5v/3e0QNp7/3KLMvAPoHh4lMbZU319UkM0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/contrib/propagators/jaeger v1.29.0 h1:+YPiqF5rR6PqHBlmEFLPumbSP0gY0WmCGFayXRcCLvs=
+go.opentelemetry.io/contrib/propagators/jaeger v1.29.0/go.mod h1:6PD7q7qquWSp3Z4HeM3e/2ipRubaY1rXZO8NIHVDZjs=
+go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0 h1:qKi9ntCcronqWqfuKxqrxZlZd82jXJEgGiAWH1+phxo=
+go.opentelemetry.io/contrib/samplers/jaegerremote v0.23.0/go.mod h1:1kbAgQa5lgYC3rC6cE3jSxQ/Q13l33wv/WI8U+htwag=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
-go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
-go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
+go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
-go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
-go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
+go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
+go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
-go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
-go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
+go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
+go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
-go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
-go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
+go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -298,12 +296,12 @@ go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
-golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
+golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -342,22 +340,22 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
-gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
-gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
-google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
-google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
+gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
+google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -378,10 +376,10 @@ k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc=
k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
diff --git a/pkg/semconv/go.mod b/pkg/semconv/go.mod
index 1217b154a55d4..81429a73accd5 100644
--- a/pkg/semconv/go.mod
+++ b/pkg/semconv/go.mod
@@ -2,7 +2,7 @@ module github.com/grafana/grafana/pkg/semconv
go 1.23.0
-require go.opentelemetry.io/otel v1.28.0
+require go.opentelemetry.io/otel v1.29.0
require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
diff --git a/pkg/semconv/go.sum b/pkg/semconv/go.sum
index 6601c18dd25f6..bf61a1563d6dd 100644
--- a/pkg/semconv/go.sum
+++ b/pkg/semconv/go.sum
@@ -6,7 +6,7 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
-go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
+go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/pkg/server/wire.go b/pkg/server/wire.go
index 47aa9aedc38ff..4b2a8f9f62d0f 100644
--- a/pkg/server/wire.go
+++ b/pkg/server/wire.go
@@ -156,6 +156,7 @@ import (
"github.com/grafana/grafana/pkg/tsdb/azuremonitor"
cloudmonitoring "github.com/grafana/grafana/pkg/tsdb/cloud-monitoring"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch"
+ "github.com/grafana/grafana/pkg/tsdb/druid"
"github.com/grafana/grafana/pkg/tsdb/elasticsearch"
postgres "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource"
pyroscope "github.com/grafana/grafana/pkg/tsdb/grafana-pyroscope-datasource"
@@ -173,6 +174,9 @@ import (
)
var wireBasicSet = wire.NewSet(
+ druid.ProvideService,
+ // legacydataservice.ProvideService,
+ // wire.Bind(new(legacydata.RequestHandler), new(*legacydataservice.Service)),
annotationsimpl.ProvideService,
wire.Bind(new(annotations.Repository), new(*annotationsimpl.RepositoryImpl)),
New,
diff --git a/pkg/services/authn/clients/ext_jwt.go b/pkg/services/authn/clients/ext_jwt.go
index f1fd557fc91a8..db7285c472980 100644
--- a/pkg/services/authn/clients/ext_jwt.go
+++ b/pkg/services/authn/clients/ext_jwt.go
@@ -8,7 +8,7 @@ import (
"github.com/go-jose/go-jose/v3/jwt"
authlib "github.com/grafana/authlib/authn"
- authlibclaims "github.com/grafana/authlib/claims"
+ "github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/apimachinery/identity"
@@ -74,7 +74,7 @@ type ExtendedJWT struct {
func (s *ExtendedJWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
jwtToken := s.retrieveAuthenticationToken(r.HTTPRequest)
- claims, err := s.accessTokenVerifier.Verify(ctx, jwtToken)
+ accessTokenClaims, err := s.accessTokenVerifier.Verify(ctx, jwtToken)
if err != nil {
return nil, errExtJWTInvalid.Errorf("failed to verify access token: %w", err)
}
@@ -86,10 +86,10 @@ func (s *ExtendedJWT) Authenticate(ctx context.Context, r *authn.Request) (*auth
return nil, errExtJWTInvalid.Errorf("failed to verify id token: %w", err)
}
- return s.authenticateAsUser(idTokenClaims, claims)
+ return s.authenticateAsUser(*idTokenClaims, *accessTokenClaims)
}
- return s.authenticateAsService(claims)
+ return s.authenticateAsService(*accessTokenClaims)
}
func (s *ExtendedJWT) IsEnabled() bool {
@@ -97,16 +97,16 @@ func (s *ExtendedJWT) IsEnabled() bool {
}
func (s *ExtendedJWT) authenticateAsUser(
- idTokenClaims *authlib.Claims[authlib.IDTokenClaims],
- accessTokenClaims *authlib.Claims[authlib.AccessTokenClaims],
+ idTokenClaims authlib.Claims[authlib.IDTokenClaims],
+ accessTokenClaims authlib.Claims[authlib.AccessTokenClaims],
) (*authn.Identity, error) {
// Only allow id tokens signed for namespace configured for this instance.
- if allowedNamespace := s.namespaceMapper(s.getDefaultOrgID()); idTokenClaims.Rest.Namespace != allowedNamespace {
+ if allowedNamespace := s.namespaceMapper(s.getDefaultOrgID()); !claims.NamespaceMatches(authlib.NewIdentityClaims(idTokenClaims), allowedNamespace) {
return nil, errExtJWTDisallowedNamespaceClaim.Errorf("unexpected id token namespace: %s", idTokenClaims.Rest.Namespace)
}
// Allow access tokens with either the same namespace as the validated id token namespace or wildcard (`*`).
- if !accessTokenClaims.Rest.NamespaceMatches(idTokenClaims.Rest.Namespace) {
+ if !claims.NamespaceMatches(authlib.NewAccessClaims(accessTokenClaims), idTokenClaims.Rest.Namespace) {
return nil, errExtJWTMisMatchedNamespaceClaims.Errorf("unexpected access token namespace: %s", accessTokenClaims.Rest.Namespace)
}
@@ -115,7 +115,7 @@ func (s *ExtendedJWT) authenticateAsUser(
return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", accessTokenClaims.Subject)
}
- if !authlibclaims.IsIdentityType(accessType, authlibclaims.TypeAccessPolicy) {
+ if !claims.IsIdentityType(accessType, claims.TypeAccessPolicy) {
return nil, errExtJWTInvalid.Errorf("unexpected identity: %s", accessTokenClaims.Subject)
}
@@ -124,7 +124,7 @@ func (s *ExtendedJWT) authenticateAsUser(
return nil, errExtJWTInvalid.Errorf("failed to parse id token subject: %w", err)
}
- if !authlibclaims.IsIdentityType(t, authlibclaims.TypeUser) {
+ if !claims.IsIdentityType(t, claims.TypeUser) {
return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", idTokenClaims.Subject)
}
@@ -139,6 +139,8 @@ func (s *ExtendedJWT) authenticateAsUser(
ID: id,
Type: t,
OrgID: s.getDefaultOrgID(),
+ AccessTokenClaims: &accessTokenClaims,
+ IDTokenClaims: &idTokenClaims,
AuthenticatedBy: login.ExtendedJWTModule,
AuthID: accessTokenClaims.Subject,
AllowedKubernetesNamespace: allowedKubernetesNamespace,
@@ -151,19 +153,19 @@ func (s *ExtendedJWT) authenticateAsUser(
}}, nil
}
-func (s *ExtendedJWT) authenticateAsService(claims *authlib.Claims[authlib.AccessTokenClaims]) (*authn.Identity, error) {
+func (s *ExtendedJWT) authenticateAsService(accessTokenClaims authlib.Claims[authlib.AccessTokenClaims]) (*authn.Identity, error) {
// Allow access tokens with that has a wildcard namespace or a namespace matching this instance.
- if allowedNamespace := s.namespaceMapper(s.getDefaultOrgID()); !claims.Rest.NamespaceMatches(allowedNamespace) {
- return nil, errExtJWTDisallowedNamespaceClaim.Errorf("unexpected access token namespace: %s", claims.Rest.Namespace)
+ if allowedNamespace := s.namespaceMapper(s.getDefaultOrgID()); !claims.NamespaceMatches(authlib.NewAccessClaims(accessTokenClaims), allowedNamespace) {
+ return nil, errExtJWTDisallowedNamespaceClaim.Errorf("unexpected access token namespace: %s", accessTokenClaims.Rest.Namespace)
}
- t, id, err := identity.ParseTypeAndID(claims.Subject)
+ t, id, err := identity.ParseTypeAndID(accessTokenClaims.Subject)
if err != nil {
return nil, fmt.Errorf("failed to parse access token subject: %w", err)
}
- if !authlibclaims.IsIdentityType(t, authlibclaims.TypeAccessPolicy) {
- return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", claims.Subject)
+ if !claims.IsIdentityType(t, claims.TypeAccessPolicy) {
+ return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", accessTokenClaims.Subject)
}
return &authn.Identity{
@@ -171,13 +173,15 @@ func (s *ExtendedJWT) authenticateAsService(claims *authlib.Claims[authlib.Acces
UID: id,
Type: t,
OrgID: s.getDefaultOrgID(),
+ AccessTokenClaims: &accessTokenClaims,
+ IDTokenClaims: nil,
AuthenticatedBy: login.ExtendedJWTModule,
- AuthID: claims.Subject,
- AllowedKubernetesNamespace: claims.Rest.Namespace,
+ AuthID: accessTokenClaims.Subject,
+ AllowedKubernetesNamespace: accessTokenClaims.Rest.Namespace,
ClientParams: authn.ClientParams{
SyncPermissions: true,
FetchPermissionsParams: authn.FetchPermissionsParams{
- Roles: claims.Rest.Permissions,
+ Roles: accessTokenClaims.Rest.Permissions,
},
FetchSyncedUser: false,
},
diff --git a/pkg/services/authn/identity.go b/pkg/services/authn/identity.go
index 4a0da892d8de0..3014c1148f556 100644
--- a/pkg/services/authn/identity.go
+++ b/pkg/services/authn/identity.go
@@ -72,8 +72,9 @@ type Identity struct {
// Permissions is the list of permissions the entity has.
Permissions map[int64]map[string][]string
// IDToken is a signed token representing the identity that can be forwarded to plugins and external services.
- IDToken string
- IDTokenClaims *authn.Claims[authn.IDTokenClaims]
+ IDToken string
+ IDTokenClaims *authn.Claims[authn.IDTokenClaims]
+ AccessTokenClaims *authn.Claims[authn.AccessTokenClaims]
}
// Access implements claims.AuthInfo.
diff --git a/pkg/services/authz/client.go b/pkg/services/authz/client.go
index 69f68f5cf947d..eb22e20de87d5 100644
--- a/pkg/services/authz/client.go
+++ b/pkg/services/authz/client.go
@@ -8,6 +8,7 @@ import (
authnlib "github.com/grafana/authlib/authn"
authzlib "github.com/grafana/authlib/authz"
authzv1 "github.com/grafana/authlib/authz/proto/v1"
+ "github.com/grafana/authlib/claims"
grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
@@ -105,7 +106,7 @@ func newInProcLegacyClient(server *legacyServer) (authzlib.MultiTenantClient, er
&authzlib.MultiTenantClientConfig{},
authzlib.WithGrpcConnectionLCOption(channel),
// nolint:staticcheck
- authzlib.WithNamespaceFormatterLCOption(authnlib.OnPremNamespaceFormatter),
+ authzlib.WithNamespaceFormatterLCOption(claims.OrgNamespaceFormatter),
authzlib.WithDisableAccessTokenLCOption(),
)
}
@@ -129,7 +130,7 @@ func newGrpcLegacyClient(address string) (authzlib.MultiTenantClient, error) {
grpc.WithStreamInterceptor(clientInterceptor.StreamClientInterceptor),
),
// nolint:staticcheck
- authzlib.WithNamespaceFormatterLCOption(authnlib.OnPremNamespaceFormatter),
+ authzlib.WithNamespaceFormatterLCOption(claims.OrgNamespaceFormatter),
// TODO(drclau): remove this once we have access token support on-prem
authzlib.WithDisableAccessTokenLCOption(),
)
diff --git a/pkg/services/featuremgmt/models.go b/pkg/services/featuremgmt/models.go
index 6260547585ba3..c4b6d4a091c50 100644
--- a/pkg/services/featuremgmt/models.go
+++ b/pkg/services/featuremgmt/models.go
@@ -130,6 +130,8 @@ type FeatureFlag struct {
// The server must be initialized with the value
RequiresRestart bool `json:"requiresRestart,omitempty"`
+
+ FlagPublicDashboards bool `json:"flagPublicDashboards,omitempty"` // flag for public dashboards
}
type FeatureToggleWebhookPayload struct {
diff --git a/pkg/services/ldap/ldap_login_test.go b/pkg/services/ldap/ldap_login_test.go
deleted file mode 100644
index 11d1d8a6cfc13..0000000000000
--- a/pkg/services/ldap/ldap_login_test.go
+++ /dev/null
@@ -1,258 +0,0 @@
-package ldap
-
-import (
- "errors"
- "testing"
-
- "github.com/go-ldap/ldap/v3"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- "github.com/grafana/grafana/pkg/infra/log"
- "github.com/grafana/grafana/pkg/services/login"
-)
-
-var defaultLogin = &login.LoginUserQuery{
- Username: "user",
- Password: "pwd",
- IpAddress: "192.168.1.1:56433",
-}
-
-func TestServer_Login_UserBind_Fail(t *testing.T) {
- connection := &MockConnection{}
- entry := ldap.Entry{}
- result := ldap.SearchResult{Entries: []*ldap.Entry{&entry}}
- connection.setSearchResult(&result)
-
- connection.BindProvider = func(username, password string) error {
- return &ldap.Error{
- ResultCode: 49,
- }
- }
-
- cfg := &Config{
- Enabled: true,
- }
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: connection,
- log: log.New("test-logger"),
- }
-
- _, err := server.Login(defaultLogin)
-
- assert.ErrorIs(t, err, ErrInvalidCredentials)
-}
-
-func TestServer_Login_Search_NoResult(t *testing.T) {
- connection := &MockConnection{}
- result := ldap.SearchResult{Entries: []*ldap.Entry{}}
- connection.setSearchResult(&result)
-
- connection.BindProvider = func(username, password string) error {
- return nil
- }
- server := &Server{
- Config: &ServerConfig{
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: connection,
- log: log.New("test-logger"),
- }
-
- _, err := server.Login(defaultLogin)
- assert.ErrorIs(t, err, ErrCouldNotFindUser)
-}
-
-func TestServer_Login_Search_Error(t *testing.T) {
- connection := &MockConnection{}
- expected := errors.New("Killa-gorilla")
- connection.setSearchError(expected)
-
- connection.BindProvider = func(username, password string) error {
- return nil
- }
- server := &Server{
- Config: &ServerConfig{
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: connection,
- log: log.New("test-logger"),
- }
-
- _, err := server.Login(defaultLogin)
- assert.ErrorIs(t, err, expected)
-}
-
-func TestServer_Login_ValidCredentials(t *testing.T) {
- connection := &MockConnection{}
- entry := ldap.Entry{
- DN: "dn", Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"markelog"}},
- {Name: "surname", Values: []string{"Gaidarenko"}},
- {Name: "email", Values: []string{"markelog@gmail.com"}},
- {Name: "name", Values: []string{"Oleg"}},
- {Name: "memberof", Values: []string{"admins"}},
- },
- }
- result := ldap.SearchResult{Entries: []*ldap.Entry{&entry}}
- connection.setSearchResult(&result)
-
- connection.BindProvider = func(username, password string) error {
- return nil
- }
-
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Attr: AttributeMap{
- Username: "username",
- Name: "name",
- MemberOf: "memberof",
- },
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: connection,
- log: log.New("test-logger"),
- }
-
- resp, err := server.Login(defaultLogin)
- require.NoError(t, err)
- assert.Equal(t, "markelog", resp.Login)
-}
-
-// TestServer_Login_UnauthenticatedBind tests that unauthenticated bind
-// is called when there is no admin password or user wildcard in the
-// bind_dn.
-func TestServer_Login_UnauthenticatedBind(t *testing.T) {
- connection := &MockConnection{}
- entry := ldap.Entry{
- DN: "test",
- }
- result := ldap.SearchResult{Entries: []*ldap.Entry{&entry}}
- connection.setSearchResult(&result)
-
- connection.UnauthenticatedBindProvider = func() error {
- return nil
- }
-
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: connection,
- log: log.New("test-logger"),
- }
-
- user, err := server.Login(defaultLogin)
- require.NoError(t, err)
- assert.Equal(t, "test", user.AuthId)
- assert.True(t, connection.UnauthenticatedBindCalled)
-}
-
-func TestServer_Login_AuthenticatedBind(t *testing.T) {
- connection := &MockConnection{}
- entry := ldap.Entry{
- DN: "test",
- }
- result := ldap.SearchResult{Entries: []*ldap.Entry{&entry}}
- connection.setSearchResult(&result)
-
- adminUsername := ""
- adminPassword := ""
- username := ""
- password := ""
-
- i := 0
- connection.BindProvider = func(name, pass string) error {
- i++
- if i == 1 {
- adminUsername = name
- adminPassword = pass
- }
-
- if i == 2 {
- username = name
- password = pass
- }
-
- return nil
- }
-
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- BindDN: "killa",
- BindPassword: "gorilla",
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: connection,
- log: log.New("test-logger"),
- }
-
- user, err := server.Login(defaultLogin)
- require.NoError(t, err)
-
- assert.Equal(t, "test", user.AuthId)
- assert.True(t, connection.BindCalled)
-
- assert.Equal(t, "killa", adminUsername)
- assert.Equal(t, "gorilla", adminPassword)
-
- assert.Equal(t, "test", username)
- assert.Equal(t, "pwd", password)
-}
-
-func TestServer_Login_UserWildcardBind(t *testing.T) {
- connection := &MockConnection{}
- entry := ldap.Entry{
- DN: "test",
- }
- connection.setSearchResult(&ldap.SearchResult{Entries: []*ldap.Entry{&entry}})
-
- authBindUser := ""
- authBindPassword := ""
-
- connection.BindProvider = func(name, pass string) error {
- authBindUser = name
- authBindPassword = pass
- return nil
- }
-
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- BindDN: "cn=%s,ou=users,dc=grafana,dc=org",
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: connection,
- log: log.New("test-logger"),
- }
-
- _, err := server.Login(defaultLogin)
- require.NoError(t, err)
-
- assert.Equal(t, "cn=user,ou=users,dc=grafana,dc=org", authBindUser)
- assert.Equal(t, "pwd", authBindPassword)
- assert.True(t, connection.BindCalled)
-}
diff --git a/pkg/services/ldap/ldap_private_test.go b/pkg/services/ldap/ldap_private_test.go
deleted file mode 100644
index 6dc52c19ba7c2..0000000000000
--- a/pkg/services/ldap/ldap_private_test.go
+++ /dev/null
@@ -1,283 +0,0 @@
-package ldap
-
-import (
- "testing"
-
- "github.com/go-ldap/ldap/v3"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- "github.com/grafana/grafana/pkg/infra/log"
- "github.com/grafana/grafana/pkg/services/login"
- "github.com/grafana/grafana/pkg/services/org"
-)
-
-func TestServer_getSearchRequest(t *testing.T) {
- expected := &ldap.SearchRequest{
- BaseDN: "killa",
- Scope: 2,
- DerefAliases: 0,
- SizeLimit: 0,
- TimeLimit: 0,
- TypesOnly: false,
- Filter: "(|)",
- Attributes: []string{
- "username",
- "email",
- "name",
- "memberof",
- "gansta",
- },
- Controls: nil,
- }
-
- server := &Server{
- Config: &ServerConfig{
- Attr: AttributeMap{
- Username: "username",
- Name: "name",
- MemberOf: "memberof",
- Email: "email",
- },
- GroupSearchFilterUserAttribute: "gansta",
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- log: log.New("test-logger"),
- }
-
- result := server.getSearchRequest("killa", []string{"gorilla"})
-
- assert.EqualValues(t, expected, result)
-}
-
-func TestSerializeUsers(t *testing.T) {
- t.Run("simple case", func(t *testing.T) {
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Attr: AttributeMap{
- Username: "username",
- Name: "name",
- MemberOf: "memberof",
- Email: "email",
- },
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: &MockConnection{},
- log: log.New("test-logger"),
- }
-
- entry := ldap.Entry{
- DN: "dn",
- Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"roelgerrits"}},
- {Name: "surname", Values: []string{"Gerrits"}},
- {Name: "email", Values: []string{"roel@test.com"}},
- {Name: "name", Values: []string{"Roel"}},
- {Name: "memberof", Values: []string{"admins"}},
- },
- }
- users := [][]*ldap.Entry{{&entry}}
-
- result, err := server.serializeUsers(users)
- require.NoError(t, err)
-
- assert.Equal(t, "roelgerrits", result[0].Login)
- assert.Equal(t, "roel@test.com", result[0].Email)
- assert.Contains(t, result[0].Groups, "admins")
- })
-
- t.Run("without lastname", func(t *testing.T) {
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Attr: AttributeMap{
- Username: "username",
- Name: "name",
- MemberOf: "memberof",
- Email: "email",
- },
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: &MockConnection{},
- log: log.New("test-logger"),
- }
-
- entry := ldap.Entry{
- DN: "dn",
- Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"roelgerrits"}},
- {Name: "email", Values: []string{"roel@test.com"}},
- {Name: "name", Values: []string{"Roel"}},
- {Name: "memberof", Values: []string{"admins"}},
- },
- }
- users := [][]*ldap.Entry{{&entry}}
-
- result, err := server.serializeUsers(users)
- require.NoError(t, err)
-
- assert.False(t, result[0].IsDisabled)
- assert.Equal(t, "Roel", result[0].Name)
- })
-
- t.Run("mark user without matching group as disabled", func(t *testing.T) {
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Groups: []*GroupToOrgRole{{
- GroupDN: "foo",
- OrgId: 1,
- OrgRole: org.RoleEditor,
- }},
- },
- Connection: &MockConnection{},
- log: log.New("test-logger"),
- }
-
- entry := ldap.Entry{
- DN: "dn",
- Attributes: []*ldap.EntryAttribute{
- {Name: "memberof", Values: []string{"admins"}},
- },
- }
- users := [][]*ldap.Entry{{&entry}}
-
- result, err := server.serializeUsers(users)
- require.NoError(t, err)
-
- assert.Len(t, result, 1)
- assert.True(t, result[0].IsDisabled)
- })
-}
-
-func TestServer_validateGrafanaUser(t *testing.T) {
- t.Run("no group config", func(t *testing.T) {
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Groups: []*GroupToOrgRole{},
- },
- log: logger.New("test"),
- }
-
- user := &login.ExternalUserInfo{
- Login: "markelog",
- }
-
- err := server.validateGrafanaUser(user)
- require.NoError(t, err)
- })
-
- t.Run("user in group", func(t *testing.T) {
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Groups: []*GroupToOrgRole{
- {
- OrgId: 1,
- },
- },
- },
- log: logger.New("test"),
- }
-
- user := &login.ExternalUserInfo{
- Login: "markelog",
- OrgRoles: map[int64]org.RoleType{
- 1: "test",
- },
- }
-
- err := server.validateGrafanaUser(user)
- require.NoError(t, err)
- })
-
- t.Run("user not in group", func(t *testing.T) {
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Groups: []*GroupToOrgRole{
- {
- OrgId: 1,
- },
- },
- },
- log: logger.New("test"),
- }
-
- user := &login.ExternalUserInfo{
- Login: "markelog",
- }
-
- err := server.validateGrafanaUser(user)
- require.ErrorIs(t, err, ErrInvalidCredentials)
- })
-}
-
-func TestServer_binds(t *testing.T) {
- t.Run("single bind with cn wildcard", func(t *testing.T) {
- server := &Server{
- Config: &ServerConfig{
- BindDN: "cn=%s,dc=grafana,dc=org",
- },
- }
-
- assert.True(t, server.shouldSingleBind())
- assert.Equal(t, "cn=test,dc=grafana,dc=org", server.singleBindDN("test"))
- })
-
- t.Run("don't single bind", func(t *testing.T) {
- server := &Server{
- Config: &ServerConfig{
- BindDN: "cn=admin,dc=grafana,dc=org",
- },
- }
-
- assert.False(t, server.shouldSingleBind())
- })
-
- t.Run("admin user bind", func(t *testing.T) {
- server := &Server{
- Config: &ServerConfig{
- BindPassword: "test",
- },
- }
-
- assert.True(t, server.shouldAdminBind())
- })
-
- t.Run("don't admin user bind", func(t *testing.T) {
- server := &Server{
- Config: &ServerConfig{
- BindPassword: "",
- },
- }
-
- assert.False(t, server.shouldAdminBind())
- })
-}
diff --git a/pkg/services/ldap/ldap_test.go b/pkg/services/ldap/ldap_test.go
deleted file mode 100644
index b67686654184c..0000000000000
--- a/pkg/services/ldap/ldap_test.go
+++ /dev/null
@@ -1,647 +0,0 @@
-package ldap
-
-import (
- "errors"
- "fmt"
- "testing"
-
- "github.com/go-ldap/ldap/v3"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- "github.com/grafana/grafana/pkg/apimachinery/identity"
- "github.com/grafana/grafana/pkg/infra/log"
-)
-
-const (
- validCert = `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURYVENDQWtXZ0F3SUJBZ0lKQUxtVlZ1RFd1NE5ZTUEwR0NTcUdTSWIzRFFFQkN
-3VUFNRVV4Q3pBSkJnTlYKQkFZVEFrRlZNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFd0h3WURWUVFLREJoSmJuUmxjbTVsZENCWAphV1JuYVhSekl
-GQjBlU0JNZEdRd0hoY05NVFl4TWpNeE1UUXpORFEzV2hjTk5EZ3dOakkxTVRRek5EUTNXakJGCk1Rc3dDUVlEVlFRR0V3SkJWVEVUTUJFR0ExVUVDQXdLVTI
-5dFpTMVRkR0YwWlRFaE1COEdBMVVFQ2d3WVNXNTAKWlhKdVpYUWdWMmxrWjJsMGN5QlFkSGtnVEhSa01JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUTh
-BTUlJQgpDZ0tDQVFFQXpVQ0ZvemdOYjFoMU0wanpOUlNDamhPQm5SK3VWYlZwYVdmWFlJUitBaFdEZEVlNXJ5WStDZ2F2Ck9nOGJmTHlieXpGZGVobFlkRFJ
-na2VkRUIvR2pHOGFKdzA2bDBxRjRqRE9BdzBrRXlnV0N1Mm1jSDdYT3hSdCsKWUFIM1RWSGEvSHUxVzNXanprb2JxcXFMUThna0tXV00yN2ZPZ0FaNkdpZWF
-KQk42VkJTTU1jUGV5M0hXTEJtYworVFlKbXYxZGJhTzJqSGhLaDhwZkt3MFcxMlZNOFAxUElPOGd2NFBodS91dUpZaWVCV0tpeEJFeXkwbEhqeWl4CllGQ1I
-xMnhkaDRDQTQ3cTk1OFpSR25uRFVHRlZFMVFoZ1JhY0pDT1o5YmQ1dDltcjhLTGFWQllUQ0pvNUVSRTgKanltYWI1ZFBxZTVxS2ZKc0NaaXFXZ2xialVvOXR
-3SURBUUFCbzFBd1RqQWRCZ05WSFE0RUZnUVV4cHV3Y3MvQwpZUU95dWkrcjFHKzNLeEJOaHhrd0h3WURWUjBqQkJnd0ZvQVV4cHV3Y3MvQ1lRT3l1aStyMUc
-rM0t4Qk5oeGt3CkRBWURWUjBUQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQWlXVUtzLzJ4L3ZpTkNLaTNZNmIKbEV1Q3RBR2h6T09aOUV
-qcnZKOCtDT0gzUmFnM3RWQldyY0JaMy91aGhQcTVneTlscXc0T2t2RXdzOTkvNWpGcwpYMUZKNk1LQmdxZnV5N3loNXMxWWZNMEFOSFljek1tWXBaZUFjUWY
-yQ0dBYVZmd1RUZlNsek5Mc0YybFcvbHk3CnlhcEZ6bFlTSkxHb1ZFK09IRXU4ZzVTbE5BQ1VFZmtYdys1RWdoaCtLemxJTjdSNlE3cjJpeFdORkJDL2pXZjc
-KTktVZkp5WDhxSUc1bWQxWVVlVDZHQlc5Qm0yLzEvUmlPMjRKVGFZbGZMZEtLOVRZYjhzRzVCK09MYWIyREltRwo5OUNKMjVSa0FjU29iV05GNXpEME82bGd
-PbzNjRWRCL2tzQ3EzaG10bEMvRGxMWi9EOENKKzdWdVpuUzFyUjJuCmFRPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==`
- validKey = `LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFdlFJQkFEQU5CZ2txaGtpRzl3MEJBUUVGQUFTQ0JLY3dnZ1NqQWdFQUFv
-SUJBUUROUUlXak9BMXZXSFV6ClNQTTFGSUtPRTRHZEg2NVZ0V2xwWjlkZ2hINENGWU4wUjdtdkpqNEtCcTg2RHh0OHZKdkxNVjE2R1ZoME5HQ1IKNTBRSDhh
-TWJ4b25EVHFYU29YaU1NNEREU1FUS0JZSzdhWndmdGM3RkczNWdBZmROVWRyOGU3VmJkYVBPU2h1cQpxb3REeUNRcFpZemJ0ODZBQm5vYUo1b2tFM3BVRkl3
-eHc5N0xjZFlzR1p6NU5nbWEvVjF0bzdhTWVFcUh5bDhyCkRSYlhaVXp3L1U4Zzd5Qy9nK0c3KzY0bGlKNEZZcUxFRVRMTFNVZVBLTEZnVUpIWGJGMkhnSURq
-dXIzbnhsRWEKZWNOUVlWVVRWQ0dCRnB3a0k1bjF0M20zMmF2d290cFVGaE1JbWprUkVUeVBLWnB2bDArcDdtb3A4bXdKbUtwYQpDVnVOU2oyM0FnTUJBQUVD
-Z2dFQUJuNEkvQjIweHhYY056QVNpVlpKdnVhOURkUkh0bXhUbGtMem5CajB4Mm9ZCnkxL05iczNkM29GUm41dUV1aEJaT1RjcGhzZ3dkUlNIRFhac1AzZ1VP
-YmV3K2QyTi96aWVVSWo4aExEVmx2SlAKclUvczRVL2w1M1EwTGlOQnlFOVRodkwrekpMUENLSnRkNXVIWmpCNWZGbTY5K1E3Z3U4eGc0eEhJdWIrMHBQNQpQ
-SGFubUhDRHJiZ05OL29xbGFyNEZaMk1YVGdla1c2QW15Yy9rb0U5aEluNEJhYTJLZS9CL0FVR1k0cE1STHFwClRBcnQrR1RWZVdlb0ZZOVFBQ1VwYUhwSmhH
-Yi9QaW91NnRsVTU3ZTQyY0xva2kxZjArU0FSc0JCS3lYQTdCQjEKMWZNSDEwS1FZRkE2OGRUWVdsS3pRYXUvSzR4YXFnNEZLbXR3RjY2R1FRS0JnUUQ5T3BO
-VVM3b1J4TUhWSmFCUgpUTldXK1YxRlh5Y3FvamVrRnBEaWpQYjJYNUNXVjE2b2VXZ2FYcDBuT0hGZHk5RVdzM0d0R3BmWmFzYVJWSHNYClNIdFBoNE5iOEpx
-SGRHRTAvQ0Q2dDArNERuczhCbjljU3F0ZFFCN1IzSm43SU1YaTlYL1U4TERLbytBMTgvSnEKVjhWZ1VuZ01ueTlZak1rUUliSzhUUldrWVFLQmdRRFBmNG54
-TzZqdSt0T0hIT1JRdHkzYllERDArT1YzSTArTAoweXowdVByZXJ5QlZpOW5ZNDNLYWtINTJEN1VaRXd3c0JqakdYRCtXSDh4RXNtQldzR05YSnUwMjVQdnpJ
-Sm96CmxBRWlYdk1wL05tWXArdFk0ckRtTzhSaHlWb2NCcVdIemgzOG0wSUZPZDRCeUZENW5MRURyQTNwRFZvMGFOZ1kKbjBHd1J5c1pGd0tCZ1FEa0NqM202
-Wk1Vc1VXRXR5K2FSMEVKaG1LeU9EQkRPblkwOUlWaEgyUy9GZXhWRnpVTgpMdGZLOTIwNmhwL0F3ZXozTG4ydVQ0WnpxcTVLN2ZNelVuaUpkQldkVkIwMDRs
-OHZvZVhwSWU5T1p1d2ZjQko5CmdGaTF6eXB4L3VGRHY0MjFCelFwQk4rUWZPZEtidmJkUVZGam5xQ3hiU0RyODB5VmxHTXJJNWZid1FLQmdHMDkKb1JyZXBP
-N0VJTzhHTi9HQ3J1TEsvcHRLR2t5aHkzUTZ4blZFbWRiNDdoWDduY0pBNUlvWlBtcmJsQ1ZTVU5zdwpuMTFYSGFia3NMOE9CZ2c5cnQ4b1FFVGhRdi9hRHpU
-T1c5YURsSk5yYWdlamlCVHdxOTlhWWVaMWdqbzFDWnE0CjJqS3VicENmeVpDNHJHRHRySWZaWWkxcStTMlVjUWh0ZDhEZGh3UWJBb0dBQU00RXBEQTR5SEI1
-eWllazFwL28KQ2JxUkN0YS9EeDZFeW8wS2xOQXlQdUZQQXNodXBHNE5CeDdtVDJBU2ZMKzJWQkhvaTZtSFNyaStCRFg1cnlZRgpmTVl2cDdVUllvcTd3N3Fp
-dlJsdnZFZzV5b1lySzEzRjIrR2o2eEo0akVOOW0wS2RNL2czbUpHcTBIQlRJUXJwClNtNzVXWHNmbE94dVRuMDhMYmdHYzRzPQotLS0tLUVORCBSU0EgUFJJ
-VkFURSBLRVktLS0tLQ==`
-)
-
-func TestNew(t *testing.T) {
- result := New(&ServerConfig{
- Attr: AttributeMap{},
- SearchBaseDNs: []string{"BaseDNHere"},
- }, &Config{})
-
- assert.Implements(t, (*IServer)(nil), result)
-}
-
-func TestServer_Dial(t *testing.T) {
- t.Run("fails having no host but with valid root and client certificate files", func(t *testing.T) {
- serverConfig := &ServerConfig{
- Host: "",
- RootCACert: "./testdata/parsable.cert",
- ClientCert: "./testdata/parsable.cert",
- ClientKey: "./testdata/parsable.pem",
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "connect")
- })
-
- t.Run("fails with invalid root certificate file", func(t *testing.T) {
- serverConfig := &ServerConfig{
- RootCACert: "./testdata/invalid.cert",
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "failed to append CA certificate")
- })
-
- t.Run("fails with non existing root certificate file", func(t *testing.T) {
- serverConfig := &ServerConfig{
- RootCACert: "./testdata/nofile.cert",
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "no such file or directory")
- })
-
- t.Run("fails with invalid client certificate file", func(t *testing.T) {
- serverConfig := &ServerConfig{
- ClientCert: "./testdata/invalid.cert",
- ClientKey: "./testdata/invalid.pem",
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "failed to find any PEM data")
- })
-
- t.Run("fails with non existing client certificate file", func(t *testing.T) {
- serverConfig := &ServerConfig{
- ClientCert: "./testdata/nofile.cert",
- ClientKey: "./testdata/parsable.pem",
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "no such file or directory")
- })
-
- t.Run("fails having no host but with valid root and client certificate values", func(t *testing.T) {
- serverConfig := &ServerConfig{
- Host: "",
- RootCACertValue: []string{validCert},
- ClientCertValue: validCert,
- ClientKeyValue: validKey,
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "connect")
- })
-
- t.Run("fails with invalid base64 root certificate value", func(t *testing.T) {
- serverConfig := &ServerConfig{
- RootCACertValue: []string{"invalid-certificate"},
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "illegal base64 data")
- })
-
- t.Run("fails with invalid root certificate value", func(t *testing.T) {
- serverConfig := &ServerConfig{
- RootCACertValue: []string{"aW52YWxpZC1jZXJ0aWZpY2F0ZQ=="},
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "failed to append CA certificate")
- })
-
- t.Run("fails with invalid base64 client certificate value", func(t *testing.T) {
- serverConfig := &ServerConfig{
- ClientCertValue: "invalid-certificate",
- ClientKeyValue: validKey,
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "illegal base64 data")
- })
-
- t.Run("fails with invalid client certificate value", func(t *testing.T) {
- serverConfig := &ServerConfig{
- ClientCertValue: validCert,
- ClientKeyValue: "aW52YWxpZC1rZXk=",
- }
- server := New(serverConfig, &Config{})
-
- err := server.Dial()
- require.Error(t, err)
- require.ErrorContains(t, err, "failed to find any PEM data")
- })
-}
-
-func TestServer_Close(t *testing.T) {
- t.Run("close the connection", func(t *testing.T) {
- connection := &MockConnection{}
-
- server := &Server{
- Config: &ServerConfig{
- Attr: AttributeMap{},
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: connection,
- }
-
- assert.NotPanics(t, server.Close)
- assert.True(t, connection.CloseCalled)
- })
-
- t.Run("panic if no connection", func(t *testing.T) {
- server := &Server{
- Config: &ServerConfig{
- Attr: AttributeMap{},
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: nil,
- }
-
- assert.Panics(t, server.Close)
- })
-}
-
-func TestServer_Users(t *testing.T) {
- t.Run("one user", func(t *testing.T) {
- conn := &MockConnection{}
- entry := ldap.Entry{
- DN: "dn", Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"roelgerrits"}},
- {Name: "surname", Values: []string{"Gerrits"}},
- {Name: "email", Values: []string{"roel@test.com"}},
- {Name: "name", Values: []string{"Roel"}},
- {Name: "memberof", Values: []string{"admins"}},
- }}
- result := ldap.SearchResult{Entries: []*ldap.Entry{&entry}}
- conn.setSearchResult(&result)
-
- // Set up attribute map without surname and email
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Attr: AttributeMap{
- Username: "username",
- Name: "name",
- MemberOf: "memberof",
- },
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: conn,
- log: log.New("test-logger"),
- }
-
- searchResult, err := server.Users([]string{"roelgerrits"})
-
- require.NoError(t, err)
- assert.NotNil(t, searchResult)
-
- // User should be searched in ldap
- assert.True(t, conn.SearchCalled)
- // No empty attributes should be added to the search request
- assert.Len(t, conn.SearchAttributes, 3)
- })
-
- t.Run("error", func(t *testing.T) {
- expected := errors.New("Killa-gorilla")
- conn := &MockConnection{}
- conn.setSearchError(expected)
-
- // Set up attribute map without surname and email
- server := &Server{
- Config: &ServerConfig{
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: conn,
- log: log.New("test-logger"),
- }
-
- _, err := server.Users([]string{"roelgerrits"})
-
- assert.ErrorIs(t, err, expected)
- })
-
- t.Run("no user", func(t *testing.T) {
- conn := &MockConnection{}
- result := ldap.SearchResult{Entries: []*ldap.Entry{}}
- conn.setSearchResult(&result)
-
- // Set up attribute map without surname and email
- server := &Server{
- Config: &ServerConfig{
- SearchBaseDNs: []string{"BaseDNHere"},
- },
- Connection: conn,
- log: log.New("test-logger"),
- }
-
- searchResult, err := server.Users([]string{"roelgerrits"})
-
- require.NoError(t, err)
- assert.Empty(t, searchResult)
- })
-
- t.Run("multiple DNs", func(t *testing.T) {
- conn := &MockConnection{}
- serviceDN := "dc=svc,dc=example,dc=org"
- serviceEntry := ldap.Entry{
- DN: "dn", Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"imgrenderer"}},
- {Name: "name", Values: []string{"Image renderer"}},
- }}
- services := ldap.SearchResult{Entries: []*ldap.Entry{&serviceEntry}}
-
- userDN := "dc=users,dc=example,dc=org"
- userEntry := ldap.Entry{
- DN: "dn", Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"grot"}},
- {Name: "name", Values: []string{"Grot"}},
- }}
- users := ldap.SearchResult{Entries: []*ldap.Entry{&userEntry}}
-
- conn.setSearchFunc(func(request *ldap.SearchRequest) (*ldap.SearchResult, error) {
- switch request.BaseDN {
- case userDN:
- return &users, nil
- case serviceDN:
- return &services, nil
- default:
- return nil, fmt.Errorf("test case not defined for baseDN: '%s'", request.BaseDN)
- }
- })
-
- server := &Server{
- cfg: &Config{},
- Config: &ServerConfig{
- Attr: AttributeMap{
- Username: "username",
- Name: "name",
- },
- SearchBaseDNs: []string{serviceDN, userDN},
- },
- Connection: conn,
- log: log.New("test-logger"),
- }
-
- searchResult, err := server.Users([]string{"imgrenderer", "grot"})
- require.NoError(t, err)
-
- assert.Len(t, searchResult, 2)
- })
-
- t.Run("same user in multiple DNs", func(t *testing.T) {
- conn := &MockConnection{}
- firstDN := "dc=users1,dc=example,dc=org"
- firstEntry := ldap.Entry{
- DN: "dn", Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"grot"}},
- {Name: "name", Values: []string{"Grot the First"}},
- }}
- firsts := ldap.SearchResult{Entries: []*ldap.Entry{&firstEntry}}
-
- secondDN := "dc=users2,dc=example,dc=org"
- secondEntry := ldap.Entry{
- DN: "dn", Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"grot"}},
- {Name: "name", Values: []string{"Grot the Second"}},
- }}
- seconds := ldap.SearchResult{Entries: []*ldap.Entry{&secondEntry}}
-
- conn.setSearchFunc(func(request *ldap.SearchRequest) (*ldap.SearchResult, error) {
- switch request.BaseDN {
- case secondDN:
- return &seconds, nil
- case firstDN:
- return &firsts, nil
- default:
- return nil, fmt.Errorf("test case not defined for baseDN: '%s'", request.BaseDN)
- }
- })
-
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Attr: AttributeMap{
- Username: "username",
- Name: "name",
- },
- SearchBaseDNs: []string{firstDN, secondDN},
- },
- Connection: conn,
- log: log.New("test-logger"),
- }
-
- res, err := server.Users([]string{"grot"})
- require.NoError(t, err)
- require.Len(t, res, 1)
- assert.Equal(t, "Grot the First", res[0].Name)
- })
-
- t.Run("org role mapping", func(t *testing.T) {
- conn := &MockConnection{}
-
- usersOU := "ou=users,dc=example,dc=org"
- grootDN := "dn=groot," + usersOU
- grootSearch := ldap.SearchResult{Entries: []*ldap.Entry{{DN: grootDN,
- Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"groot"}},
- {Name: "name", Values: []string{"I am Groot"}},
- }}}}
- babyGrootDN := "dn=babygroot," + usersOU
- babyGrootSearch := ldap.SearchResult{Entries: []*ldap.Entry{{DN: grootDN,
- Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"babygroot"}},
- {Name: "name", Values: []string{"I am baby Groot"}},
- }}}}
- peterDN := "dn=peter," + usersOU
- peterSearch := ldap.SearchResult{Entries: []*ldap.Entry{{DN: peterDN,
- Attributes: []*ldap.EntryAttribute{
- {Name: "username", Values: []string{"peter"}},
- {Name: "name", Values: []string{"Peter"}},
- }}}}
- groupsOU := "ou=groups,dc=example,dc=org"
- creaturesDN := "dn=creatures," + groupsOU
- grootGroups := ldap.SearchResult{Entries: []*ldap.Entry{{DN: creaturesDN,
- Attributes: []*ldap.EntryAttribute{
- {Name: "member", Values: []string{grootDN}},
- }}},
- }
- babyCreaturesDN := "dn=babycreatures," + groupsOU
- babyGrootGroups := ldap.SearchResult{Entries: []*ldap.Entry{{DN: babyCreaturesDN,
- Attributes: []*ldap.EntryAttribute{
- {Name: "member", Values: []string{babyGrootDN}},
- }}},
- }
- humansDN := "dn=humans," + groupsOU
- peterGroups := ldap.SearchResult{Entries: []*ldap.Entry{{DN: humansDN,
- Attributes: []*ldap.EntryAttribute{
- {Name: "member", Values: []string{peterDN}},
- }}},
- }
-
- conn.setSearchFunc(func(request *ldap.SearchRequest) (*ldap.SearchResult, error) {
- switch request.BaseDN {
- case usersOU:
- switch request.Filter {
- case "(|(username=groot))":
- return &grootSearch, nil
- case "(|(username=babygroot))":
- return &babyGrootSearch, nil
- case "(|(username=peter))":
- return &peterSearch, nil
- default:
- return nil, fmt.Errorf("test case not defined for user filter: '%s'", request.Filter)
- }
- case groupsOU:
- switch request.Filter {
- case "(member=groot)":
- return &grootGroups, nil
- case "(member=babygroot)":
- return &babyGrootGroups, nil
- case "(member=peter)":
- return &peterGroups, nil
- default:
- return nil, fmt.Errorf("test case not defined for group filter: '%s'", request.Filter)
- }
- default:
- return nil, fmt.Errorf("test case not defined for baseDN: '%s'", request.BaseDN)
- }
- })
-
- isGrafanaAdmin := true
- cfg := &Config{
- Enabled: true,
- }
-
- server := &Server{
- cfg: cfg,
- Config: &ServerConfig{
- Attr: AttributeMap{
- Username: "username",
- Name: "name",
- },
- SearchBaseDNs: []string{usersOU},
- SearchFilter: "(username=%s)",
- GroupSearchFilter: "(member=%s)",
- GroupSearchBaseDNs: []string{groupsOU},
- Groups: []*GroupToOrgRole{
- {
- GroupDN: creaturesDN,
- OrgId: 2,
- IsGrafanaAdmin: &isGrafanaAdmin,
- OrgRole: "Admin",
- },
- {
- GroupDN: babyCreaturesDN,
- OrgId: 2,
- OrgRole: "Editor",
- },
- },
- },
- Connection: conn,
- log: log.New("test-logger"),
- }
-
- t.Run("disable user with no mapping", func(t *testing.T) {
- res, err := server.Users([]string{"peter"})
- require.NoError(t, err)
- require.Len(t, res, 1)
- require.Equal(t, "Peter", res[0].Name)
- require.ElementsMatch(t, res[0].Groups, []string{humansDN})
- require.Empty(t, res[0].OrgRoles)
- require.True(t, res[0].IsDisabled)
- })
- t.Run("skip org role sync", func(t *testing.T) {
- server.cfg.SkipOrgRoleSync = true
-
- res, err := server.Users([]string{"groot"})
- require.NoError(t, err)
- require.Len(t, res, 1)
- require.Equal(t, "I am Groot", res[0].Name)
- require.ElementsMatch(t, res[0].Groups, []string{creaturesDN})
- require.Empty(t, res[0].OrgRoles)
- require.False(t, res[0].IsDisabled)
- })
- t.Run("sync org role", func(t *testing.T) {
- server.cfg.SkipOrgRoleSync = false
- res, err := server.Users([]string{"groot"})
- require.NoError(t, err)
- require.Len(t, res, 1)
- require.Equal(t, "I am Groot", res[0].Name)
- require.ElementsMatch(t, res[0].Groups, []string{creaturesDN})
- require.Len(t, res[0].OrgRoles, 1)
- role, mappingExist := res[0].OrgRoles[2]
- require.True(t, mappingExist)
- require.Equal(t, identity.RoleAdmin, role)
- require.False(t, res[0].IsDisabled)
- require.NotNil(t, res[0].IsGrafanaAdmin)
- assert.True(t, *res[0].IsGrafanaAdmin)
- })
- t.Run("set Grafana Admin to false by default", func(t *testing.T) {
- res, err := server.Users([]string{"babygroot"})
- require.NoError(t, err)
- require.Len(t, res, 1)
- require.Equal(t, "I am baby Groot", res[0].Name)
- require.ElementsMatch(t, res[0].Groups, []string{babyCreaturesDN})
- require.Len(t, res[0].OrgRoles, 1)
- role, mappingExist := res[0].OrgRoles[2]
- require.True(t, mappingExist)
- require.Equal(t, identity.RoleEditor, role)
- require.False(t, res[0].IsDisabled)
- require.NotNil(t, res[0].IsGrafanaAdmin)
- assert.False(t, *res[0].IsGrafanaAdmin)
- })
- })
-}
-
-func TestServer_UserBind(t *testing.T) {
- t.Run("use provided DN and password", func(t *testing.T) {
- connection := &MockConnection{}
- var actualUsername, actualPassword string
- connection.BindProvider = func(username, password string) error {
- actualUsername = username
- actualPassword = password
- return nil
- }
- server := &Server{
- Connection: connection,
- Config: &ServerConfig{
- BindDN: "cn=admin,dc=grafana,dc=org",
- },
- }
-
- dn := "cn=user,ou=users,dc=grafana,dc=org"
- err := server.UserBind(dn, "pwd")
-
- require.NoError(t, err)
- assert.Equal(t, dn, actualUsername)
- assert.Equal(t, "pwd", actualPassword)
- })
-
- t.Run("error", func(t *testing.T) {
- connection := &MockConnection{}
- expected := &ldap.Error{
- ResultCode: uint16(25),
- }
- connection.BindProvider = func(username, password string) error {
- return expected
- }
- server := &Server{
- Connection: connection,
- Config: &ServerConfig{
- BindDN: "cn=%s,ou=users,dc=grafana,dc=org",
- },
- log: log.New("test-logger"),
- }
- err := server.UserBind("user", "pwd")
- assert.ErrorIs(t, err, expected)
- })
-}
-
-func TestServer_AdminBind(t *testing.T) {
- t.Run("use admin DN and password", func(t *testing.T) {
- connection := &MockConnection{}
- var actualUsername, actualPassword string
- connection.BindProvider = func(username, password string) error {
- actualUsername = username
- actualPassword = password
- return nil
- }
-
- dn := "cn=admin,dc=grafana,dc=org"
-
- server := &Server{
- Connection: connection,
- Config: &ServerConfig{
- BindPassword: "pwd",
- BindDN: dn,
- },
- }
-
- err := server.AdminBind()
- require.NoError(t, err)
-
- assert.Equal(t, dn, actualUsername)
- assert.Equal(t, "pwd", actualPassword)
- })
-
- t.Run("error", func(t *testing.T) {
- connection := &MockConnection{}
- expected := &ldap.Error{
- ResultCode: uint16(25),
- }
- connection.BindProvider = func(username, password string) error {
- return expected
- }
-
- dn := "cn=admin,dc=grafana,dc=org"
-
- server := &Server{
- Connection: connection,
- Config: &ServerConfig{
- BindPassword: "pwd",
- BindDN: dn,
- },
- log: log.New("test-logger"),
- }
-
- err := server.AdminBind()
- assert.ErrorIs(t, err, expected)
- })
-}
diff --git a/pkg/services/ldap/testing.go b/pkg/services/ldap/testing.go
index 292b8be7d8a8f..a31951c7afb49 100644
--- a/pkg/services/ldap/testing.go
+++ b/pkg/services/ldap/testing.go
@@ -55,8 +55,10 @@ func (c *MockConnection) UnauthenticatedBind(username string) error {
}
// Close mocks Close connection function
-func (c *MockConnection) Close() {
+func (c *MockConnection) Close() error {
c.CloseCalled = true
+
+ return nil
}
func (c *MockConnection) setSearchResult(result *ldap.SearchResult) {
diff --git a/pkg/services/pluginsintegration/plugins_integration_test.go b/pkg/services/pluginsintegration/plugins_integration_test.go
index 66d6dda25d5fb..23dc547f3bbc3 100644
--- a/pkg/services/pluginsintegration/plugins_integration_test.go
+++ b/pkg/services/pluginsintegration/plugins_integration_test.go
@@ -26,6 +26,7 @@ import (
"github.com/grafana/grafana/pkg/tsdb/azuremonitor"
cloudmonitoring "github.com/grafana/grafana/pkg/tsdb/cloud-monitoring"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch"
+ "github.com/grafana/grafana/pkg/tsdb/druid"
"github.com/grafana/grafana/pkg/tsdb/elasticsearch"
postgres "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource"
pyroscope "github.com/grafana/grafana/pkg/tsdb/grafana-pyroscope-datasource"
@@ -94,7 +95,8 @@ func TestIntegrationPluginManager(t *testing.T) {
graf := grafanads.ProvideService(sv2, nil)
pyroscope := pyroscope.ProvideService(hcp)
parca := parca.ProvideService(hcp)
- coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf, pyroscope, parca)
+ dr := druid.ProvideService(hcp)
+ coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf, pyroscope, parca, dr)
testCtx := CreateIntegrationTestCtx(t, cfg, coreRegistry)
diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod
index cc553c54044b9..566c362bda8a3 100644
--- a/pkg/storage/unified/apistore/go.mod
+++ b/pkg/storage/unified/apistore/go.mod
@@ -3,13 +3,13 @@ module github.com/grafana/grafana/pkg/storage/unified/apistore
go 1.23.0
require (
- github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db
+ github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240821155123-6891eb1d35da
github.com/grafana/grafana/pkg/apiserver v0.0.0-20240821155123-6891eb1d35da
github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20240821161612-71f0dae39e9d
github.com/stretchr/testify v1.9.0
gocloud.dev v0.39.0
- google.golang.org/grpc v1.65.0
+ google.golang.org/grpc v1.66.0
k8s.io/apimachinery v0.31.0
k8s.io/apiserver v0.31.0
k8s.io/client-go v0.31.0
@@ -19,13 +19,13 @@ require (
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
- github.com/bufbuild/protocompile v0.4.0 // indirect
+ github.com/bufbuild/protocompile v0.14.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/emicklei/go-restful/v3 v3.11.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fullstorydev/grpchan v1.1.1 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
@@ -33,21 +33,23 @@ require (
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/jsonreference v0.20.4 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
+ github.com/google/btree v1.1.3 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
- github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db // indirect
+ github.com/gorilla/websocket v1.5.3 // indirect
+ github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2 // 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.20.0 // indirect
- github.com/jhump/protoreflect v1.15.1 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
+ github.com/jhump/protoreflect v1.16.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect
@@ -58,24 +60,24 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/prometheus/client_golang v1.20.0 // indirect
+ github.com/prometheus/client_golang v1.20.2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
- github.com/prometheus/common v0.55.0 // indirect
+ github.com/prometheus/common v0.57.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/x448/float16 v0.8.4 // indirect
- go.etcd.io/etcd/api/v3 v3.5.14 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
- go.etcd.io/etcd/client/v3 v3.5.14 // indirect
+ go.etcd.io/etcd/api/v3 v3.5.15 // indirect
+ go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect
+ go.etcd.io/etcd/client/v3 v3.5.15 // indirect
go.opencensus.io v0.24.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
- go.opentelemetry.io/otel v1.28.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
- go.opentelemetry.io/otel/metric v1.28.0 // indirect
- go.opentelemetry.io/otel/sdk v1.28.0 // indirect
- go.opentelemetry.io/otel/trace v1.28.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
+ go.opentelemetry.io/otel v1.29.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
+ go.opentelemetry.io/otel/metric v1.29.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.29.0 // indirect
+ go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
@@ -88,17 +90,17 @@ require (
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
- google.golang.org/api v0.191.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect
+ google.golang.org/api v0.195.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.31.0 // indirect
k8s.io/component-base v0.31.0 // indirect
- k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
- k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
+ k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 // indirect
+ k8s.io/utils v0.0.0-20240821151609-f90d01438635 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum
index f779d2b72816a..cc8aa706ab77a 100644
--- a/pkg/storage/unified/apistore/go.sum
+++ b/pkg/storage/unified/apistore/go.sum
@@ -1,8 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
-cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
-cloud.google.com/go/auth v0.8.1 h1:QZW9FjC5lZzN864p13YxvAtGUlQ+KgRL+8Sg45Z6vxo=
-cloud.google.com/go/auth v0.8.1/go.mod h1:qGVp/Y3kDRSDZ5gFD/XPUfYQ9xW1iI7q8RIRoCyBbJc=
+cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ=
+cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc=
+cloud.google.com/go/auth v0.9.1 h1:+pMtLEV2k0AXKvs/tGZojuj6QaioxfUjOpMsG5Gtx+w=
+cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk=
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw=
@@ -58,8 +58,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
-github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
-github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
+github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU=
+github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -78,8 +78,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
-github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
+github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -100,8 +100,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
-github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
@@ -129,8 +129,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
-github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
+github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -146,8 +146,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
-github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -159,12 +159,12 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db h1:z++X4DdoX+aNlZNT1ZY4cykiFay4+f077pa0AG48SGg=
-github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db/go.mod h1:ptt910z9KFfpVSIbSbXvTRR7tS19mxD7EtmVbbJi/WE=
-github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db h1:mDk0bwRV6rDrLSmKXftcPf9kLA9uH6EvxJvzpPW9bso=
-github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2 h1:SU+p1ck8037cz6F8W38PIL9MzRb6YMeNqc7+GHDuqiU=
+github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY=
+github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2 h1:YTF1Y1BYCDkD7ssmbhzRqXlxevsYpXPmOnoO8qbOue8=
+github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240821155123-6891eb1d35da h1:2E3c/I3ayAy4Z1GwIPqXNZcpUccRapE1aBXA1ho4g7o=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240821155123-6891eb1d35da/go.mod h1:p09fvU5ujNL/Ig8HB7g4f+S0zyYbQq3x/f0jA4ujVOM=
github.com/grafana/grafana/pkg/apiserver v0.0.0-20240821155123-6891eb1d35da h1:xQMb8cRZYu7D0IO9q/lB7qFQpLGAoPUnCase1CGHrXY=
@@ -179,14 +179,14 @@ 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.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
-github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
-github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
+github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
+github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
@@ -230,16 +230,16 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
-github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
-github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
+github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
-github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
+github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
@@ -273,14 +273,14 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
-go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0=
-go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU=
-go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ=
-go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
+go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk=
+go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM=
+go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA=
+go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU=
go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8=
go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg=
-go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
-go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
+go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4=
+go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU=
go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M=
go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0=
go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
@@ -289,22 +289,22 @@ go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok
go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
-go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
-go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
-go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
-go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
-go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
-go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
-go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
-go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=
+go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
+go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
+go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
+go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
+go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
+go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -402,27 +402,27 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
-google.golang.org/api v0.191.0 h1:cJcF09Z+4HAB2t5qTQM1ZtfL/PemsLFkcFG67qq2afk=
-google.golang.org/api v0.191.0/go.mod h1:tD5dsFGxFza0hnQveGfVk9QQYKcfp+VzgRqyXFxE0+E=
+google.golang.org/api v0.195.0 h1:Ude4N8FvTKnnQJHU48RFI40jOBgIrL8Zqr3/QeST6yU=
+google.golang.org/api v0.195.0/go.mod h1:DOGRWuv3P8TU8Lnz7uQc4hyNqrBpMtD9ppW3wBJurgc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
-google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c h1:TYOEhrQMrNDTAd2rX9m+WgGr8Ku6YNuj1D7OX6rWSok=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
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=
@@ -430,8 +430,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
-google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
+google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -477,10 +477,10 @@ k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs=
k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
-k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI=
+k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod
index 360723aab76dd..1f690404216b0 100644
--- a/pkg/storage/unified/resource/go.mod
+++ b/pkg/storage/unified/resource/go.mod
@@ -4,22 +4,22 @@ go 1.23.0
require (
github.com/fullstorydev/grpchan v1.1.1
- github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db
- github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db
+ github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2
+ github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808164224-787abccfbc9e
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
- github.com/prometheus/client_golang v1.20.0
+ github.com/prometheus/client_golang v1.20.2
github.com/stretchr/testify v1.9.0
- go.opentelemetry.io/otel/trace v1.28.0
+ go.opentelemetry.io/otel/trace v1.29.0
gocloud.dev v0.39.0
- google.golang.org/grpc v1.65.0
+ google.golang.org/grpc v1.66.0
google.golang.org/protobuf v1.34.2
k8s.io/apimachinery v0.31.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
- github.com/bufbuild/protocompile v0.4.0 // indirect
+ github.com/bufbuild/protocompile v0.14.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
@@ -30,7 +30,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
- github.com/jhump/protoreflect v1.15.1 // indirect
+ github.com/jhump/protoreflect v1.16.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -38,25 +38,28 @@ require (
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
- github.com/prometheus/common v0.55.0 // indirect
+ github.com/prometheus/common v0.57.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.opencensus.io v0.24.0 // indirect
- go.opentelemetry.io/otel v1.28.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
+ go.opentelemetry.io/otel v1.29.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
- google.golang.org/api v0.191.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect
+ google.golang.org/api v0.195.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiserver v0.31.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
- k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
+ k8s.io/utils v0.0.0-20240821151609-f90d01438635 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)
diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum
index 02d4c05722a9c..82ec4d611ab81 100644
--- a/pkg/storage/unified/resource/go.sum
+++ b/pkg/storage/unified/resource/go.sum
@@ -1,8 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
-cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
-cloud.google.com/go/auth v0.8.1 h1:QZW9FjC5lZzN864p13YxvAtGUlQ+KgRL+8Sg45Z6vxo=
-cloud.google.com/go/auth v0.8.1/go.mod h1:qGVp/Y3kDRSDZ5gFD/XPUfYQ9xW1iI7q8RIRoCyBbJc=
+cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ=
+cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc=
+cloud.google.com/go/auth v0.9.1 h1:+pMtLEV2k0AXKvs/tGZojuj6QaioxfUjOpMsG5Gtx+w=
+cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk=
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw=
@@ -55,8 +55,8 @@ github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
-github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
+github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU=
+github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -128,10 +128,10 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
-github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db h1:z++X4DdoX+aNlZNT1ZY4cykiFay4+f077pa0AG48SGg=
-github.com/grafana/authlib v0.0.0-20240814074258-eae7d47f01db/go.mod h1:ptt910z9KFfpVSIbSbXvTRR7tS19mxD7EtmVbbJi/WE=
-github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db h1:mDk0bwRV6rDrLSmKXftcPf9kLA9uH6EvxJvzpPW9bso=
-github.com/grafana/authlib/claims v0.0.0-20240814074258-eae7d47f01db/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
+github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2 h1:SU+p1ck8037cz6F8W38PIL9MzRb6YMeNqc7+GHDuqiU=
+github.com/grafana/authlib v0.0.0-20240828122726-9edfcbea43e2/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY=
+github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2 h1:YTF1Y1BYCDkD7ssmbhzRqXlxevsYpXPmOnoO8qbOue8=
+github.com/grafana/authlib/claims v0.0.0-20240828122726-9edfcbea43e2/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808164224-787abccfbc9e h1:3vNpomyzv714Hgls5vn+fC0vgv8wUOSHepUl7PB5nUs=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808164224-787abccfbc9e/go.mod h1:ORVFiW/KNRY52lNjkGwnFWCxNVfE97bJG2jr2fetq0I=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
@@ -140,8 +140,8 @@ github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSl
github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
-github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
-github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
+github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
+github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -169,13 +169,13 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
-github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
+github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
-github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
-github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
+github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
@@ -200,16 +200,16 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
-go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
-go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
-go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
-go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
-go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
-go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
+go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
+go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
+go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
gocloud.dev v0.39.0 h1:EYABYGhAalPUaMrbSKOr5lejxoxvXj99nE8XFtsDgds=
gocloud.dev v0.39.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -301,27 +301,27 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
-google.golang.org/api v0.191.0 h1:cJcF09Z+4HAB2t5qTQM1ZtfL/PemsLFkcFG67qq2afk=
-google.golang.org/api v0.191.0/go.mod h1:tD5dsFGxFza0hnQveGfVk9QQYKcfp+VzgRqyXFxE0+E=
+google.golang.org/api v0.195.0 h1:Ude4N8FvTKnnQJHU48RFI40jOBgIrL8Zqr3/QeST6yU=
+google.golang.org/api v0.195.0/go.mod h1:DOGRWuv3P8TU8Lnz7uQc4hyNqrBpMtD9ppW3wBJurgc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM=
-google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk=
-google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c h1:TYOEhrQMrNDTAd2rX9m+WgGr8Ku6YNuj1D7OX6rWSok=
+google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
+google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
-google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
+google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -356,8 +356,8 @@ k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY=
k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI=
+k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
diff --git a/pkg/tsdb/cloudwatch/metric_data_query_builder_test.go b/pkg/tsdb/cloudwatch/metric_data_query_builder_test.go
index 907516f0d80d3..6f8922f3e8d91 100644
--- a/pkg/tsdb/cloudwatch/metric_data_query_builder_test.go
+++ b/pkg/tsdb/cloudwatch/metric_data_query_builder_test.go
@@ -264,6 +264,51 @@ func TestMetricDataQueryBuilder(t *testing.T) {
assert.Equal(t, "${LABEL}|&|${PROP('Dim.InstanceId')}|&|${PROP('Dim.LoadBalancer')}", *mdq.Label)
})
+ t.Run("Query has multiple dimensions and an account Id", func(t *testing.T) {
+ query := &models.CloudWatchQuery{
+ Namespace: "AWS/EC2",
+ MetricName: "CPUUtilization",
+ Dimensions: map[string][]string{
+ "LoadBalancer": {"lb1", "lb2", "lb3"},
+ "InstanceId": {"i-123", "*", "i-789"},
+ },
+ Period: 300,
+ Expression: "",
+ MatchExact: matchExact,
+ Statistic: "Average",
+ MetricQueryType: models.MetricQueryTypeSearch,
+ MetricEditorMode: models.MetricEditorModeBuilder,
+ }
+
+ mdq, err := executor.buildMetricDataQuery(contextWithFeaturesEnabled(features.FlagCloudWatchNewLabelParsing), query)
+ require.NoError(t, err)
+ assert.Equal(t, `REMOVE_EMPTY(SEARCH('{"AWS/EC2","InstanceId","LoadBalancer"} MetricName="CPUUtilization" "LoadBalancer"=("lb1" OR "lb2" OR "lb3")', 'Average', 300))`, *mdq.Expression)
+ assert.Equal(t, "${LABEL}|&|${PROP('Dim.InstanceId')}|&|${PROP('Dim.LoadBalancer')}", *mdq.Label)
+ })
+
+ t.Run("Query has multiple dimensions and an account Id", func(t *testing.T) {
+ query := &models.CloudWatchQuery{
+ Namespace: "AWS/EC2",
+ MetricName: "CPUUtilization",
+ Dimensions: map[string][]string{
+ "LoadBalancer": {"lb1", "lb2", "lb3"},
+ "InstanceId": {"i-123", "*", "i-789"},
+ },
+ Period: 300,
+ Expression: "",
+ MatchExact: matchExact,
+ AccountId: aws.String("some account id"),
+ Statistic: "Average",
+ MetricQueryType: models.MetricQueryTypeSearch,
+ MetricEditorMode: models.MetricEditorModeBuilder,
+ }
+
+ mdq, err := executor.buildMetricDataQuery(contextWithFeaturesEnabled(features.FlagCloudWatchNewLabelParsing), query)
+ require.NoError(t, err)
+ assert.Equal(t, `REMOVE_EMPTY(SEARCH('{"AWS/EC2","InstanceId","LoadBalancer"} MetricName="CPUUtilization" "LoadBalancer"=("lb1" OR "lb2" OR "lb3") :aws.AccountId="some account id"', 'Average', 300))`, *mdq.Expression)
+ assert.Equal(t, "${LABEL}|&|${PROP('Dim.InstanceId')}|&|${PROP('Dim.LoadBalancer')}", *mdq.Label)
+ })
+
t.Run("Query has a dimension key with a space", func(t *testing.T) {
query := &models.CloudWatchQuery{
Namespace: "AWS/Kafka",
@@ -465,6 +510,74 @@ func TestMetricDataQueryBuilder(t *testing.T) {
assert.Equal(t, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"="lb1" "InstanceId"', 'Average', 300))`, *mdq.Expression)
assert.Equal(t, "LB: ${PROP('Dim.LoadBalancer')|&|${PROP('Dim.InstanceId')}", *mdq.Label)
})
+
+ t.Run("query has multiple dimensions and an account Id", func(t *testing.T) {
+ query := &models.CloudWatchQuery{
+ Namespace: "AWS/EC2",
+ MetricName: "CPUUtilization",
+ Dimensions: map[string][]string{
+ "LoadBalancer": {"lb1", "lb2", "lb3"},
+ "InstanceId": {"i-123", "*", "i-789"},
+ },
+ Period: 300,
+ Expression: "",
+ MatchExact: matchExact,
+ Statistic: "Average",
+ MetricQueryType: models.MetricQueryTypeSearch,
+ MetricEditorMode: models.MetricEditorModeBuilder,
+ }
+
+ mdq, err := executor.buildMetricDataQuery(contextWithFeaturesEnabled(features.FlagCloudWatchNewLabelParsing), query)
+ require.NoError(t, err)
+ assert.Equal(t, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"=("lb1" OR "lb2" OR "lb3") "InstanceId"', 'Average', 300))`, *mdq.Expression)
+ assert.Equal(t, "${LABEL}|&|${PROP('Dim.InstanceId')}|&|${PROP('Dim.LoadBalancer')}", *mdq.Label)
+ })
+
+ t.Run("query has multiple dimensions and an account Id", func(t *testing.T) {
+ query := &models.CloudWatchQuery{
+ Namespace: "AWS/EC2",
+ MetricName: "CPUUtilization",
+ Dimensions: map[string][]string{
+ "LoadBalancer": {"lb1", "lb2", "lb3"},
+ "InstanceId": {"i-123", "*", "i-789"},
+ },
+ Period: 300,
+ Expression: "",
+ MatchExact: matchExact,
+ AccountId: aws.String("some account id"),
+ Statistic: "Average",
+ MetricQueryType: models.MetricQueryTypeSearch,
+ MetricEditorMode: models.MetricEditorModeBuilder,
+ }
+
+ mdq, err := executor.buildMetricDataQuery(contextWithFeaturesEnabled(features.FlagCloudWatchNewLabelParsing), query)
+ require.NoError(t, err)
+ assert.Equal(t, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"=("lb1" OR "lb2" OR "lb3") "InstanceId" :aws.AccountId="some account id"', 'Average', 300))`, *mdq.Expression)
+ assert.Equal(t, "${LABEL}|&|${PROP('Dim.InstanceId')}|&|${PROP('Dim.LoadBalancer')}", *mdq.Label)
+ })
+
+ t.Run("Query has a custom label", func(t *testing.T) {
+ query := &models.CloudWatchQuery{
+ Namespace: "AWS/EC2",
+ MetricName: "CPUUtilization",
+ Dimensions: map[string][]string{
+ "LoadBalancer": {"lb1"},
+ "InstanceId": {"i-123", "*", "i-789"},
+ },
+ Period: 300,
+ Expression: "",
+ MatchExact: matchExact,
+ Statistic: "Average",
+ Label: "LB: ${PROP('Dim.LoadBalancer')",
+ MetricQueryType: models.MetricQueryTypeSearch,
+ MetricEditorMode: models.MetricEditorModeBuilder,
+ }
+
+ mdq, err := executor.buildMetricDataQuery(contextWithFeaturesEnabled(features.FlagCloudWatchNewLabelParsing), query)
+ require.NoError(t, err)
+ assert.Equal(t, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"="lb1" "InstanceId"', 'Average', 300))`, *mdq.Expression)
+ assert.Equal(t, "LB: ${PROP('Dim.LoadBalancer')|&|${PROP('Dim.InstanceId')}", *mdq.Label)
+ })
})
t.Run("Query has invalid characters in dimension values", func(t *testing.T) {
diff --git a/pkg/tsdb/cloudwatch/models/api.go b/pkg/tsdb/cloudwatch/models/api.go
index c54c156b12397..236e0d189ed68 100644
--- a/pkg/tsdb/cloudwatch/models/api.go
+++ b/pkg/tsdb/cloudwatch/models/api.go
@@ -71,3 +71,8 @@ type EC2APIProvider interface {
DescribeRegionsWithContext(ctx context.Context, in *ec2.DescribeRegionsInput, opts ...request.Option) (*ec2.DescribeRegionsOutput, error)
DescribeInstancesPagesWithContext(ctx context.Context, in *ec2.DescribeInstancesInput, fn func(*ec2.DescribeInstancesOutput, bool) bool, opts ...request.Option) error
}
+
+type OAMClientProvider interface {
+ ListSinks(*oam.ListSinksInput) (*oam.ListSinksOutput, error)
+ ListAttachedLinks(*oam.ListAttachedLinksInput) (*oam.ListAttachedLinksOutput, error)
+}
diff --git a/pkg/tsdb/druid/column_type.go b/pkg/tsdb/druid/column_type.go
new file mode 100644
index 0000000000000..d29f9b9738c5f
--- /dev/null
+++ b/pkg/tsdb/druid/column_type.go
@@ -0,0 +1,58 @@
+package druid
+
+import (
+ "strconv"
+ "strings"
+ "time"
+)
+
+func detectColumnType(c *responseColumn, pos int, rows [][]interface{}) {
+ if len(rows) == 0 {
+ c.Type = ColumnString
+ return
+ }
+ t := map[columnType]int{"nil": 0}
+ maxRowsToScan := (len(rows) / 5) + 1
+ for _, row := range rows[:maxRowsToScan] {
+ switch v := row[pos].(type) {
+ case string:
+ _, err := strconv.Atoi(v)
+ if err == nil {
+ t[ColumnInt]++
+ continue
+ }
+ _, err = strconv.ParseBool(v)
+ if err == nil {
+ t[ColumnBool]++
+ continue
+ }
+ // TODO is there any other timestamp format possible?
+ _, err = time.Parse("2006-01-02T15:04:05.000Z", v)
+ if err == nil {
+ t[ColumnTime]++
+ continue
+ }
+ t[ColumnString]++
+ continue
+ case float64:
+ if c.Name == "__time" || strings.Contains(strings.ToLower(c.Name), "time_") {
+ t[ColumnTime]++
+ continue
+ }
+ t[ColumnFloat]++
+ continue
+ case bool:
+ t[ColumnBool]++
+ continue
+ }
+ }
+ key := ColumnString
+ maxVal := 0
+ for k, v := range t {
+ if v > maxVal {
+ maxVal = v
+ key = k
+ }
+ }
+ c.Type = key
+}
diff --git a/pkg/tsdb/druid/druid.go b/pkg/tsdb/druid/druid.go
new file mode 100644
index 0000000000000..30b2ae4bc336e
--- /dev/null
+++ b/pkg/tsdb/druid/druid.go
@@ -0,0 +1,943 @@
+package druid
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/Knetic/govaluate"
+ "github.com/bitly/go-simplejson"
+ "github.com/grafadruid/go-druid"
+ druidquerybuilder "github.com/grafadruid/go-druid/builder"
+ druidquery "github.com/grafadruid/go-druid/builder/query"
+ "github.com/grafana/grafana-plugin-sdk-go/backend"
+ "github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
+ "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
+ "github.com/grafana/grafana-plugin-sdk-go/data"
+ "github.com/grafana/grafana/pkg/infra/httpclient"
+ "github.com/grafana/grafana/pkg/tsdb/druid/result"
+)
+
+// Internal interval and range variables
+var (
+ varInterval = variableVariants("__interval")
+ varIntervalMs = variableVariants("__interval_ms")
+ varRange = variableVariants("__range")
+ varRangeS = variableVariants("__range_s")
+ varRangeMs = variableVariants("__range_ms")
+ varRateInterval = variableVariants("__rate_interval")
+)
+
+func variableVariants(base string) []string {
+ return []string{
+ fmt.Sprintf(`"${%s}"`, base),
+ fmt.Sprintf(`"$%s"`, base),
+ fmt.Sprintf(`$%s`, base),
+ fmt.Sprintf(`${%s}`, base),
+ }
+}
+
+type druidQuery struct {
+ Builder map[string]interface{} `json:"builder"`
+ Settings map[string]interface{} `json:"settings"`
+}
+
+type druidResponse struct {
+ Reference string
+ Columns []responseColumn
+ Rows [][]interface{}
+}
+
+type columnType string
+
+const (
+ ColumnString columnType = "string"
+ ColumnTime columnType = "time"
+ ColumnBool columnType = "bool"
+ ColumnInt columnType = "int"
+ ColumnFloat columnType = "float"
+)
+
+type responseColumn struct {
+ Name string
+ Type columnType
+}
+
+type druidInstanceSettings struct {
+ client *druid.Client
+ defaultQuerySettings map[string]interface{}
+}
+
+func (s *druidInstanceSettings) Dispose() {
+ s.client.Close()
+}
+
+func newDataSourceInstance(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
+ data, err := simplejson.NewJson(settings.JSONData)
+ if err != nil {
+ return &druidInstanceSettings{}, err
+ }
+ secureData := settings.DecryptedSecureJSONData
+
+ var druidOpts []druid.ClientOption
+ if retryMax := data.Get("connection.retryableRetryMax").MustInt(-1); retryMax != -1 {
+ druidOpts = append(druidOpts, druid.WithRetryMax(retryMax))
+ }
+ if retryWaitMin := data.Get("connection.retryableRetryWaitMin").MustInt(-1); retryWaitMin != -1 {
+ druidOpts = append(druidOpts, druid.WithRetryWaitMin(time.Duration(retryWaitMin)*time.Millisecond))
+ }
+ if retryWaitMax := data.Get("connection.retryableRetryWaitMax").MustInt(-1); retryWaitMax != -1 {
+ druidOpts = append(druidOpts, druid.WithRetryWaitMax(time.Duration(retryWaitMax)*time.Millisecond))
+ }
+ if basicAuth := data.Get("connection.basicAuth").MustBool(); basicAuth {
+ druidOpts = append(druidOpts, druid.WithBasicAuth(data.Get("connection.basicAuthUser").MustString(), secureData["connection.basicAuthPassword"]))
+ }
+ if skipTLS := data.Get("connection.skipTls").MustBool(); skipTLS {
+ druidOpts = append(druidOpts, druid.WithSkipTLSVerify())
+ }
+
+ c, err := druid.NewClient(data.Get("connection.url").MustString(), druidOpts...)
+ if err != nil {
+ return &druidInstanceSettings{}, err
+ }
+
+ return &druidInstanceSettings{
+ client: c,
+ defaultQuerySettings: prepareQuerySettings(settings.JSONData),
+ }, nil
+}
+
+func prepareQuerySettings(data json.RawMessage) map[string]interface{} {
+ var d map[string]interface{}
+ settings := make(map[string]interface{})
+ err := json.Unmarshal(data, &d)
+ if err != nil {
+ return settings
+ }
+ for k, v := range d {
+ if strings.HasPrefix(k, "query.") {
+ settings[strings.TrimPrefix(k, "query.")] = v
+ }
+ }
+ return settings
+}
+
+func mergeSettings(settings ...map[string]interface{}) map[string]interface{} {
+ stg := make(map[string]interface{})
+ for _, s := range settings {
+ for k, v := range s {
+ stg[k] = v
+ }
+ }
+ return stg
+}
+
+func newDatasource() datasource.ServeOpts {
+ ds := &Service{
+ im: datasource.NewInstanceManager(newDataSourceInstance),
+ }
+
+ return datasource.ServeOpts{
+ QueryDataHandler: ds,
+ CheckHealthHandler: ds,
+ CallResourceHandler: ds,
+ }
+}
+
+type Service struct {
+ im instancemgmt.InstanceManager
+}
+
+func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
+ return newDataSourceInstance
+}
+
+func ProvideService(httpClientProvider httpclient.Provider) *Service {
+ return &Service{
+ im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
+ }
+}
+
+func (ds *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
+ var err error
+ var body interface{}
+ var code int
+ body = "Unknown error"
+ code = 500
+ switch req.Path {
+ case "query-variable":
+ switch req.Method {
+ case "POST":
+ body, err = ds.QueryVariableData(ctx, req)
+ if err == nil {
+ code = 200
+ }
+ default:
+ body = "Method not supported"
+ }
+ default:
+ body = "Path not supported"
+ }
+ resp := &backend.CallResourceResponse{
+ Headers: map[string][]string{},
+ Status: code,
+ }
+ resp.Body, err = json.Marshal(body)
+ if err != nil {
+ resp.Body = []byte("Error marshalling response")
+ resp.Status = 500
+ }
+ sender.Send(resp)
+ return nil
+}
+
+type grafanaMetricFindValue struct {
+ Value interface{} `json:"value"`
+ Text string `json:"text"`
+}
+
+func (ds *Service) QueryVariableData(ctx context.Context, req *backend.CallResourceRequest) ([]grafanaMetricFindValue, error) {
+ s, err := ds.settings(req.PluginContext, ctx)
+ if err != nil {
+ return []grafanaMetricFindValue{}, err
+ }
+ return ds.queryVariable(req.Body, s, toHTTPHeaders(req.Headers))
+}
+
+func (ds *Service) queryVariable(qry []byte, s *druidInstanceSettings, headers http.Header) ([]grafanaMetricFindValue, error) {
+ // feature: probably implement a short (1s ? 500ms ? configurable in datasource ? beware memory: constrain size ?) life cache (druidInstanceSettings.cache ?) and early return then
+ response := []grafanaMetricFindValue{}
+ q, stg, err := ds.prepareQuery(qry, s)
+ if err != nil {
+ return response, err
+ }
+ r, err := ds.oldExecuteQuery("variable", q, s, stg, headers)
+ if err != nil {
+ return response, err
+ }
+ response, err = ds.prepareVariableResponse(r, stg)
+ return response, err
+}
+
+func (ds *Service) prepareVariableResponse(resp *druidResponse, settings map[string]interface{}) ([]grafanaMetricFindValue, error) {
+ // refactor: probably some method that returns a container (make([]whattypeever, 0)) and its related appender func based on column type)
+ response := []grafanaMetricFindValue{}
+ for ic, c := range resp.Columns {
+ for _, r := range resp.Rows {
+ switch c.Type {
+ case "string":
+ if r[ic] != nil {
+ response = append(response, grafanaMetricFindValue{Value: r[ic].(string), Text: r[ic].(string)})
+ }
+ case "float":
+ if r[ic] != nil {
+ response = append(response, grafanaMetricFindValue{Value: r[ic].(float64), Text: fmt.Sprintf("%f", r[ic].(float64))})
+ }
+ case "int":
+ if r[ic] != nil {
+ i, err := strconv.Atoi(r[ic].(string))
+ if err != nil {
+ i = 0
+ }
+ response = append(response, grafanaMetricFindValue{Value: i, Text: r[ic].(string)})
+ }
+ case "bool":
+ var b bool
+ var err error
+ b, ok := r[ic].(bool)
+ if !ok {
+ b, err = strconv.ParseBool(r[ic].(string))
+ if err != nil {
+ b = false
+ }
+ }
+ var i int
+ if b {
+ i = 1
+ } else {
+ i = 0
+ }
+ response = append(response, grafanaMetricFindValue{Value: i, Text: strconv.FormatBool(b)})
+ case "time":
+ var t time.Time
+ var err error
+ if r[ic] == nil {
+ r[ic] = 0.0
+ }
+ switch r[ic].(type) {
+ case string:
+ t, err = time.Parse("2006-01-02T15:04:05.000Z", r[ic].(string))
+ if err != nil {
+ t = time.Now()
+ }
+ case float64:
+ sec, dec := math.Modf(r[ic].(float64) / 1000)
+ t = time.Unix(int64(sec), int64(dec*(1e9)))
+ }
+ response = append(response, grafanaMetricFindValue{Value: t.Unix(), Text: t.Format(time.UnixDate)})
+ }
+ }
+ }
+ return response, nil
+}
+
+func (ds *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
+ result := &backend.CheckHealthResult{
+ Status: backend.HealthStatusError,
+ Message: "Can't connect to Druid",
+ }
+
+ i, err := ds.im.Get(ctx, req.PluginContext)
+ if err != nil {
+ result.Message = "Can't get Druid instance"
+ return result, nil
+ }
+
+ status, _, err := i.(*druidInstanceSettings).client.Common().Status()
+ if err != nil {
+ result.Message = "Can't fetch Druid status"
+ return result, nil
+ }
+
+ result.Status = backend.HealthStatusOk
+ result.Message = fmt.Sprintf("Succesfully connected to Druid %s", status.Version)
+ return result, nil
+}
+
+func (ds *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
+ response := backend.NewQueryDataResponse()
+ s, err := ds.settings(req.PluginContext, ctx)
+ if err != nil {
+ return response, err
+ }
+
+ for _, q := range req.Queries {
+ response.Responses[q.RefID] = ds.query(q, s, toHTTPHeaders(req.Headers))
+ }
+
+ return response, nil
+}
+
+func toHTTPHeaders(rawOriginal interface{}) http.Header {
+ headers := http.Header{}
+ switch original := rawOriginal.(type) {
+ case map[string]string:
+ for k, v := range original {
+ // This is temporary fix. List of allowed headers should be configurable.
+ if k != "Cookie" {
+ continue
+ }
+ headers.Set(k, v)
+ }
+ case map[string][]string:
+ for k, vv := range original {
+ // This is temporary fix. List of allowed headers should be configurable.
+ if k != "Cookie" {
+ continue
+ }
+ for _, v := range vv {
+ headers.Set(k, v)
+ }
+ }
+ }
+ return headers
+}
+
+func (ds *Service) settings(ctx backend.PluginContext, getCtx context.Context) (*druidInstanceSettings, error) {
+ s, err := ds.im.Get(getCtx, ctx)
+ if err != nil {
+ return nil, err
+ }
+ return s.(*druidInstanceSettings), nil
+}
+
+func (ds *Service) query(qry backend.DataQuery, s *druidInstanceSettings, headers http.Header) backend.DataResponse {
+ rawQuery := interpolateVariables(string(qry.JSON), qry.Interval, qry.TimeRange.Duration())
+
+ // feature: probably implement a short (1s ? 500ms ? configurable in datasource ? beware memory: constrain size ?) life cache (druidInstanceSettings.cache ?) and early return then
+ response := backend.DataResponse{}
+ q, stg, err := ds.prepareQuery([]byte(rawQuery), s)
+ if err != nil {
+ response.Error = err
+ return response
+ }
+ r, err := ds.executeQuery(qry.RefID, q, s, stg, headers)
+ if err != nil {
+ response.Error = err
+ return response
+ }
+ response, err = ds.prepareResponse(r, stg)
+ if err != nil {
+ // note: error could be set from prepareResponse but this gives a chance to react to error here
+ response.Error = err
+ }
+ return response
+}
+
+func interpolateVariables(expr string, interval time.Duration, timeRange time.Duration) string {
+ rangeMs := timeRange.Milliseconds()
+ rangeSRounded := int64(math.Round(float64(rangeMs) / 1000.0))
+
+ expr = multiReplace(expr, varIntervalMs, strconv.FormatInt(int64(interval/time.Millisecond), 10))
+ expr = multiReplace(expr, varInterval, formatDuration(interval))
+ expr = multiReplace(expr, varRangeMs, strconv.FormatInt(rangeMs, 10))
+ expr = multiReplace(expr, varRangeS, strconv.FormatInt(rangeSRounded, 10))
+ expr = multiReplace(expr, varRange, strconv.FormatInt(rangeSRounded, 10)+"s")
+ expr = multiReplace(expr, varRateInterval, interval.String())
+
+ return expr
+}
+
+func multiReplace(s string, olds []string, new string) string {
+ res := s
+ for _, old := range olds {
+ res = strings.ReplaceAll(res, old, new)
+ }
+ return res
+}
+
+func formatDuration(inter time.Duration) string {
+ day := time.Hour * 24
+ year := day * 365
+ if inter >= year {
+ return fmt.Sprintf("%dy", inter/year)
+ }
+
+ if inter >= day {
+ return fmt.Sprintf("%dd", inter/day)
+ }
+
+ if inter >= time.Hour {
+ return fmt.Sprintf("%dh", inter/time.Hour)
+ }
+
+ if inter >= time.Minute {
+ return fmt.Sprintf("%dm", inter/time.Minute)
+ }
+
+ if inter >= time.Second {
+ return fmt.Sprintf("%ds", inter/time.Second)
+ }
+
+ if inter >= time.Millisecond {
+ return fmt.Sprintf("%dms", inter/time.Millisecond)
+ }
+
+ return "1ms"
+}
+
+func (ds *Service) prepareQuery(qry []byte, s *druidInstanceSettings) (druidquerybuilder.Query, map[string]interface{}, error) {
+ var q druidQuery
+ err := json.Unmarshal(qry, &q)
+ if err != nil {
+ return nil, nil, err
+ }
+ var defaultQueryContext map[string]interface{}
+ if defaultContextParameters, ok := s.defaultQuerySettings["contextParameters"]; ok {
+ defaultQueryContext = ds.prepareQueryContext(defaultContextParameters.([]interface{}))
+ }
+ q.Builder["context"] = defaultQueryContext
+ if queryContextParameters, ok := q.Settings["contextParameters"]; ok {
+ q.Builder["context"] = mergeSettings(
+ defaultQueryContext,
+ ds.prepareQueryContext(queryContextParameters.([]interface{})))
+ }
+ if g, ok := q.Builder["granularity"].(map[string]any); ok {
+ q.Builder["granularity"] = resolveGranularity(g)
+ }
+ jsonQuery, err := json.Marshal(q.Builder)
+ if err != nil {
+ return nil, nil, err
+ }
+ query, err := s.client.Query().Load(jsonQuery)
+ // feature: could ensure __time column is selected, time interval is set based on qry given timerange and consider max data points ?
+ return query, mergeSettings(s.defaultQuerySettings, q.Settings), err
+}
+
+func resolveGranularity(m map[string]any) map[string]any {
+ // granularity is optional, so return early if not set and is of wrong type
+ if m == nil || m["type"] != "duration" {
+ return m
+ }
+ expr, ok := m["duration"].(string)
+ if !ok {
+ return m
+ }
+
+ eval, err := govaluate.NewEvaluableExpression(expr)
+ if err != nil {
+ return m
+ }
+ result, err := eval.Evaluate(nil)
+ if err != nil {
+ return m
+ }
+ m["duration"] = result
+ return m
+}
+
+func (ds *Service) prepareQueryContext(parameters []interface{}) map[string]interface{} {
+ ctx := make(map[string]interface{})
+ for _, parameter := range parameters {
+ p := parameter.(map[string]interface{})
+ ctx[p["name"].(string)] = p["value"]
+ }
+ return ctx
+}
+
+func (ds *Service) executeQuery(
+ queryRef string,
+ q druidquerybuilder.Query,
+ s *druidInstanceSettings,
+ settings map[string]interface{},
+ headers http.Header,
+) (*data.Frame, error) {
+ var resultFramer result.Framer
+ qtyp := q.Type()
+ switch qtyp {
+ case "sql":
+ q.(*druidquery.SQL).SetResultFormat("array").SetHeader(true)
+ return nil, errors.New("not implemented")
+ case "timeseries":
+ var r result.TimeseriesResult
+ _, err := s.client.Query().Execute(q, &r, headers)
+ if err != nil {
+ return nil, fmt.Errorf("Query error: %w", err)
+ }
+ resultFramer = &r
+ case "topN":
+ var r result.TopNResult
+ _, err := s.client.Query().Execute(q, &r, headers)
+ if err != nil {
+ return nil, fmt.Errorf("Query error: %w", err)
+ }
+ resultFramer = &r
+ case "groupBy":
+ var r result.GroupByResult
+ _, err := s.client.Query().Execute(q, &r, headers)
+ if err != nil {
+ return nil, fmt.Errorf("Query error: %w", err)
+ }
+ resultFramer = &r
+ case "scan":
+ q.(*druidquery.Scan).SetResultFormat("compactedList")
+ return nil, errors.New("not implemented")
+ case "search":
+ return nil, errors.New("not implemented")
+ case "timeBoundary":
+ return nil, errors.New("not implemented")
+ case "dataSourceMetadata":
+ return nil, errors.New("not implemented")
+ case "segmentMetadata":
+ return nil, errors.New("not implemented")
+ default:
+ return nil, errors.New("unknown query type")
+ }
+ f := resultFramer.Frame()
+ f.Name = queryRef
+ return f, nil
+}
+
+func (ds *Service) oldExecuteQuery(queryRef string, q druidquerybuilder.Query, s *druidInstanceSettings, settings map[string]interface{}, headers http.Header) (*druidResponse, error) {
+ // refactor: probably need to extract per-query preprocessor and postprocessor into a per-query file. load those "plugins" (ak. QueryProcessor ?) into a register and then do something like plugins[q.Type()].preprocess(q) and plugins[q.Type()].postprocess(r)
+ r := &druidResponse{Reference: queryRef}
+ qtyp := q.Type()
+ switch qtyp {
+ case "sql":
+ q.(*druidquery.SQL).SetResultFormat("array").SetHeader(true)
+ case "scan":
+ q.(*druidquery.Scan).SetResultFormat("compactedList")
+ }
+ var res json.RawMessage
+ _, err := s.client.Query().Execute(q, &res, headers)
+ if err != nil {
+ return r, err
+ }
+ switch qtyp {
+ case "sql":
+ var sqlr []interface{}
+ err := json.Unmarshal(res, &sqlr)
+ if err == nil && len(sqlr) > 1 {
+ for _, row := range sqlr[1:] {
+ r.Rows = append(r.Rows, row.([]interface{}))
+ }
+ for i, c := range sqlr[0].([]interface{}) {
+ col := responseColumn{
+ Name: c.(string),
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+ }
+ case "timeseries":
+ var tsResult result.TimeseriesResult
+ err := json.Unmarshal(res, &tsResult)
+ if err != nil {
+ return r, err
+ }
+ if len(tsResult) == 0 {
+ return r, nil
+ }
+ columns := tsResult.Columns()
+ for _, result := range tsResult {
+ var row []interface{}
+ t := result.Timestamp
+ if t.IsZero() {
+ // If timestamp not set, use value from previous row.
+ // This can happen when grand total is calculated.
+ t = r.Rows[len(r.Rows)-1][0].(time.Time)
+ }
+ row = append(row, t)
+ colResults := result.Result
+ for _, c := range columns[1:] {
+ row = append(row, colResults[c])
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ for i, c := range columns {
+ col := responseColumn{
+ Name: c,
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+ case "topN":
+ var tn []map[string]interface{}
+ err := json.Unmarshal(res, &tn)
+ if err == nil && len(tn) > 0 {
+ columns := []string{"timestamp"}
+ results := tn[0]["result"].([]interface{})
+ if len(results) > 0 {
+ for c := range results[0].(map[string]interface{}) {
+ columns = append(columns, c)
+ }
+ }
+ for _, result := range tn {
+ for _, record := range result["result"].([]interface{}) {
+ var row []interface{}
+ row = append(row, result["timestamp"])
+ o := record.(map[string]interface{})
+ for _, c := range columns[1:] {
+ row = append(row, o[c])
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ }
+ for i, c := range columns {
+ col := responseColumn{
+ Name: c,
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+ }
+ case "groupBy":
+ var gb []map[string]interface{}
+ err := json.Unmarshal(res, &gb)
+ if err == nil && len(gb) > 0 {
+ columns := []string{"timestamp"}
+ for c := range gb[0]["event"].(map[string]interface{}) {
+ columns = append(columns, c)
+ }
+ for _, result := range gb {
+ var row []interface{}
+ row = append(row, result["timestamp"])
+ colResults := result["event"].(map[string]interface{})
+ for _, c := range columns[1:] {
+ row = append(row, colResults[c])
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ for i, c := range columns {
+ col := responseColumn{
+ Name: c,
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+ }
+ case "scan":
+ var scanr []map[string]interface{}
+ err := json.Unmarshal(res, &scanr)
+ if err == nil && len(scanr) > 0 {
+ for _, e := range scanr[0]["events"].([]interface{}) {
+ r.Rows = append(r.Rows, e.([]interface{}))
+ }
+ for i, c := range scanr[0]["columns"].([]interface{}) {
+ col := responseColumn{
+ Name: c.(string),
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+ }
+ case "search":
+ var s []map[string]interface{}
+ err := json.Unmarshal(res, &s)
+ if err == nil && len(s) > 0 {
+ columns := []string{"timestamp"}
+ for c := range s[0]["result"].([]interface{})[0].(map[string]interface{}) {
+ columns = append(columns, c)
+ }
+ for _, result := range s {
+ for _, record := range result["result"].([]interface{}) {
+ var row []interface{}
+ row = append(row, result["timestamp"])
+ o := record.(map[string]interface{})
+ for _, c := range columns[1:] {
+ row = append(row, o[c])
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ }
+ for i, c := range columns {
+ col := responseColumn{
+ Name: c,
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+ }
+ case "timeBoundary":
+ var tb []map[string]interface{}
+ err := json.Unmarshal(res, &tb)
+ if err == nil && len(tb) > 0 {
+ columns := []string{"timestamp"}
+ for c := range tb[0]["result"].(map[string]interface{}) {
+ columns = append(columns, c)
+ }
+ for _, result := range tb {
+ var row []interface{}
+ row = append(row, result["timestamp"])
+ colResults := result["result"].(map[string]interface{})
+ for _, c := range columns[1:] {
+ row = append(row, colResults[c])
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ for i, c := range columns {
+ col := responseColumn{
+ Name: c,
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+ }
+ case "dataSourceMetadata":
+ var dsm []map[string]interface{}
+ err := json.Unmarshal(res, &dsm)
+ if err == nil && len(dsm) > 0 {
+ columns := []string{"timestamp"}
+ for c := range dsm[0]["result"].(map[string]interface{}) {
+ columns = append(columns, c)
+ }
+ for _, result := range dsm {
+ var row []interface{}
+ row = append(row, result["timestamp"])
+ colResults := result["result"].(map[string]interface{})
+ for _, c := range columns[1:] {
+ row = append(row, colResults[c])
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ for i, c := range columns {
+ col := responseColumn{
+ Name: c,
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+ }
+ case "segmentMetadata":
+ var sm []map[string]interface{}
+ err := json.Unmarshal(res, &sm)
+ if err == nil && len(sm) > 0 {
+ var columns []string
+ switch settings["view"].(string) {
+ case "base":
+ for k, v := range sm[0] {
+ if k != "aggregators" && k != "columns" && k != "timestampSpec" {
+ if k == "intervals" {
+ for i := range v.([]interface{}) {
+ pos := strconv.Itoa(i)
+ columns = append(columns, "interval_start_"+pos)
+ columns = append(columns, "interval_stop_"+pos)
+ }
+ } else {
+ columns = append(columns, k)
+ }
+ }
+ }
+ for _, result := range sm {
+ var row []interface{}
+ for _, c := range columns {
+ var col interface{}
+ if strings.HasPrefix(c, "interval_") {
+ parts := strings.Split(c, "_")
+ pos := 0
+ if parts[1] == "stop" {
+ pos = 1
+ }
+ idx, err := strconv.Atoi(parts[2])
+ if err != nil {
+ return r, errors.New("interval parsing goes wrong")
+ }
+ ii := result["intervals"].([]interface{})[idx]
+ col = strings.Split(ii.(string), "/")[pos]
+ } else {
+ col = result[c]
+ }
+ row = append(row, col)
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ case "aggregators":
+ for _, v := range sm[0]["aggregators"].(map[string]interface{}) {
+ columns = append(columns, "aggregator")
+ for k := range v.(map[string]interface{}) {
+ columns = append(columns, k)
+ }
+ break
+ }
+ for _, result := range sm {
+ for k, v := range result["aggregators"].(map[string]interface{}) {
+ var row []interface{}
+ for _, c := range columns {
+ var col interface{}
+ if c == "aggregator" {
+ col = k
+ } else {
+ col = v.(map[string]interface{})[c]
+ }
+ row = append(row, col)
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ }
+ case "columns":
+ for _, v := range sm[0]["columns"].(map[string]interface{}) {
+ columns = append(columns, "column")
+ for k := range v.(map[string]interface{}) {
+ columns = append(columns, k)
+ }
+ break
+ }
+ for _, result := range sm {
+ for k, v := range result["columns"].(map[string]interface{}) {
+ var row []interface{}
+ for _, c := range columns {
+ var col interface{}
+ if c == "column" {
+ col = k
+ } else {
+ col = v.(map[string]interface{})[c]
+ }
+ row = append(row, col)
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ }
+ case "timestampspec":
+ for k := range sm[0]["timestampSpec"].(map[string]interface{}) {
+ columns = append(columns, k)
+ }
+ for _, result := range sm {
+ var row []interface{}
+ for _, c := range columns {
+ col := result["timestampSpec"].(map[string]interface{})[c]
+ row = append(row, col)
+ }
+ r.Rows = append(r.Rows, row)
+ }
+ }
+ for i, c := range columns {
+ col := responseColumn{
+ Name: c,
+ }
+ detectColumnType(&col, i, r.Rows)
+ r.Columns = append(r.Columns, col)
+ }
+
+ }
+ default:
+ return r, errors.New("unknown query type")
+ }
+ return r, err
+}
+
+func (ds *Service) prepareResponse(frame *data.Frame, settings map[string]interface{}) (backend.DataResponse, error) {
+ // refactor: probably some method that returns a container (make([]whattypeever, 0)) and its related appender func based on column type)
+ response := backend.DataResponse{}
+ // TODO support those settings
+ // hideEmptyColumns, _ := settings["hideEmptyColumns"].(bool)
+ // responseLimit, _ := settings["responseLimit"].(float64)
+ format, found := settings["format"]
+ if !found {
+ format = "long"
+ } else {
+ format = format.(string)
+ }
+ // convert to other formats if specified
+ if format == "wide" && len(frame.Fields) > 0 {
+ f, err := data.LongToWide(frame, nil)
+ if err == nil {
+ frame = f
+ }
+ } else if format == "log" && len(frame.Fields) > 0 {
+ f, err := longToLog(frame, settings)
+ if err == nil {
+ frame = f
+ }
+ }
+ response.Frames = append(response.Frames, frame)
+ return response, nil
+}
+
+func longToLog(longFrame *data.Frame, settings map[string]interface{}) (*data.Frame, error) {
+ logFrame := data.NewFrame("response")
+ logFrame.SetMeta(&data.FrameMeta{PreferredVisualization: data.VisTypeLogs})
+ // fetch settings
+ logColumnTime, found := settings["logColumnTime"]
+ if !found {
+ logColumnTime = "__time"
+ } else {
+ logColumnTime = logColumnTime.(string)
+ }
+ logColumnLevel, found := settings["logColumnLevel"]
+ if !found {
+ logColumnLevel = "level"
+ } else {
+ logColumnLevel = logColumnLevel.(string)
+ }
+ logColumnMessage, found := settings["logColumnMessage"]
+ if !found {
+ logColumnMessage = "message"
+ } else {
+ logColumnMessage = logColumnMessage.(string)
+ }
+ // make sure the special time and message fields come first in the frame because that's how
+ // the log ui decides what time and message to display
+ for _, f := range longFrame.Fields {
+ if f.Name == logColumnTime || f.Name == logColumnMessage {
+ logFrame.Fields = append(logFrame.Fields, f)
+ }
+ }
+ // now copy over the rest of the fields
+ for _, f := range longFrame.Fields {
+ if f.Name == logColumnTime {
+ // skip because time already copied above. does not skip message because we want it
+ // included twice since otherwise it won't be available as a detected field
+ continue
+ } else if f.Name == logColumnLevel {
+ f.Name = "level"
+ }
+ logFrame.Fields = append(logFrame.Fields, f)
+ }
+ return logFrame, nil
+}
diff --git a/pkg/tsdb/druid/druid_test.go b/pkg/tsdb/druid/druid_test.go
new file mode 100644
index 0000000000000..2b1b41a9956b0
--- /dev/null
+++ b/pkg/tsdb/druid/druid_test.go
@@ -0,0 +1,21 @@
+package druid
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestResolveGranularity(t *testing.T) {
+ granularity := map[string]any{
+ "type": "duration",
+ "duration": "10 * 10",
+ "origin": "2012-01-01T00:30:00Z",
+ }
+ gran := resolveGranularity(granularity)
+ assert.Equal(t, gran, map[string]any{
+ "type": "duration",
+ "duration": 100,
+ "origin": "2012-01-01T00:30:00Z",
+ })
+}
diff --git a/pkg/tsdb/druid/result/common.go b/pkg/tsdb/druid/result/common.go
new file mode 100644
index 0000000000000..5d15a866c8d6b
--- /dev/null
+++ b/pkg/tsdb/druid/result/common.go
@@ -0,0 +1,82 @@
+package result
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/grafana/grafana-plugin-sdk-go/backend/log"
+ "github.com/grafana/grafana-plugin-sdk-go/data"
+)
+
+type Framer interface {
+ Frame() *data.Frame
+}
+
+const timestampColumn = "timestamp"
+
+func toTypedResults(raw []interface{}) interface{} {
+ // TODO this is not perfect. Maybe we should get this from the query?
+ switch raw[0].(type) {
+ // TODO this can be done with generics, but we should wait until go is updated in this repo
+ case string:
+ results := make([]string, len(raw))
+ for i, v := range raw {
+ vv, _ := v.(string)
+ results[i] = vv
+ }
+ return results
+ case int:
+ results := make([]int, len(raw))
+ for i, v := range raw {
+ vv, _ := v.(int)
+ results[i] = vv
+ }
+ return results
+ case int32:
+ results := make([]int32, len(raw))
+ for i, v := range raw {
+ vv, _ := v.(int32)
+ results[i] = vv
+ }
+ return results
+ case int64:
+ results := make([]int64, len(raw))
+ for i, v := range raw {
+ vv, _ := v.(int64)
+ results[i] = vv
+ }
+ return results
+ case float32:
+ results := make([]float32, len(raw))
+ for i, v := range raw {
+ vv, _ := v.(float32)
+ results[i] = vv
+ }
+ return results
+ case float64:
+ results := make([]float64, len(raw))
+ for i, v := range raw {
+ vv, _ := v.(float64)
+ results[i] = vv
+ }
+ return results
+ case bool:
+ results := make([]bool, len(raw))
+ for i, v := range raw {
+ vv, _ := v.(bool)
+ results[i] = vv
+ }
+ return results
+ case time.Time:
+ results := make([]time.Time, len(raw))
+ for i, v := range raw {
+ vv, _ := v.(time.Time)
+ results[i] = vv
+ }
+ return results
+ default:
+ // TODO better error handling
+ log.DefaultLogger.Debug(fmt.Sprintf("Unsupported type %T", raw[0]))
+ return nil
+ }
+}
diff --git a/pkg/tsdb/druid/result/groupby.go b/pkg/tsdb/druid/result/groupby.go
new file mode 100644
index 0000000000000..e3cb2a49b9472
--- /dev/null
+++ b/pkg/tsdb/druid/result/groupby.go
@@ -0,0 +1,74 @@
+package result
+
+import (
+ "sort"
+ "time"
+
+ "github.com/grafana/grafana-plugin-sdk-go/data"
+)
+
+type GroupByResult []GroupByRecord
+
+// Frame returns data formatted as Grafana Frame.
+func (t *GroupByResult) Frame() *data.Frame {
+ columns := t.Columns()
+ fields := make([]*data.Field, len(columns))
+ for i, column := range columns {
+ labels := data.Labels{}
+ fields[i] = data.NewField(column, labels, t.Values(column))
+ }
+ return data.NewFrame("", fields...)
+}
+
+// Columns returns list of columns. It calls `Columns()` on first record. If
+// no records are available it returns nil.
+func (t *GroupByResult) Columns() []string {
+ for _, r := range *t {
+ return r.Columns()
+ }
+ return nil
+}
+
+// Values returns all values for given column.
+func (t *GroupByResult) Values(column string) interface{} {
+ if len(*t) == 0 {
+ return nil
+ }
+ results := make([]interface{}, len(*t))
+ for i, r := range *t {
+ results[i] = r.Value(column)
+ }
+ return toTypedResults(results)
+}
+
+type GroupByRecord struct {
+ Timestamp time.Time `json:"timestamp"`
+ Event map[string]interface{} `json:"event"`
+}
+
+// Columns returns list of columns for given record.
+// The first column will always be "timestamp" followed by other columns sorted
+// alphabetically.
+func (t *GroupByRecord) Columns() []string {
+ columns := make([]string, len(t.Event)+1)
+ columns[0] = timestampColumn
+ i := 1
+ for c := range t.Event {
+ columns[i] = c
+ i++
+ }
+ sort.Strings(columns[1:])
+ return columns
+}
+
+// Value returns value for given column.
+func (t *GroupByRecord) Value(column string) interface{} {
+ if column == timestampColumn {
+ return t.Timestamp
+ }
+ v, ok := t.Event[column]
+ if !ok {
+ return nil
+ }
+ return v
+}
diff --git a/pkg/tsdb/druid/result/groupby_test.go b/pkg/tsdb/druid/result/groupby_test.go
new file mode 100644
index 0000000000000..80cc4cb335b67
--- /dev/null
+++ b/pkg/tsdb/druid/result/groupby_test.go
@@ -0,0 +1,60 @@
+package result
+
+import (
+ "encoding/json"
+ "testing"
+ "time"
+
+ "github.com/grafana/grafana-plugin-sdk-go/data"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGroupByResultUnmarshal(t *testing.T) {
+ input := []byte(`[
+ {
+ "timestamp": "2022-10-14T08:08:10.000Z",
+ "event": {
+ "dog_count": 47,
+ "dog_rate": 2.083,
+ "dog_name": "foo"
+ }
+ },
+ {
+ "timestamp": "2022-10-14T08:08:11.000Z",
+ "event": {
+ "dog_count": 75,
+ "dog_rate": 3.846,
+ "dog_name": "bar"
+ }
+ }
+ ]`)
+
+ var res GroupByResult
+ err := json.Unmarshal(input, &res)
+ assert.Nil(t, err, "Failed to unmarshal response")
+ assert.Equal(t, len(res), 2, "Wrong number of unmarshalled results")
+ frame := res.Frame()
+ assert.Equal(t, len(frame.Fields), 4, "Wrong number of framed fields")
+
+ assert.Equal(t, frame.Fields[0].Name, "timestamp")
+ assert.Equal(t, frame.Fields[0].Type(), data.FieldTypeTime)
+ assert.Equal(t, frame.Fields[0].Len(), 2)
+ assert.Equal(t, frame.Fields[0].At(0), time.Time(time.Date(2022, time.October, 14, 8, 8, 10, 0, time.UTC)))
+ assert.Equal(t, frame.Fields[0].At(1), time.Time(time.Date(2022, time.October, 14, 8, 8, 11, 0, time.UTC)))
+
+ assert.Equal(t, frame.Fields[1].Name, "dog_count")
+ assert.Equal(t, frame.Fields[1].Type(), data.FieldTypeFloat64)
+ assert.Equal(t, frame.Fields[1].At(0), float64(47))
+ assert.Equal(t, frame.Fields[1].At(1), float64(75))
+
+ assert.Equal(t, frame.Fields[2].Name, "dog_name")
+ assert.Equal(t, frame.Fields[2].Type(), data.FieldTypeString)
+ assert.Equal(t, frame.Fields[2].At(0), "foo")
+ assert.Equal(t, frame.Fields[2].At(1), "bar")
+
+ assert.Equal(t, frame.Fields[3].Name, "dog_rate")
+ assert.Equal(t, frame.Fields[3].Type(), data.FieldTypeFloat64)
+ assert.Equal(t, frame.Fields[3].At(0), float64(2.083))
+ assert.Equal(t, frame.Fields[3].At(1), float64(3.846))
+
+}
diff --git a/pkg/tsdb/druid/result/timeseries.go b/pkg/tsdb/druid/result/timeseries.go
new file mode 100644
index 0000000000000..ec9e20e64fa52
--- /dev/null
+++ b/pkg/tsdb/druid/result/timeseries.go
@@ -0,0 +1,74 @@
+package result
+
+import (
+ "sort"
+ "time"
+
+ "github.com/grafana/grafana-plugin-sdk-go/data"
+)
+
+type TimeseriesResult []TimeseriesRecord
+
+// Frame returns data formatted as Grafana Frame.
+func (t *TimeseriesResult) Frame() *data.Frame {
+ columns := t.Columns()
+ fields := make([]*data.Field, len(columns))
+ for i, column := range columns {
+ labels := data.Labels{}
+ fields[i] = data.NewField(column, labels, t.Values(column))
+ }
+ return data.NewFrame("", fields...)
+}
+
+// Columns returns list of columns. It calls `Columns()` on first record. If
+// no records are available it returns nil.
+func (t *TimeseriesResult) Columns() []string {
+ for _, r := range *t {
+ return r.Columns()
+ }
+ return nil
+}
+
+// Values returns all values for given column.
+func (t *TimeseriesResult) Values(column string) interface{} {
+ if len(*t) == 0 {
+ return nil
+ }
+ results := make([]interface{}, len(*t))
+ for i, r := range *t {
+ results[i] = r.Value(column)
+ }
+ return toTypedResults(results)
+}
+
+type TimeseriesRecord struct {
+ Timestamp time.Time `json:"timestamp"`
+ Result map[string]interface{} `json:"result"`
+}
+
+// Columns returns list of columns for given record.
+// The first column will always be "timestamp" followed by other columns sorted
+// alphabetically.
+func (t *TimeseriesRecord) Columns() []string {
+ columns := make([]string, len(t.Result)+1)
+ columns[0] = timestampColumn
+ i := 1
+ for c := range t.Result {
+ columns[i] = c
+ i++
+ }
+ sort.Strings(columns[1:])
+ return columns
+}
+
+// Value returns value for given column.
+func (t *TimeseriesRecord) Value(column string) interface{} {
+ if column == timestampColumn {
+ return t.Timestamp
+ }
+ v, ok := t.Result[column]
+ if !ok {
+ return nil
+ }
+ return v
+}
diff --git a/pkg/tsdb/druid/result/timeseries_test.go b/pkg/tsdb/druid/result/timeseries_test.go
new file mode 100644
index 0000000000000..1154b0f0d522b
--- /dev/null
+++ b/pkg/tsdb/druid/result/timeseries_test.go
@@ -0,0 +1,60 @@
+package result
+
+import (
+ "encoding/json"
+ "testing"
+ "time"
+
+ "github.com/grafana/grafana-plugin-sdk-go/data"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestTimeseriesResultUnmarshal(t *testing.T) {
+ input := []byte(`[
+ {
+ "timestamp": "2022-10-14T08:08:10.000Z",
+ "result": {
+ "dog_count": 47,
+ "dog_rate": 2.083,
+ "dog_name": "foo"
+ }
+ },
+ {
+ "timestamp": "2022-10-14T08:08:11.000Z",
+ "result": {
+ "dog_count": 75,
+ "dog_rate": 3.846,
+ "dog_name": "bar"
+ }
+ }
+ ]`)
+
+ var res TimeseriesResult
+ err := json.Unmarshal(input, &res)
+ assert.Nil(t, err, "Failed to unmarshal response")
+ assert.Equal(t, len(res), 2, "Wrong number of unmarshalled results")
+ frame := res.Frame()
+ assert.Equal(t, len(frame.Fields), 4, "Wrong number of framed fields")
+
+ assert.Equal(t, frame.Fields[0].Name, "timestamp")
+ assert.Equal(t, frame.Fields[0].Type(), data.FieldTypeTime)
+ assert.Equal(t, frame.Fields[0].Len(), 2)
+ assert.Equal(t, frame.Fields[0].At(0), time.Time(time.Date(2022, time.October, 14, 8, 8, 10, 0, time.UTC)))
+ assert.Equal(t, frame.Fields[0].At(1), time.Time(time.Date(2022, time.October, 14, 8, 8, 11, 0, time.UTC)))
+
+ assert.Equal(t, frame.Fields[1].Name, "dog_count")
+ assert.Equal(t, frame.Fields[1].Type(), data.FieldTypeFloat64)
+ assert.Equal(t, frame.Fields[1].At(0), float64(47))
+ assert.Equal(t, frame.Fields[1].At(1), float64(75))
+
+ assert.Equal(t, frame.Fields[2].Name, "dog_name")
+ assert.Equal(t, frame.Fields[2].Type(), data.FieldTypeString)
+ assert.Equal(t, frame.Fields[2].At(0), "foo")
+ assert.Equal(t, frame.Fields[2].At(1), "bar")
+
+ assert.Equal(t, frame.Fields[3].Name, "dog_rate")
+ assert.Equal(t, frame.Fields[3].Type(), data.FieldTypeFloat64)
+ assert.Equal(t, frame.Fields[3].At(0), float64(2.083))
+ assert.Equal(t, frame.Fields[3].At(1), float64(3.846))
+
+}
diff --git a/pkg/tsdb/druid/result/topn.go b/pkg/tsdb/druid/result/topn.go
new file mode 100644
index 0000000000000..ba64fa7dc508b
--- /dev/null
+++ b/pkg/tsdb/druid/result/topn.go
@@ -0,0 +1,78 @@
+package result
+
+import (
+ "sort"
+ "time"
+
+ "github.com/grafana/grafana-plugin-sdk-go/data"
+)
+
+type TopNResult []TopNRecord
+
+// Frame returns data formatted as Grafana Frame.
+func (t *TopNResult) Frame() *data.Frame {
+ columns := t.Columns()
+ fields := make([]*data.Field, len(columns))
+ for i, column := range columns {
+ labels := data.Labels{}
+ fields[i] = data.NewField(column, labels, t.Values(column))
+ }
+ return data.NewFrame("", fields...)
+}
+
+// Columns returns list of columns. It calls `Columns()` on first record. If
+// no records are available it returns nil.
+func (t *TopNResult) Columns() []string {
+ for _, r := range *t {
+ return r.Columns()
+ }
+ return nil
+}
+
+// Values returns all values for given column.
+func (t *TopNResult) Values(column string) interface{} {
+ results := []interface{}{}
+ for _, r := range *t {
+ results = append(results, r.Values(column)...)
+ }
+ return toTypedResults(results)
+}
+
+type TopNRecord struct {
+ Timestamp time.Time `json:"timestamp"`
+ Result []map[string]interface{} `json:"result"`
+}
+
+// Columns returns list of columns for given record.
+// It assumes that every map from Result has the same columns, so it gets
+// the list from first item.
+// The first column will always be "timestamp" followed by other columns sorted
+// alphabetically.
+func (t *TopNRecord) Columns() []string {
+ for _, result := range t.Result {
+ columns := make([]string, len(result)+1)
+ columns[0] = timestampColumn
+ i := 1
+ for c := range result {
+ columns[i] = c
+ i++
+ }
+ sort.Strings(columns[1:])
+ return columns
+ }
+ return nil
+}
+
+// Value returns values for given column.
+func (t *TopNRecord) Values(column string) []interface{} {
+ values := []interface{}{}
+ for _, result := range t.Result {
+ if column == timestampColumn {
+ values = append(values, t.Timestamp)
+ continue
+ }
+ v, _ := result[column]
+ values = append(values, v)
+ }
+ return values
+}
diff --git a/pkg/tsdb/druid/result/topn_test.go b/pkg/tsdb/druid/result/topn_test.go
new file mode 100644
index 0000000000000..7fb2503aae7cc
--- /dev/null
+++ b/pkg/tsdb/druid/result/topn_test.go
@@ -0,0 +1,59 @@
+package result
+
+import (
+ "encoding/json"
+ "testing"
+ "time"
+
+ "github.com/grafana/grafana-plugin-sdk-go/data"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestTopNResultUnmarshal(t *testing.T) {
+ input := []byte(`[
+ {
+ "timestamp": "2022-10-14T08:08:10.000Z",
+ "result": [
+ {
+ "dog_count": 47,
+ "dog_rate": 2.083,
+ "dog_name": "foo"
+ },
+ {
+ "dog_count": 75,
+ "dog_rate": 3.846,
+ "dog_name": "bar"
+ }
+ ]
+ }
+ ]`)
+
+ var res TopNResult
+ err := json.Unmarshal(input, &res)
+ assert.Nil(t, err, "Failed to unmarshal response")
+ assert.Equal(t, len(res), 1, "Wrong number of unmarshalled results")
+ frame := res.Frame()
+ assert.Equal(t, len(frame.Fields), 4, "Wrong number of framed fields")
+
+ assert.Equal(t, frame.Fields[0].Name, "timestamp")
+ assert.Equal(t, frame.Fields[0].Type(), data.FieldTypeTime)
+ assert.Equal(t, frame.Fields[0].Len(), 2)
+ assert.Equal(t, frame.Fields[0].At(0), time.Time(time.Date(2022, time.October, 14, 8, 8, 10, 0, time.UTC)))
+ assert.Equal(t, frame.Fields[0].At(1), time.Time(time.Date(2022, time.October, 14, 8, 8, 10, 0, time.UTC)))
+
+ assert.Equal(t, frame.Fields[1].Name, "dog_count")
+ assert.Equal(t, frame.Fields[1].Type(), data.FieldTypeFloat64)
+ assert.Equal(t, frame.Fields[1].At(0), float64(47))
+ assert.Equal(t, frame.Fields[1].At(1), float64(75))
+
+ assert.Equal(t, frame.Fields[2].Name, "dog_name")
+ assert.Equal(t, frame.Fields[2].Type(), data.FieldTypeString)
+ assert.Equal(t, frame.Fields[2].At(0), "foo")
+ assert.Equal(t, frame.Fields[2].At(1), "bar")
+
+ assert.Equal(t, frame.Fields[3].Name, "dog_rate")
+ assert.Equal(t, frame.Fields[3].Type(), data.FieldTypeFloat64)
+ assert.Equal(t, frame.Fields[3].At(0), float64(2.083))
+ assert.Equal(t, frame.Fields[3].At(1), float64(3.846))
+
+}
diff --git a/pkg/util/xorm/go.mod b/pkg/util/xorm/go.mod
index 45b2e78666ad2..0980eb6993491 100644
--- a/pkg/util/xorm/go.mod
+++ b/pkg/util/xorm/go.mod
@@ -5,7 +5,7 @@ go 1.21.10
require (
github.com/mattn/go-sqlite3 v1.14.22
github.com/stretchr/testify v1.9.0
- xorm.io/builder v0.3.6
+ xorm.io/builder v0.3.13
xorm.io/core v0.7.3
)
diff --git a/pkg/util/xorm/go.sum b/pkg/util/xorm/go.sum
index 060ce3a658dc1..6afb0e24030dc 100644
--- a/pkg/util/xorm/go.sum
+++ b/pkg/util/xorm/go.sum
@@ -1,5 +1,7 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -7,8 +9,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
-github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
-github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -41,7 +41,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
-xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
+xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
+xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/core v0.7.3 h1:W8ws1PlrnkS1CZU1YWaYLMQcQilwAmQXU0BJDJon+H0=
xorm.io/core v0.7.3/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
diff --git a/public/app/core/components/Page/usePageTitle.ts b/public/app/core/components/Page/usePageTitle.ts
index c2e53b23251dc..53a7e147ac2e1 100644
--- a/public/app/core/components/Page/usePageTitle.ts
+++ b/public/app/core/components/Page/usePageTitle.ts
@@ -1,6 +1,7 @@
import { useEffect } from 'react';
import { NavModel, NavModelItem } from '@grafana/data';
+import { FnGlobalState } from 'app/core/reducers/fn-slice';
import { HOME_NAV_ID } from 'app/core/reducers/navModel';
import { useSelector } from 'app/types';
@@ -8,7 +9,9 @@ import { Branding } from '../Branding/Branding';
import { buildBreadcrumbs } from '../Breadcrumbs/utils';
export function usePageTitle(navModel?: NavModel, pageNav?: NavModelItem) {
- const homeNav = useSelector((state) => state.navIndex)?.[HOME_NAV_ID];
+ const homeNav = useSelector((state) => state.navIndex)[HOME_NAV_ID];
+ const { FNDashboard, pageTitle } = useSelector((state) => state.fnGlobalState);
+
useEffect(() => {
const sectionNav = (navModel?.node !== navModel?.main ? navModel?.node : navModel?.main) ?? { text: 'Grafana' };
const parts: string[] = buildBreadcrumbs(sectionNav, pageNav, homeNav)
@@ -18,6 +21,6 @@ export function usePageTitle(navModel?: NavModel, pageNav?: NavModelItem) {
// Override `Home` with the custom brand title
parts[parts.length - 1] = Branding.AppTitle;
- document.title = parts.join(' - ');
- }, [homeNav, navModel, pageNav]);
+ document.title = !FNDashboard ? parts.join(' - ') : pageTitle ? pageTitle : 'CodeRabbit';
+ }, [FNDashboard, homeNav, navModel, pageNav, pageTitle]);
}
diff --git a/public/app/core/components/TimePicker/TimePickerWithHistory.tsx b/public/app/core/components/TimePicker/TimePickerWithHistory.tsx
index 64c08d31b6703..12e351ff80443 100644
--- a/public/app/core/components/TimePicker/TimePickerWithHistory.tsx
+++ b/public/app/core/components/TimePicker/TimePickerWithHistory.tsx
@@ -1,9 +1,12 @@
-import { uniqBy } from 'lodash';
+import { isEqual, uniqBy } from 'lodash';
+import { CSSProperties, FC, useEffect, useRef } from 'react';
+// eslint-disable-next-line no-restricted-imports
+import { useDispatch, useSelector } from 'react-redux';
-import { AppEvents, TimeRange, isDateTime, rangeUtil } from '@grafana/data';
-import { TimeRangePickerProps, TimeRangePicker } from '@grafana/ui';
-import { t } from '@grafana/ui/src/utils/i18n';
-import appEvents from 'app/core/app_events';
+import { TimeRange, isDateTime, rangeUtil } from '@grafana/data';
+import { TimeRangePickerProps, TimeRangePicker, useTheme2 } from '@grafana/ui';
+import { FnGlobalState, updatePartialFnStates } from 'app/core/reducers/fn-slice';
+import { StoreState } from 'app/types';
import { LocalStorageValueProvider } from '../LocalStorageValueProvider';
@@ -20,31 +23,66 @@ interface TimePickerHistoryItem {
// We should only be storing TimePickerHistoryItem, but in the past we also stored TimeRange
type LSTimePickerHistoryItem = TimePickerHistoryItem | TimeRange;
-export const TimePickerWithHistory = (props: Props) => {
- return (
- storageKey={LOCAL_STORAGE_KEY} defaultValue={[]}>
- {(rawValues, onSaveToStore) => {
- const values = migrateHistory(rawValues);
- const history = deserializeHistory(values);
-
- return (
- {
- onAppendToHistory(value, values, onSaveToStore);
- props.onChange(value);
- }}
- onError={(error?: string) =>
- appEvents.emit(AppEvents.alertError, [
- t('time-picker.copy-paste.default-error-title', 'Invalid time range'),
- t('time-picker.copy-paste.default-error-message', `{{error}} is not a valid time range`, { error }),
- ])
- }
- />
+const FnText: React.FC = () => {
+ const { FNDashboard } = useSelector(({ fnGlobalState }) => fnGlobalState);
+ const theme = useTheme2();
+
+ const FN_TEXT_STYLE: CSSProperties = { fontWeight: 700, fontSize: 14, marginLeft: 8 };
+
+ return <>{FNDashboard ? UTC : ''}>;
+};
+
+export const TimePickerWithHistory: FC = (props) => (
+ storageKey={LOCAL_STORAGE_KEY} defaultValue={[]}>
+ {(rawValues, onSaveToStore) => {
+ return ;
+ }}
+
+);
+
+export interface PickerProps {
+ rawValues: LSTimePickerHistoryItem[];
+ onSaveToStore: (value: LSTimePickerHistoryItem[]) => void;
+ pickerProps: Props;
+}
+
+export const Picker: FC = ({ rawValues, onSaveToStore, pickerProps }) => {
+ const { fnGlobalTimeRange } = useSelector(({ fnGlobalState }) => fnGlobalState);
+ const dispatch = useDispatch();
+
+ const values = migrateHistory(rawValues);
+ const history = deserializeHistory(values);
+
+ const didMountRef = useRef(false);
+ useEffect(() => {
+ /* The condition below skips the first run of useeffect that happens when this component gets mounted */
+ if (didMountRef.current) {
+ /* If the current timerange value has changed, update fnGlobalTimeRange */
+ if (!isEqual(fnGlobalTimeRange?.raw, pickerProps.value.raw)) {
+ dispatch(
+ updatePartialFnStates({
+ fnGlobalTimeRange: pickerProps.value,
+ })
);
+ }
+ } else if (fnGlobalTimeRange && !isEqual(fnGlobalTimeRange.raw, pickerProps.value.raw)) {
+ /* If fnGlobalTimeRange exists in the initial render, set the time as that */
+ pickerProps.onChange(fnGlobalTimeRange);
+ }
+
+ didMountRef.current = true;
+ }, [dispatch, fnGlobalTimeRange, pickerProps]);
+
+ return (
+ {
+ onAppendToHistory(value, values, onSaveToStore);
+ pickerProps.onChange(value);
}}
-
+ fnText={ }
+ />
);
};
diff --git a/public/app/core/internationalization/index.tsx b/public/app/core/internationalization/index.tsx
index 2d31fc1d70873..006894cdfcae7 100644
--- a/public/app/core/internationalization/index.tsx
+++ b/public/app/core/internationalization/index.tsx
@@ -78,7 +78,7 @@ export const t = (id: string, defaultMessage: string, values?: Record>;
+
+export type SetFnStateAction = PayloadAction>;
+
+export type FnPropMappedFromState = Extract<
+ keyof FnGlobalState,
+ 'FNDashboard' | 'hiddenVariables' | 'mode' | 'uid' | 'queryParams' | 'slug' | 'version' | 'controlsContainer'
+>;
+export type FnStateProp = keyof FnGlobalState;
+
+export type FnPropsMappedFromState = Pick;
+
+export const fnStateProps: FnStateProp[] = [
+ 'FNDashboard',
+ 'controlsContainer',
+ 'hiddenVariables',
+ 'mode',
+ 'pageTitle',
+ 'queryParams',
+ 'slug',
+ 'uid',
+ 'version',
+];
+
+export const fnPropsMappedFromState: readonly FnPropMappedFromState[] = [
+ 'FNDashboard',
+ 'hiddenVariables',
+ 'mode',
+ 'uid',
+ 'queryParams',
+ 'slug',
+ 'version',
+] as const;
+
+const INITIAL_MODE = GrafanaThemeType.Light;
+
+export const FN_STATE_KEY = 'fnGlobalState';
+
+export const INITIAL_FN_STATE: FnGlobalState = {
+ // NOTE: initial value is false
+ FNDashboard: false,
+ uid: '',
+ slug: '',
+ version: 1,
+ mode: INITIAL_MODE,
+ controlsContainer: null,
+ pageTitle: '',
+ queryParams: {},
+ hiddenVariables: [],
+ fnGlobalTimeRange: null,
+} as const;
+
+const reducers: SliceCaseReducers = {
+ updateFnState: (state, action: SetFnStateAction) => {
+ return { ...state, ...action.payload };
+ },
+ updatePartialFnStates: (state, action: UpdateFNGlobalStateAction) => {
+ return {
+ ...state,
+ ...action.payload,
+ };
+ },
+};
+
+const fnSlice = createSlice, string, SliceSelectors>({
+ name: FN_STATE_KEY,
+ initialState: INITIAL_FN_STATE,
+ reducers,
+});
+
+export const { updatePartialFnStates, updateFnState } = fnSlice.actions;
+export const fnSliceReducer = fnSlice.reducer;
diff --git a/public/app/core/reducers/index.ts b/public/app/core/reducers/index.ts
index 6482f26c932ca..2d14820d77d62 100644
--- a/public/app/core/reducers/index.ts
+++ b/public/app/core/reducers/index.ts
@@ -1,4 +1,5 @@
import { appNotificationsReducer as appNotifications } from './appNotification';
+import { fnSliceReducer as fnGlobalState } from './fn-slice';
import { navTreeReducer as navBarTree } from './navBarTree';
import { navIndexReducer as navIndex } from './navModel';
@@ -6,4 +7,5 @@ export default {
navBarTree,
navIndex,
appNotifications,
+ fnGlobalState,
};
diff --git a/public/app/core/services/backend_srv.ts b/public/app/core/services/backend_srv.ts
index 64ac099efbaf3..372170b6a72e2 100644
--- a/public/app/core/services/backend_srv.ts
+++ b/public/app/core/services/backend_srv.ts
@@ -65,6 +65,7 @@ export class BackendSrv implements BackendService {
private readonly responseQueue: ResponseQueue;
private _tokenRotationInProgress?: Observable | null = null;
private deviceID?: string | null = null;
+ private grafanaPrefix: boolean;
private dependencies: BackendSrvDependencies = {
fromFetch: fromFetch,
@@ -83,6 +84,7 @@ export class BackendSrv implements BackendService {
};
}
+ this.grafanaPrefix = false;
this.noBackendCache = false;
this.internalFetch = this.internalFetch.bind(this);
this.fetchQueue = new FetchQueue();
@@ -108,6 +110,12 @@ export class BackendSrv implements BackendService {
}
fetch(options: BackendSrvRequest): Observable> {
+ // prefix "/grafana" to options.url
+ if (this.grafanaPrefix) {
+ if (options.url.indexOf('/grafana') !== 0) {
+ options.url = '/grafana' + options.url;
+ }
+ }
// We need to match an entry added to the queue stream with the entry that is eventually added to the response stream
const id = uuidv4();
const fetchQueue = this.fetchQueue;
@@ -181,6 +189,18 @@ export class BackendSrv implements BackendService {
return lastValueFrom(this.fetch(options));
}
+ private getCodeRabbitOrg(): { id: string } | null {
+ const selectedOrgStorage = sessionStorage.getItem('selected_org');
+
+ try {
+ return selectedOrgStorage ? (JSON.parse(selectedOrgStorage) as { id: string }) : null;
+ } catch (e) {
+ console.error('Failed to parse selected_org', selectedOrgStorage, 'error:', e);
+ sessionStorage.removeItem('selected_org');
+ return null;
+ }
+ }
+
private parseRequestOptions(options: BackendSrvRequest): BackendSrvRequest {
const orgId = this.dependencies.contextSrv.user?.orgId;
@@ -193,10 +213,22 @@ export class BackendSrv implements BackendService {
options.headers['X-Grafana-Org-Id'] = orgId;
}
+ const codeRabbitOrg = this.getCodeRabbitOrg();
+ if (codeRabbitOrg) {
+ options.headers = options.headers ?? {};
+ options.headers['x-coderabbit-organization'] = codeRabbitOrg.id;
+ }
+
if (options.url.startsWith('/')) {
options.url = options.url.substring(1);
}
+ const codeRabbitToken = sessionStorage.getItem('accessToken');
+ if (codeRabbitToken) {
+ options.headers = options.headers ?? {};
+ options.headers['x-coderabbit-token'] = `Bearer ${codeRabbitToken}`;
+ }
+
if (options.headers?.Authorization) {
options.headers['X-DS-Authorization'] = options.headers.Authorization;
delete options.headers.Authorization;
@@ -516,13 +548,20 @@ export class BackendSrv implements BackendService {
return getDashboardAPI().getDashboardDTO(uid);
}
- validateDashboard(dashboard: DashboardModel): Promise {
- // support for this function will be implemented in the k8s flavored api-server
- // hidden by experimental feature flag:
- // config.featureToggles.showDashboardValidationWarnings
- return Promise.resolve({
- isValid: false,
- message: 'dashboard validation is not supported',
+ getDashboardByUidVersion(uid: string, version: number): Promise {
+ return this.get(`/api/dashboards/uid/${uid}/versions/${version}`);
+ }
+
+ validateDashboard(dashboard: DashboardModel) {
+ // We want to send the dashboard as a JSON string (in the JSON body payload) so we can get accurate error line numbers back
+ const dashboardJson = JSON.stringify(dashboard, replaceJsonNulls, 2);
+
+ return this.request({
+ method: 'POST',
+ url: `/api/dashboards/validate`,
+ data: { dashboard: dashboardJson },
+ showSuccessAlert: false,
+ showErrorAlert: false,
});
}
@@ -540,6 +579,10 @@ export class BackendSrv implements BackendService {
showErrorAlert: false,
});
}
+
+ setGrafanaPrefix(prefix: boolean) {
+ this.grafanaPrefix = prefix;
+ }
}
// Used for testing and things that really need BackendSrv
@@ -550,3 +593,10 @@ interface ValidateDashboardResponse {
isValid: boolean;
message?: string;
}
+
+function replaceJsonNulls(key: string, value: T): T | undefined {
+ if (typeof value === 'number' && !isFinite(value)) {
+ return undefined;
+ }
+ return value;
+}
diff --git a/public/app/core/utils/ConfigProvider.tsx b/public/app/core/utils/ConfigProvider.tsx
index 53cdc1c3fc4d7..702311aed674a 100644
--- a/public/app/core/utils/ConfigProvider.tsx
+++ b/public/app/core/utils/ConfigProvider.tsx
@@ -34,8 +34,8 @@ export const ThemeProvider = ({ children, value }: { children: React.ReactNode;
);
};
-export const provideTheme = (component: React.ComponentType
, theme: GrafanaTheme2) => {
- return function ThemeProviderWrapper(props: P) {
+export const provideTheme = (component: React.ComponentType, theme: GrafanaTheme2) => {
+ return function ThemeProviderWrapper(props: any) {
return {React.createElement(component, { ...props })} ;
};
};
diff --git a/public/app/features/alerting/unified/state/actions.ts b/public/app/features/alerting/unified/state/actions.ts
index 276c43a0bcca5..3927496017958 100644
--- a/public/app/features/alerting/unified/state/actions.ts
+++ b/public/app/features/alerting/unified/state/actions.ts
@@ -2,7 +2,6 @@ import { createAsyncThunk } from '@reduxjs/toolkit';
import { isEmpty } from 'lodash';
import { locationService } from '@grafana/runtime';
-import { logMeasurement } from '@grafana/runtime/src/utils/logging';
import {
AlertManagerCortexConfig,
AlertmanagerGroup,
@@ -21,7 +20,12 @@ import {
import { PromApplication, RulerRuleDTO, RulerRulesConfigDTO } from 'app/types/unified-alerting-dto';
import { backendSrv } from '../../../../core/services/backend_srv';
-import { withPerformanceLogging, withPromRulesMetadataLogging, withRulerRulesMetadataLogging } from '../Analytics';
+import {
+ logMeasurement,
+ withPerformanceLogging,
+ withPromRulesMetadataLogging,
+ withRulerRulesMetadataLogging,
+} from '../Analytics';
import {
deleteAlertManagerConfig,
fetchAlertGroups,
diff --git a/public/app/features/api-keys/ApiKeysPage.test.tsx b/public/app/features/api-keys/ApiKeysPage.test.tsx
index 728508a14e8c7..a2ab2351547ba 100644
--- a/public/app/features/api-keys/ApiKeysPage.test.tsx
+++ b/public/app/features/api-keys/ApiKeysPage.test.tsx
@@ -6,6 +6,7 @@ import { ApiKey, OrgRole } from 'app/types';
import { mockToolkitActionCreator } from '../../../test/core/redux/mocks';
import { silenceConsoleOutput } from '../../../test/core/utils/silenceConsoleOutput';
+import { configureStore } from '../../store/configureStore';
import { ApiKeysPageUnconnected, Props } from './ApiKeysPage';
import { getMultipleMockKeys } from './__mocks__/apiKeysMock';
@@ -21,6 +22,7 @@ jest.mock('app/core/core', () => {
});
const setup = (propOverrides: Partial) => {
+ const store = configureStore();
const loadApiKeysMock = jest.fn();
const deleteApiKeyMock = jest.fn();
const migrateApiKeyMock = jest.fn();
@@ -49,7 +51,7 @@ const setup = (propOverrides: Partial) => {
Object.assign(props, propOverrides);
const { rerender } = render(
-
+
);
diff --git a/public/app/features/dashboard-scene/sharing/ExportButton/ExportMenu.tsx b/public/app/features/dashboard-scene/sharing/ExportButton/ExportMenu.tsx
index a9b3f91b0aad7..02e99fe5ff92a 100644
--- a/public/app/features/dashboard-scene/sharing/ExportButton/ExportMenu.tsx
+++ b/public/app/features/dashboard-scene/sharing/ExportButton/ExportMenu.tsx
@@ -1,22 +1,16 @@
import { useCallback } from 'react';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
-import { SceneObject } from '@grafana/scenes';
+import { locationService } from '@grafana/runtime';
import { IconName, Menu } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { getTrackingSource, shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils';
import { DashboardScene } from '../../scene/DashboardScene';
import { DashboardInteractions } from '../../utils/interactions';
-import { ShareDrawer } from '../ShareDrawer/ShareDrawer';
-import { SceneShareDrawerState } from '../types';
-
-import { ExportAsJson } from './ExportAsJson';
const newExportButtonSelector = e2eSelectors.pages.Dashboard.DashNav.NewExportButton.Menu;
-type CustomDashboardDrawer = new (...args: SceneShareDrawerState[]) => SceneObject;
-
export interface ExportDrawerMenuItem {
shareId: string;
testId: string;
@@ -34,17 +28,9 @@ export function addDashboardExportDrawerItem(item: ExportDrawerMenuItem) {
}
export default function ExportMenu({ dashboard }: { dashboard: DashboardScene }) {
- const onMenuItemClick = useCallback(
- (title: string, component: CustomDashboardDrawer) => {
- const drawer = new ShareDrawer({
- title,
- body: new component(),
- });
-
- dashboard.showModal(drawer);
- },
- [dashboard]
- );
+ const onMenuItemClick = (shareView: string) => {
+ locationService.partial({ shareView });
+ };
const buildMenuItems = useCallback(() => {
const menuItems: ExportDrawerMenuItem[] = [];
@@ -57,11 +43,11 @@ export default function ExportMenu({ dashboard }: { dashboard: DashboardScene })
icon: 'arrow',
label: t('share-dashboard.menu.export-json-title', 'Export as JSON'),
renderCondition: true,
- onClick: () => onMenuItemClick(t('export.json.title', 'Save dashboard JSON'), ExportAsJson),
+ onClick: () => onMenuItemClick(shareDashboardType.export),
});
return menuItems.filter((item) => item.renderCondition);
- }, [onMenuItemClick]);
+ }, []);
const onClick = (item: ExportDrawerMenuItem) => {
DashboardInteractions.sharingCategoryClicked({
diff --git a/public/app/features/dashboard/components/DashNav/ShareButton.tsx b/public/app/features/dashboard/components/DashNav/ShareButton.tsx
index 5a73143687e9a..5254e1c2b673d 100644
--- a/public/app/features/dashboard/components/DashNav/ShareButton.tsx
+++ b/public/app/features/dashboard/components/DashNav/ShareButton.tsx
@@ -1,11 +1,18 @@
+import { useContext } from 'react';
+
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { locationService } from '@grafana/runtime';
-import { Button } from '@grafana/ui';
+import { Button, ModalsContext } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { DashboardModel } from 'app/features/dashboard/state';
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
+import { ShareModal } from '../ShareModal';
+import { shareDashboardType } from '../ShareModal/utils';
+
export const ShareButton = ({ dashboard }: { dashboard: DashboardModel }) => {
+ const { showModal, hideModal } = useContext(ModalsContext);
+
return (
{
size="sm"
onClick={() => {
DashboardInteractions.toolbarShareClick();
- locationService.partial({ shareView: 'link' });
+ locationService.partial({ shareView: shareDashboardType.link });
+ showModal(ShareModal, {
+ dashboard,
+ onDismiss: hideModal,
+ });
}}
>
Share
diff --git a/public/app/features/dashboard/components/DashboardLoading/CodeRabbitLogo.tsx b/public/app/features/dashboard/components/DashboardLoading/CodeRabbitLogo.tsx
new file mode 100644
index 0000000000000..2cadfda7b1f23
--- /dev/null
+++ b/public/app/features/dashboard/components/DashboardLoading/CodeRabbitLogo.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+
+type LogoFullProps = React.SVGProps;
+
+export const CodeRabbitLogo: React.FC = (props) => {
+ return (
+
+
+
+
+ );
+};
diff --git a/public/app/features/dashboard/components/DashboardLoading/FnLoader.tsx b/public/app/features/dashboard/components/DashboardLoading/FnLoader.tsx
new file mode 100644
index 0000000000000..635d10f26a694
--- /dev/null
+++ b/public/app/features/dashboard/components/DashboardLoading/FnLoader.tsx
@@ -0,0 +1,48 @@
+import { Box, CircularProgress, CircularProgressProps, Typography, type BoxProps } from '@mui/material';
+import { type ReactNode, type FC } from 'react';
+
+import { useTheme2 } from '@grafana/ui';
+
+import { CodeRabbitLogo } from './CodeRabbitLogo';
+
+export type FnLoaderProps = {
+ outerContainerProps?: Omit;
+ innerContainerProps?: Omit;
+ circularProgressProps?: CircularProgressProps;
+ text?: ReactNode;
+};
+
+export const FnLoader: FC = ({
+ outerContainerProps,
+ innerContainerProps,
+ circularProgressProps,
+ text,
+}) => {
+ const theme = useTheme2();
+
+ return (
+
+
+
+
+
+ {typeof text === 'string' ? {text} : text || null}
+
+ );
+};
diff --git a/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx b/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx
deleted file mode 100644
index a36703ab6420f..0000000000000
--- a/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx
+++ /dev/null
@@ -1,98 +0,0 @@
-import { screen, render } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-
-import { createTheme } from '@grafana/data';
-import { selectors } from '@grafana/e2e-selectors';
-import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/types';
-
-import { PanelModel } from '../../state/PanelModel';
-
-import { DashboardRow, UnthemedDashboardRow } from './DashboardRow';
-
-describe('DashboardRow', () => {
- let panel: PanelModel, dashboardMock: any;
-
- beforeEach(() => {
- dashboardMock = {
- toggleRow: jest.fn(),
- on: jest.fn(),
- meta: {
- canEdit: true,
- },
- events: { subscribe: jest.fn() },
- getRowPanels: () => [],
- };
-
- panel = new PanelModel({ collapsed: false });
- });
-
- it('Should correctly show expanded state when the panel is expanded', () => {
- render( );
- const row = screen.getByTestId(selectors.components.DashboardRow.title(''));
- expect(row).toBeInTheDocument();
- expect(row).toHaveAttribute('aria-expanded', 'true');
- });
-
- it('Should correctly show expanded state when the panel is collapsed', async () => {
- const panel = new PanelModel({ collapsed: true });
- render( );
- const row = screen.getByTestId(selectors.components.DashboardRow.title(''));
- expect(row).toHaveAttribute('aria-expanded', 'false');
- });
-
- it('Should collapse after clicking title', async () => {
- render( );
- await userEvent.click(screen.getByTestId('data-testid dashboard-row-title-'));
- expect(dashboardMock.toggleRow.mock.calls).toHaveLength(1);
- });
-
- it('Should subscribe to event during mount', () => {
- render( );
- expect(dashboardMock.events.subscribe.mock.calls).toHaveLength(1);
- });
-
- it('should have a row options and delete row button', () => {
- render( );
- expect(screen.getByRole('button', { name: 'Delete row' })).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'Row options' })).toBeInTheDocument();
- });
-
- it('should not show row drag handle when cannot edit', () => {
- dashboardMock.meta.canEdit = false;
- render( );
- expect(screen.queryByTestId('dashboard-row-container')).toBeInTheDocument();
- expect(screen.queryByTestId('dashboard-row-drag')).not.toBeInTheDocument();
- });
-
- it('should have zero actions when cannot edit', () => {
- dashboardMock.meta.canEdit = false;
- panel = new PanelModel({ collapsed: false });
- render( );
- expect(screen.queryByRole('button', { name: 'Delete row' })).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Row options' })).not.toBeInTheDocument();
- });
-
- it('Should return warning message when row panel has a panel with dashboard ds set', async () => {
- const panel = new PanelModel({
- datasource: {
- type: 'datasource',
- uid: SHARED_DASHBOARD_QUERY,
- },
- });
- const rowPanel = new PanelModel({ collapsed: true, panels: [panel] });
- const dashboardRow = new UnthemedDashboardRow({ panel: rowPanel, dashboard: dashboardMock, theme: createTheme() });
- expect(dashboardRow.getWarning()).toBeDefined();
- });
-
- it('Should not return warning message when row panel does not have a panel with dashboard ds set', async () => {
- const panel = new PanelModel({
- datasource: {
- type: 'datasource',
- uid: 'ds-uid',
- },
- });
- const rowPanel = new PanelModel({ collapsed: true, panels: [panel] });
- const dashboardRow = new UnthemedDashboardRow({ panel: rowPanel, dashboard: dashboardMock, theme: createTheme() });
- expect(dashboardRow.getWarning()).not.toBeDefined();
- });
-});
diff --git a/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx b/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
index 80cba9c2c779a..9b2d69584e2f4 100644
--- a/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
+++ b/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { indexOf } from 'lodash';
-import { Component } from 'react';
+import React from 'react';
+import { connect } from 'react-redux';
import { Unsubscribable } from 'rxjs';
import { GrafanaTheme2 } from '@grafana/data';
@@ -9,6 +10,7 @@ import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
import { Icon, TextLink, Themeable2, withTheme2 } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/types';
+import { StoreState } from 'app/types';
import { ShowConfirmModalEvent } from '../../../../types/events';
import { DashboardModel } from '../../state/DashboardModel';
@@ -18,9 +20,10 @@ import { RowOptionsButton } from '../RowOptions/RowOptionsButton';
export interface DashboardRowProps extends Themeable2 {
panel: PanelModel;
dashboard: DashboardModel;
+ isFnDashboard: boolean;
}
-export class UnthemedDashboardRow extends Component {
+class Component extends React.Component {
sub?: Unsubscribable;
componentDidMount() {
@@ -94,12 +97,14 @@ export class UnthemedDashboardRow extends Component {
};
render() {
+ const { isFnDashboard } = this.props;
+
const title = getTemplateSrv().replace(this.props.panel.title, this.props.panel.scopedVars, 'text');
const count = this.props.panel.panels ? this.props.panel.panels.length : 0;
const panels = count === 1 ? 'panel' : 'panels';
- const canEdit = this.props.dashboard.meta.canEdit === true;
- const collapsed = this.props.panel.collapsed;
+ const canEdit = this.props.dashboard.meta.canEdit === true && !isFnDashboard;
const styles = getStyles(this.props.theme);
+ const collapsed = this.props.panel.collapsed;
return (
{
}
}
-export const DashboardRow = withTheme2(UnthemedDashboardRow);
+function mapStateToProps() {
+ return (state: StoreState) => ({
+ isFnDashboard: state.fnGlobalState.FNDashboard,
+ });
+}
+
+export const DashboardRow = withTheme2(connect(mapStateToProps)(Component));
const getStyles = (theme: GrafanaTheme2) => {
const actions = css({
diff --git a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
index 6bd55b389aa0e..8b6045b57ff21 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
@@ -5,12 +5,14 @@ import { TestProvider } from 'test/helpers/TestProvider';
import { locationService, setAngularLoader, setDataSourceSrv } from '@grafana/runtime';
import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified/mocks';
+import { configureStore } from '../../../../store/configureStore';
import { DashboardModel } from '../../state/DashboardModel';
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
import { AnnotationsSettings } from './AnnotationsSettings';
function setup(dashboard: DashboardModel, editIndex?: number) {
+ const store = configureStore();
const sectionNav = {
main: { text: 'Dashboard' },
node: {
@@ -19,7 +21,7 @@ function setup(dashboard: DashboardModel, editIndex?: number) {
};
return render(
-
+
);
diff --git a/public/app/features/dashboard/components/SubMenu/SubMenu.tsx b/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
index 3fdc08ad0799c..aa2b80a47b974 100644
--- a/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
+++ b/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
@@ -1,10 +1,9 @@
import { css } from '@emotion/css';
import { PureComponent } from 'react';
-import * as React from 'react';
import { connect, MapStateToProps } from 'react-redux';
-import { AnnotationQuery, DataQuery, TypedVariableModel, GrafanaTheme2 } from '@grafana/data';
-import { DashboardLink } from '@grafana/schema';
+import { AnnotationQuery, DataQuery, GrafanaTheme2, TypedVariableModel } from '@grafana/data';
+import { DashboardLink } from '@grafana/schema/dist/esm/index';
import { stylesFactory, Themeable2, withTheme2 } from '@grafana/ui';
import { StoreState } from '../../../../types';
@@ -52,6 +51,10 @@ class SubMenuUnConnected extends PureComponent {
const styles = getStyles(theme);
+ if (!dashboard.isSubMenuVisible()) {
+ return null;
+ }
+
const readOnlyVariables = dashboard.meta.isSnapshot ?? false;
return (
@@ -74,6 +77,7 @@ class SubMenuUnConnected extends PureComponent {
const mapStateToProps: MapStateToProps = (state, ownProps) => {
const { uid } = ownProps.dashboard;
const templatingState = getVariablesState(uid, state);
+
return {
variables: getSubMenuVariables(uid, templatingState.variables),
};
@@ -81,19 +85,20 @@ const mapStateToProps: MapStateToProps = (
const getStyles = stylesFactory((theme: GrafanaTheme2) => {
return {
- formStyles: css({
- display: 'contents',
- flexWrap: 'wrap',
- }),
- submenu: css({
- display: 'flex',
- flexDirection: 'row',
- flexWrap: 'wrap',
- alignContent: 'flex-start',
- alignItems: 'flex-start',
- gap: `${theme.spacing(1)} ${theme.spacing(2)}`,
- padding: `0 0 ${theme.spacing(1)} 0`,
- }),
+ formStyles: css`
+ display: flex;
+ flex-wrap: wrap;
+ display: contents;
+ `,
+ submenu: css`
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ align-content: flex-start;
+ align-items: flex-start;
+ gap: ${theme.spacing(1)} ${theme.spacing(2)};
+ padding: 0 0 ${theme.spacing(1)} 0;
+ `,
spacer: css({
flexGrow: 1,
}),
diff --git a/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx b/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
index 9c43e1722d4e5..4c9a0afffd57b 100644
--- a/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
+++ b/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
import { GrafanaTheme2, TypedVariableModel, VariableHide } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '@grafana/ui';
+import { useSelector } from 'app/types';
import { PickerRenderer } from '../../../variables/pickers/PickerRenderer';
@@ -14,11 +15,16 @@ interface Props {
export const SubMenuItems = ({ variables, readOnly }: Props) => {
const [visibleVariables, setVisibleVariables] = useState([]);
+
+ const hiddenVariables = useSelector((state) => state.fnGlobalState.hiddenVariables);
+
const styles = useStyles2(getStyles);
useEffect(() => {
- setVisibleVariables(variables.filter((state) => state.hide !== VariableHide.hideVariable));
- }, [variables]);
+ setVisibleVariables(
+ variables.filter((state) => state.hide !== VariableHide.hideVariable && !hiddenVariables?.includes(state.id))
+ );
+ }, [variables, hiddenVariables]);
if (visibleVariables.length === 0) {
return null;
@@ -26,15 +32,17 @@ export const SubMenuItems = ({ variables, readOnly }: Props) => {
return (
<>
- {visibleVariables.map((variable) => (
-
- ))}
+ {visibleVariables.map((variable) => {
+ return (
+
+ );
+ })}
>
);
};
diff --git a/public/app/features/dashboard/containers/DashboardPage.test.tsx b/public/app/features/dashboard/containers/DashboardPage.test.tsx
deleted file mode 100644
index 4e178bfe8a6de..0000000000000
--- a/public/app/features/dashboard/containers/DashboardPage.test.tsx
+++ /dev/null
@@ -1,303 +0,0 @@
-import { screen, waitFor } from '@testing-library/react';
-import { KBarProvider } from 'kbar';
-import { Component } from 'react';
-import { match } from 'react-router-dom';
-import { useEffectOnce } from 'react-use';
-import { mockToolkitActionCreator } from 'test/core/redux/mocks';
-import { render } from 'test/test-utils';
-
-import { createTheme } from '@grafana/data';
-import { selectors } from '@grafana/e2e-selectors';
-import { config, setDataSourceSrv } from '@grafana/runtime';
-import { Dashboard } from '@grafana/schema';
-import { notifyApp } from 'app/core/actions';
-import { AppChrome } from 'app/core/components/AppChrome/AppChrome';
-import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
-import { RouteDescriptor } from 'app/core/navigation/types';
-import { HOME_NAV_ID } from 'app/core/reducers/navModel';
-import { DashboardInitPhase, DashboardMeta, DashboardRoutes } from 'app/types';
-
-import { Props as LazyLoaderProps } from '../dashgrid/LazyLoader';
-import { DashboardSrv, setDashboardSrv } from '../services/DashboardSrv';
-import { DashboardModel } from '../state';
-import { createDashboardModelFixture } from '../state/__fixtures__/dashboardFixtures';
-
-import { Props, UnthemedDashboardPage } from './DashboardPage';
-
-jest.mock('app/features/dashboard/dashgrid/LazyLoader', () => {
- const LazyLoader = ({ children, onLoad }: Pick) => {
- useEffectOnce(() => {
- onLoad?.();
- });
- return <>{typeof children === 'function' ? children({ isInView: true }) : children}>;
- };
- return { LazyLoader };
-});
-
-jest.mock('app/features/dashboard/components/DashboardSettings/GeneralSettings', () => {
- class GeneralSettings extends Component<{}, {}> {
- render() {
- return <>general settings>;
- }
- }
-
- return { GeneralSettings };
-});
-
-jest.mock('app/features/query/components/QueryGroup', () => {
- return {
- QueryGroup: () => null,
- };
-});
-
-jest.mock('app/core/core', () => ({
- appEvents: {
- subscribe: () => {
- return { unsubscribe: () => {} };
- },
- },
- contextSrv: {
- user: { orgId: 1 },
- },
-}));
-
-jest.mock('@grafana/runtime', () => ({
- ...jest.requireActual('@grafana/runtime'),
- getPluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
- usePluginLinkExtensions: jest.fn().mockReturnValue({ extensions: [] }),
-}));
-
-function getTestDashboard(overrides?: Partial, metaOverrides?: Partial): DashboardModel {
- const data = Object.assign(
- {
- title: 'My dashboard',
- panels: [
- {
- id: 1,
- type: 'timeseries',
- title: 'My panel title',
- gridPos: { x: 0, y: 0, w: 1, h: 1 },
- },
- ],
- },
- overrides
- );
-
- return createDashboardModelFixture(data, metaOverrides);
-}
-
-const mockInitDashboard = jest.fn();
-const mockCleanUpDashboardAndVariables = jest.fn();
-
-function setup(propOverrides?: Partial) {
- config.bootData.navTree = [
- { text: 'Dashboards', id: 'dashboards/browse' },
- { text: 'Home', id: HOME_NAV_ID },
- {
- text: 'Help',
- id: 'help',
- },
- ];
-
- const props: Props = {
- ...getRouteComponentProps({
- match: { params: { slug: 'my-dash', uid: '11' } } as unknown as match,
- route: { routeName: DashboardRoutes.Normal } as RouteDescriptor,
- }),
- navIndex: {
- 'dashboards/browse': {
- text: 'Dashboards',
- id: 'dashboards/browse',
- parentItem: { text: 'Home', id: HOME_NAV_ID },
- },
- [HOME_NAV_ID]: { text: 'Home', id: HOME_NAV_ID },
- },
- initPhase: DashboardInitPhase.NotStarted,
- initError: null,
- initDashboard: mockInitDashboard,
- notifyApp: mockToolkitActionCreator(notifyApp),
- cleanUpDashboardAndVariables: mockCleanUpDashboardAndVariables,
- cancelVariables: jest.fn(),
- templateVarsChangedInUrl: jest.fn(),
- dashboard: null,
- theme: createTheme(),
- };
-
- Object.assign(props, propOverrides);
-
- const { unmount, rerender } = render( );
-
- const wrappedRerender = (newProps: Partial) => {
- Object.assign(props, newProps);
- return rerender( );
- };
-
- return { rerender: wrappedRerender, unmount };
-}
-
-describe('DashboardPage', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- it('Should call initDashboard on mount', () => {
- setup();
- expect(mockInitDashboard).toBeCalledWith({
- fixUrl: true,
- routeName: 'normal-dashboard',
- urlSlug: 'my-dash',
- urlUid: '11',
- keybindingSrv: expect.anything(),
- });
- });
-
- describe('Given a simple dashboard', () => {
- it('Should render panels', async () => {
- setup({ dashboard: getTestDashboard() });
- expect(await screen.findByText('My panel title')).toBeInTheDocument();
- });
-
- it('Should update title', async () => {
- setup({ dashboard: getTestDashboard() });
- await waitFor(() => {
- expect(document.title).toBe('My dashboard - Dashboards - Grafana');
- });
- });
-
- it('only calls initDashboard once when wrapped in AppChrome', async () => {
- const props: Props = {
- ...getRouteComponentProps({
- match: { params: { slug: 'my-dash', uid: '11' }, isExact: true, path: '', url: '' },
- route: { routeName: DashboardRoutes.Normal } as RouteDescriptor,
- }),
- navIndex: {
- 'dashboards/browse': {
- text: 'Dashboards',
- id: 'dashboards/browse',
- parentItem: { text: 'Home', id: HOME_NAV_ID },
- },
- [HOME_NAV_ID]: { text: 'Home', id: HOME_NAV_ID },
- },
- initPhase: DashboardInitPhase.Completed,
- initError: null,
- initDashboard: mockInitDashboard,
- notifyApp: mockToolkitActionCreator(notifyApp),
- cleanUpDashboardAndVariables: mockCleanUpDashboardAndVariables,
- cancelVariables: jest.fn(),
- templateVarsChangedInUrl: jest.fn(),
- dashboard: getTestDashboard(),
- theme: createTheme(),
- };
-
- render(
-
-
-
-
-
- );
-
- await screen.findByText('My dashboard');
- expect(mockInitDashboard).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('When going into view mode', () => {
- beforeEach(() => {
- setDataSourceSrv({
- get: jest.fn().mockResolvedValue({ getRef: jest.fn(), query: jest.fn().mockResolvedValue([]) }),
- getInstanceSettings: jest.fn().mockReturnValue({ meta: {} }),
- getList: jest.fn(),
- reload: jest.fn(),
- });
- setDashboardSrv({
- getCurrent: () => getTestDashboard(),
- } as DashboardSrv);
- });
-
- it('Should render panel in view mode', async () => {
- const dashboard = getTestDashboard();
- setup({
- dashboard,
- queryParams: { viewPanel: '1' },
- });
- await waitFor(() => {
- expect(dashboard.panelInView).toBeDefined();
- expect(dashboard.panels[0].isViewing).toBe(true);
- });
- });
-
- it('Should reset state when leaving', async () => {
- const dashboard = getTestDashboard();
- const { rerender } = setup({
- dashboard,
- queryParams: { viewPanel: '1' },
- });
- rerender({ queryParams: {}, dashboard });
-
- await waitFor(() => {
- expect(dashboard.panelInView).toBeUndefined();
- expect(dashboard.panels[0].isViewing).toBe(false);
- });
- });
- });
-
- describe('When going into edit mode', () => {
- it('Should render panel in edit mode', async () => {
- const dashboard = getTestDashboard();
- setup({
- dashboard,
- queryParams: { editPanel: '1' },
- });
- await waitFor(() => {
- expect(dashboard.panelInEdit).toBeDefined();
- });
- });
- });
-
- describe('When dashboard unmounts', () => {
- it('Should call close action', async () => {
- const { rerender, unmount } = setup();
- rerender({ dashboard: getTestDashboard() });
- unmount();
- await waitFor(() => {
- expect(mockCleanUpDashboardAndVariables).toHaveBeenCalledTimes(1);
- });
- });
- });
-
- describe('When dashboard changes', () => {
- it('Should call clean up action and init', async () => {
- const { rerender } = setup();
- rerender({ dashboard: getTestDashboard() });
- rerender({
- match: { params: { uid: 'new-uid' } } as unknown as match,
- dashboard: getTestDashboard({ title: 'Another dashboard' }),
- });
- await waitFor(() => {
- expect(mockCleanUpDashboardAndVariables).toHaveBeenCalledTimes(1);
- expect(mockInitDashboard).toHaveBeenCalledTimes(2);
- });
- });
- });
-
- describe('No kiosk mode tv', () => {
- it('should render dashboard page toolbar with no submenu', async () => {
- setup({
- dashboard: getTestDashboard(),
- });
- expect(await screen.findAllByTestId(selectors.pages.Dashboard.DashNav.navV2)).toHaveLength(1);
- expect(screen.queryAllByLabelText(selectors.pages.Dashboard.SubMenu.submenu)).toHaveLength(0);
- });
- });
-
- describe('When in full kiosk mode', () => {
- it('should not render page toolbar and submenu', async () => {
- setup({ dashboard: getTestDashboard(), queryParams: { kiosk: true } });
- await waitFor(() => {
- expect(screen.queryAllByTestId(selectors.pages.Dashboard.DashNav.navV2)).toHaveLength(0);
- expect(screen.queryAllByLabelText(selectors.pages.Dashboard.SubMenu.submenu)).toHaveLength(0);
- });
- });
- });
-});
diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx
index ecc58a535a682..5ebe4cbcd006c 100644
--- a/public/app/features/dashboard/containers/DashboardPage.tsx
+++ b/public/app/features/dashboard/containers/DashboardPage.tsx
@@ -1,61 +1,102 @@
-import { css, cx } from '@emotion/css';
-import { PureComponent } from 'react';
-import { connect, ConnectedProps } from 'react-redux';
+import { cx } from '@emotion/css';
+import { Portal } from '@mui/material';
+import React, { PureComponent } from 'react';
+import { connect, ConnectedProps, MapDispatchToProps, MapStateToProps } from 'react-redux';
-import { NavModel, NavModelItem, TimeRange, PageLayoutType, locationUtil, GrafanaTheme2 } from '@grafana/data';
+import { NavModel, NavModelItem, TimeRange, PageLayoutType, locationUtil } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { config, locationService } from '@grafana/runtime';
-import { Themeable2, withTheme2 } from '@grafana/ui';
+import { Themeable2, withTheme2, ToolbarButtonRow } from '@grafana/ui';
import { notifyApp } from 'app/core/actions';
-import { ScrollRefElement } from 'app/core/components/NativeScrollbar';
import { Page } from 'app/core/components/Page/Page';
import { EntityNotFound } from 'app/core/components/PageNotFound/EntityNotFound';
import { GrafanaContext, GrafanaContextType } from 'app/core/context/GrafanaContext';
import { createErrorNotification } from 'app/core/copy/appNotification';
import { getKioskMode } from 'app/core/navigation/kiosk';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
-import { ID_PREFIX } from 'app/core/reducers/navBarTree';
+import { FnGlobalState } from 'app/core/reducers/fn-slice';
import { getNavModel } from 'app/core/selectors/navModel';
import { PanelModel } from 'app/features/dashboard/state';
import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
-import { AngularDeprecationNotice } from 'app/features/plugins/angularDeprecation/AngularDeprecationNotice';
-import { AngularMigrationNotice } from 'app/features/plugins/angularDeprecation/AngularMigrationNotice';
+import { updateTimeZoneForSession } from 'app/features/profile/state/reducers';
import { getPageNavFromSlug, getRootContentNavModel } from 'app/features/storage/StorageFolderPage';
-import { DashboardRoutes, KioskMode, StoreState } from 'app/types';
+import { FNDashboardProps } from 'app/fn-app/types';
+import { DashboardRoutes, DashboardState, KioskMode, StoreState } from 'app/types';
import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events';
import { cancelVariables, templateVarsChangedInUrl } from '../../variables/state/actions';
import { findTemplateVarChanges } from '../../variables/utils';
import { AddWidgetModal } from '../components/AddWidgetModal/AddWidgetModal';
import { DashNav } from '../components/DashNav';
+import { DashNavTimeControls } from '../components/DashNav/DashNavTimeControls';
import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed';
import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading';
+import { FnLoader } from '../components/DashboardLoading/FnLoader';
import { DashboardPrompt } from '../components/DashboardPrompt/DashboardPrompt';
import { DashboardSettings } from '../components/DashboardSettings';
import { PanelInspector } from '../components/Inspector/PanelInspector';
import { PanelEditor } from '../components/PanelEditor/PanelEditor';
-import { ShareModal } from '../components/ShareModal';
import { SubMenu } from '../components/SubMenu/SubMenu';
import { DashboardGrid } from '../dashgrid/DashboardGrid';
import { liveTimer } from '../dashgrid/liveTimer';
import { getTimeSrv } from '../services/TimeSrv';
-import { explicitlyControlledMigrationPanels, autoMigrateAngular } from '../state/PanelModel';
import { cleanUpDashboardAndVariables } from '../state/actions';
import { initDashboard } from '../state/initDashboard';
+import { calculateNewPanelGridPos } from '../utils/panel';
+
+export interface DashboardPageRouteParams {
+ uid?: string;
+ type?: string;
+ slug?: string;
+ accessToken?: string;
+ version?: number;
+}
-import { DashboardPageRouteParams, DashboardPageRouteSearchParams } from './types';
+export type DashboardPageRouteSearchParams = {
+ tab?: string;
+ folderUid?: string;
+ editPanel?: string;
+ viewPanel?: string;
+ editview?: string;
+ shareView?: string;
+ addWidget?: boolean;
+ panelType?: string;
+ inspect?: string;
+ from?: string;
+ to?: string;
+ refresh?: string;
+ kiosk?: string | true;
+};
-import 'react-grid-layout/css/styles.css';
-import 'react-resizable/css/styles.css';
+export type MapStateToDashboardPageProps = MapStateToProps<
+ Pick & {
+ dashboard: ReturnType;
+ navIndex: StoreState['navIndex'];
+ } & Pick,
+ OwnProps,
+ StoreState
+>;
+
+export type MapDispatchToDashboardPageProps = MapDispatchToProps;
+
+export type MappedDispatch = {
+ initDashboard: typeof initDashboard;
+ cleanUpDashboardAndVariables: typeof cleanUpDashboardAndVariables;
+ notifyApp: typeof notifyApp;
+ cancelVariables: typeof cancelVariables;
+ templateVarsChangedInUrl: typeof templateVarsChangedInUrl;
+};
-export const mapStateToProps = (state: StoreState) => ({
+export const mapStateToProps: MapStateToDashboardPageProps = (state) => ({
initPhase: state.dashboard.initPhase,
initError: state.dashboard.initError,
dashboard: state.dashboard.getModel(),
navIndex: state.navIndex,
+ FNDashboard: state.fnGlobalState.FNDashboard,
+ controlsContainer: state.fnGlobalState.controlsContainer,
});
-const mapDispatchToProps = {
+const mapDispatchToProps: MapDispatchToDashboardPageProps = {
initDashboard,
cleanUpDashboardAndVariables,
notifyApp,
@@ -65,6 +106,16 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps);
+type OwnProps = {
+ isPublic?: boolean;
+ controlsContainer?: string | null;
+ version?: FNDashboardProps['version'];
+ isLoading?: FNDashboardProps['isLoading'];
+};
+
+export type DashboardPageProps = OwnProps &
+ GrafanaRouteComponentProps;
+
export type Props = Themeable2 &
GrafanaRouteComponentProps &
ConnectedProps;
@@ -72,51 +123,16 @@ export type Props = Themeable2 &
export interface State {
editPanel: PanelModel | null;
viewPanel: PanelModel | null;
- editView: string | null;
updateScrollTop?: number;
rememberScrollTop?: number;
showLoadingState: boolean;
panelNotFound: boolean;
editPanelAccessDenied: boolean;
- scrollElement?: ScrollRefElement;
+ scrollElement?: HTMLDivElement;
pageNav?: NavModelItem;
sectionNav?: NavModel;
}
-const getStyles = (theme: GrafanaTheme2) => ({
- fullScreenPanel: css({
- '.react-grid-layout': {
- height: 'auto !important',
- transitionProperty: 'none',
- },
- '.react-grid-item': {
- display: 'none !important',
- transitionProperty: 'none !important',
-
- '&--fullscreen': {
- display: 'block !important',
- // can't avoid type assertion here due to !important
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
- position: 'unset !important' as 'unset',
- transform: 'translate(0px, 0px) !important',
- },
- },
-
- // Disable grid interaction indicators in fullscreen panels
- '.panel-header:hover': {
- backgroundColor: 'inherit',
- },
-
- '.panel-title-container': {
- cursor: 'pointer',
- },
-
- '.react-resizable-handle': {
- display: 'none',
- },
- }),
-});
-
export class UnthemedDashboardPage extends PureComponent {
declare context: GrafanaContextType;
static contextType = GrafanaContext;
@@ -126,7 +142,6 @@ export class UnthemedDashboardPage extends PureComponent {
getCleanState(): State {
return {
- editView: null,
editPanel: null,
viewPanel: null,
showLoadingState: false,
@@ -137,7 +152,11 @@ export class UnthemedDashboardPage extends PureComponent {
componentDidMount() {
this.initDashboard();
- this.forceRouteReloadCounter = (this.props.history.location.state as any)?.routeReloadCounter || 0;
+ const { FNDashboard } = this.props;
+
+ if (!FNDashboard) {
+ this.forceRouteReloadCounter = (this.props.history.location?.state as any)?.routeReloadCounter || 0;
+ }
}
componentWillUnmount() {
@@ -150,7 +169,7 @@ export class UnthemedDashboardPage extends PureComponent {
}
initDashboard() {
- const { dashboard, match, queryParams } = this.props;
+ const { dashboard, match, queryParams, FNDashboard } = this.props;
if (dashboard) {
this.closeDashboard();
@@ -160,10 +179,10 @@ export class UnthemedDashboardPage extends PureComponent {
urlSlug: match.params.slug,
urlUid: match.params.uid,
urlType: match.params.type,
- urlFolderUid: queryParams.folderUid,
+ // urlFolderUid: queryParams.folderUid,
panelType: queryParams.panelType,
routeName: this.props.route.routeName,
- fixUrl: true,
+ fixUrl: !FNDashboard,
accessToken: match.params.accessToken,
keybindingSrv: this.context.keybindings,
});
@@ -173,20 +192,24 @@ export class UnthemedDashboardPage extends PureComponent {
}
componentDidUpdate(prevProps: Props, prevState: State) {
- const { dashboard, match, templateVarsChangedInUrl } = this.props;
- const routeReloadCounter = (this.props.history.location.state as any)?.routeReloadCounter;
+ const { dashboard, match, templateVarsChangedInUrl, FNDashboard } = this.props;
if (!dashboard) {
return;
}
- if (
- prevProps.match.params.uid !== match.params.uid ||
- (routeReloadCounter !== undefined && this.forceRouteReloadCounter !== routeReloadCounter)
- ) {
- this.initDashboard();
- this.forceRouteReloadCounter = routeReloadCounter;
- return;
+ if (!FNDashboard) {
+ const routeReloadCounter = (this.props.history.location?.state as any)?.routeReloadCounter;
+
+ if (
+ prevProps.match.params.uid !== match.params.uid ||
+ prevProps.match.params.version !== match.params.version ||
+ (routeReloadCounter !== undefined && this.forceRouteReloadCounter !== routeReloadCounter)
+ ) {
+ this.initDashboard();
+ this.forceRouteReloadCounter = routeReloadCounter;
+ return;
+ }
}
if (prevProps.location.search !== this.props.location.search) {
@@ -234,11 +257,6 @@ export class UnthemedDashboardPage extends PureComponent {
this.props.notifyApp(createErrorNotification(`Panel not found`));
locationService.partial({ editPanel: null, viewPanel: null });
}
-
- // Update window scroll position
- if (this.state.updateScrollTop !== undefined && this.state.updateScrollTop !== prevState.updateScrollTop) {
- this.state.scrollElement?.scrollTo(0, this.state.updateScrollTop);
- }
}
updateLiveTimer = () => {
@@ -254,7 +272,6 @@ export class UnthemedDashboardPage extends PureComponent {
const urlEditPanelId = queryParams.editPanel;
const urlViewPanelId = queryParams.viewPanel;
- const urlEditView = queryParams.editview;
if (!dashboard) {
return state;
@@ -262,19 +279,6 @@ export class UnthemedDashboardPage extends PureComponent {
const updatedState = { ...state };
- // Entering settings view
- if (!state.editView && urlEditView) {
- updatedState.editView = urlEditView;
- updatedState.rememberScrollTop = state.scrollElement?.scrollTop;
- updatedState.updateScrollTop = 0;
- }
-
- // Leaving settings view
- else if (state.editView && !urlEditView) {
- updatedState.updateScrollTop = state.rememberScrollTop;
- updatedState.editView = null;
- }
-
// Entering edit mode
if (!state.editPanel && urlEditPanelId) {
const panel = dashboard.getPanelByUrlId(urlEditPanelId);
@@ -327,7 +331,30 @@ export class UnthemedDashboardPage extends PureComponent {
return updateStatePageNavFromProps(props, updatedState);
}
- setScrollRef = (scrollElement: ScrollRefElement): void => {
+ // Todo: Remove this when we remove the emptyDashboardPage toggle
+ onAddPanel = () => {
+ const { dashboard } = this.props;
+
+ if (!dashboard) {
+ return;
+ }
+
+ // Return if the "Add panel" exists already
+ if (dashboard.panels.length > 0 && dashboard.panels[0].type === 'add-panel') {
+ return;
+ }
+
+ dashboard.addPanel({
+ type: 'add-panel',
+ gridPos: calculateNewPanelGridPos(dashboard),
+ title: 'Panel Title',
+ });
+
+ // scroll to top after adding panel
+ this.setState({ updateScrollTop: 0 });
+ };
+
+ setScrollRef = (scrollElement: HTMLDivElement): void => {
this.setState({ scrollElement });
};
@@ -350,27 +377,22 @@ export class UnthemedDashboardPage extends PureComponent {
return inspectPanel;
}
- onCloseShareModal = () => {
- locationService.partial({ shareView: null });
- };
-
render() {
- const { dashboard, initError, queryParams, theme } = this.props;
+ const { dashboard, initError, queryParams, FNDashboard, controlsContainer } = this.props;
const { editPanel, viewPanel, pageNav, sectionNav } = this.state;
const kioskMode = getKioskMode(this.props.queryParams);
- const styles = getStyles(theme);
- if (!dashboard || !pageNav || !sectionNav) {
- return ;
+ if (!dashboard) {
+ return FNDashboard ? : ;
}
const inspectPanel = this.getInspectPanel();
- const showSubMenu = !editPanel && !kioskMode && !this.props.queryParams.editview && dashboard.isSubMenuVisible();
+ const showSubMenu = !editPanel && !kioskMode && !this.props.queryParams.editview;
- const showToolbar = kioskMode !== KioskMode.Full && !queryParams.editview;
+ const showToolbar = FNDashboard || (kioskMode !== KioskMode.Full && !queryParams.editview);
const pageClassName = cx({
- [styles.fullScreenPanel]: Boolean(viewPanel),
+ 'panel-in-fullscreen': Boolean(viewPanel),
'page-hidden': Boolean(queryParams.editview || editPanel),
});
@@ -382,100 +404,63 @@ export class UnthemedDashboardPage extends PureComponent {
);
}
- const migrationFeatureFlags = new Set([
- 'autoMigrateOldPanels',
- 'autoMigrateGraphPanel',
- 'autoMigrateTablePanel',
- 'autoMigratePiechartPanel',
- 'autoMigrateWorldmapPanel',
- 'autoMigrateStatPanel',
- 'disableAngular',
- ]);
-
- const isAutoMigrationFlagSet = () => {
- const urlParams = new URLSearchParams(window.location.search);
- let isFeatureFlagSet = false;
-
- urlParams.forEach((value, key) => {
- if (key.startsWith('__feature.')) {
- const featureName = key.substring(10);
- const toggleState = value === 'true' || value === '';
- const featureToggles = config.featureToggles as Record;
-
- if (featureToggles[featureName]) {
- return;
- }
-
- if (migrationFeatureFlags.has(featureName) && toggleState) {
- isFeatureFlagSet = true;
- return;
- }
- }
- });
-
- return isFeatureFlagSet;
- };
-
- const dashboardWasAngular = dashboard.panels.some(
- (panel) => panel.autoMigrateFrom && autoMigrateAngular[panel.autoMigrateFrom] != null
+ const FNTimeRange = !controlsContainer ? (
+
+
+
+ ) : (
+
+
+
+
+
);
- const showDashboardMigrationNotice =
- config.featureToggles.angularDeprecationUI &&
- dashboardWasAngular &&
- isAutoMigrationFlagSet() &&
- dashboard.uid !== null;
-
return (
- <>
+
{showToolbar && (
-
+ {FNDashboard ? (
+ FNTimeRange
+ ) : (
+
+ )}
)}
-
+ {!FNDashboard && }
{initError && }
{showSubMenu && (
)}
- {config.featureToggles.angularDeprecationUI && dashboard.hasAngularPlugins() && dashboard.uid !== null && (
-
- explicitlyControlledMigrationPanels.includes(panel.type)
- )}
- />
- )}
- {showDashboardMigrationNotice && }
- {inspectPanel && }
- {queryParams.shareView && (
-
- )}
+ {inspectPanel && !FNDashboard && }
- {editPanel && (
+ {editPanel && !FNDashboard && sectionNav && pageNav && (
{
pageNav={pageNav}
/>
)}
- {queryParams.editview && (
+ {queryParams.editview && !FNDashboard && pageNav && sectionNav && (
{
sectionNav={sectionNav}
/>
)}
- {queryParams.addWidget && config.featureToggles.vizAndWidgetSplit && }
- >
+ {!FNDashboard && queryParams.addWidget && config.featureToggles.vizAndWidgetSplit && }
+
);
}
}
function updateStatePageNavFromProps(props: Props, state: State): State {
- const { dashboard, navIndex } = props;
+ const { dashboard, FNDashboard } = props;
- if (!dashboard) {
+ if (!dashboard || FNDashboard) {
return state;
}
let pageNav = state.pageNav;
let sectionNav = state.sectionNav;
- if (!pageNav || dashboard.title !== pageNav.text || dashboard.meta.folderUrl !== pageNav.parentItem?.url) {
+ if (!pageNav || dashboard.title !== pageNav.text) {
pageNav = {
text: dashboard.title,
url: locationUtil.getUrlForPartial(props.history.location, {
@@ -519,6 +504,18 @@ function updateStatePageNavFromProps(props: Props, state: State): State {
};
}
+ // Check if folder changed
+ const { folderTitle, folderUid } = dashboard.meta;
+ if (folderTitle && folderUid && pageNav && pageNav.parentItem?.text !== folderTitle) {
+ pageNav = {
+ ...pageNav,
+ parentItem: {
+ text: folderTitle,
+ url: `/dashboards/f/${dashboard.meta.folderUid}`,
+ },
+ };
+ }
+
if (props.route.routeName === DashboardRoutes.Path) {
sectionNav = getRootContentNavModel();
const pageNav = getPageNavFromSlug(props.match.params.slug!);
@@ -526,24 +523,7 @@ function updateStatePageNavFromProps(props: Props, state: State): State {
pageNav.parentItem = pageNav.parentItem;
}
} else {
- sectionNav = getNavModel(
- props.navIndex,
- ID_PREFIX + dashboard.uid,
- getNavModel(props.navIndex, 'dashboards/browse')
- );
- }
-
- const { folderUid } = dashboard.meta;
- if (folderUid && pageNav && sectionNav.main.id !== 'starred') {
- const folderNavModel = getNavModel(navIndex, `folder-dashboards-${folderUid}`).main;
- // If the folder hasn't loaded (maybe user doesn't have permission on it?) then
- // don't show the "page not found" breadcrumb
- if (folderNavModel.id !== 'not-found') {
- pageNav = {
- ...pageNav,
- parentItem: folderNavModel,
- };
- }
+ sectionNav = getNavModel(props.navIndex, config.featureToggles.topnav ? 'dashboards/browse' : 'dashboards');
}
if (state.editPanel || state.viewPanel) {
diff --git a/public/app/features/dashboard/containers/SoloPanelPage.tsx b/public/app/features/dashboard/containers/SoloPanelPage.tsx
index 76e38b778c8fe..7b38a12b2511a 100644
--- a/public/app/features/dashboard/containers/SoloPanelPage.tsx
+++ b/public/app/features/dashboard/containers/SoloPanelPage.tsx
@@ -55,7 +55,7 @@ export class SoloPanelPage extends Component {
urlType: match.params.type,
routeName: route.routeName,
fixUrl: false,
- keybindingSrv: this.context.keybindings,
+ keybindingSrv: this.context?.keybindings,
});
}
diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
index be9499a53de65..fef25cc59b942 100644
--- a/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
@@ -17,7 +17,7 @@ import { DashboardMeta } from 'app/types';
import { DashboardModel } from '../state';
import { createDashboardModelFixture } from '../state/__fixtures__/dashboardFixtures';
-import { DashboardGrid, PANEL_FILTER_VARIABLE, Props } from './DashboardGrid';
+import { DashboardGrid, Props } from './DashboardGrid';
import { Props as LazyLoaderProps } from './LazyLoader';
jest.mock('@grafana/runtime', () => ({
@@ -133,7 +133,7 @@ describe('DashboardGrid', () => {
refreshAll: false,
variable: {
type: 'textbox',
- id: PANEL_FILTER_VARIABLE,
+ id: '1',
current: {
value: 'My graph',
},
@@ -158,7 +158,7 @@ describe('DashboardGrid', () => {
isEditable: true,
dashboard: getTestDashboard(undefined, undefined, () => [
{
- id: PANEL_FILTER_VARIABLE,
+ id: '1',
type: 'textbox',
query: 'My tab',
} as TextBoxVariableModel,
diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
index cb09e66048aa4..70c88a5d54182 100644
--- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
@@ -1,14 +1,14 @@
import classNames from 'classnames';
-import { PureComponent, CSSProperties } from 'react';
-import * as React from 'react';
+import React, { PureComponent, CSSProperties } from 'react';
import ReactGridLayout, { ItemCallback } from 'react-grid-layout';
+import { connect } from 'react-redux';
+import AutoSizer from 'react-virtualized-auto-sizer';
import { Subscription } from 'rxjs';
import { config } from '@grafana/runtime';
-import appEvents from 'app/core/app_events';
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
import { contextSrv } from 'app/core/services/context_srv';
-import { VariablesChanged } from 'app/features/variables/types';
+import { StoreState } from 'app/types';
import { DashboardPanelsChangedEvent } from 'app/types/events';
import { AddLibraryPanelWidget } from '../components/AddLibraryPanelWidget';
@@ -19,22 +19,16 @@ import { GridPos } from '../state/PanelModel';
import DashboardEmpty from './DashboardEmpty';
import { DashboardPanel } from './DashboardPanel';
-export const PANEL_FILTER_VARIABLE = 'systemPanelFilterVar';
-
export interface Props {
dashboard: DashboardModel;
isEditable: boolean;
editPanel: PanelModel | null;
viewPanel: PanelModel | null;
hidePanelMenus?: boolean;
+ isFnDashboard?: boolean;
}
-interface State {
- panelFilter?: RegExp;
- width: number;
-}
-
-export class DashboardGrid extends PureComponent {
+export class Component extends PureComponent {
private panelMap: { [key: string]: PanelModel } = {};
private eventSubs = new Subscription();
private windowHeight = 1200;
@@ -46,41 +40,10 @@ export class DashboardGrid extends PureComponent {
constructor(props: Props) {
super(props);
- this.state = {
- panelFilter: undefined,
- width: document.body.clientWidth, // initial very rough estimate
- };
}
componentDidMount() {
const { dashboard } = this.props;
-
- if (config.featureToggles.panelFilterVariable) {
- // If panel filter variable is set on load then
- // update state to filter panels
- for (const variable of dashboard.getVariables()) {
- if (variable.id === PANEL_FILTER_VARIABLE) {
- if ('query' in variable) {
- this.setPanelFilter(variable.query);
- }
- break;
- }
- }
-
- this.eventSubs.add(
- appEvents.subscribe(VariablesChanged, (e) => {
- if (e.payload.variable?.id === PANEL_FILTER_VARIABLE) {
- if ('current' in e.payload.variable) {
- let variable = e.payload.variable.current;
- if ('value' in variable && typeof variable.value === 'string') {
- this.setPanelFilter(variable.value);
- }
- }
- }
- })
- );
- }
-
this.eventSubs.add(dashboard.events.subscribe(DashboardPanelsChangedEvent, this.triggerForceUpdate));
}
@@ -88,25 +51,10 @@ export class DashboardGrid extends PureComponent {
this.eventSubs.unsubscribe();
}
- setPanelFilter(regex: string) {
- // Only set the panels filter if the systemPanelFilterVar variable
- // is a non-empty string
- let panelFilter = undefined;
- if (regex.length > 0) {
- panelFilter = new RegExp(regex, 'i');
- }
-
- this.setState({
- panelFilter: panelFilter,
- });
- }
-
buildLayout() {
const layout: ReactGridLayout.Layout[] = [];
this.panelMap = {};
- const { panelFilter } = this.state;
- let count = 0;
for (const panel of this.props.dashboard.panels) {
if (!panel.key) {
panel.key = `panel-${panel.id}-${Date.now()}`;
@@ -133,27 +81,13 @@ export class DashboardGrid extends PureComponent {
panelPos.isDraggable = panel.collapsed;
}
- if (!panelFilter) {
- layout.push(panelPos);
- } else {
- if (panelFilter.test(panel.title)) {
- panelPos.isResizable = false;
- panelPos.isDraggable = false;
- panelPos.x = (count % 2) * GRID_COLUMN_COUNT;
- panelPos.y = Math.floor(count / 2);
- layout.push(panelPos);
- count++;
- }
- }
+ layout.push(panelPos);
}
return layout;
}
onLayoutChange = (newLayout: ReactGridLayout.Layout[]) => {
- if (this.state.panelFilter) {
- return;
- }
for (const newPos of newLayout) {
this.panelMap[newPos.i!].updateGridPos(newPos, this.isLayoutInitialized);
}
@@ -205,7 +139,6 @@ export class DashboardGrid extends PureComponent {
}
renderPanels(gridWidth: number, isDashboardDraggable: boolean) {
- const { panelFilter } = this.state;
const panelElements = [];
// Reset last panel bottom
@@ -222,7 +155,7 @@ export class DashboardGrid extends PureComponent {
for (const panel of this.props.dashboard.panels) {
const panelClasses = classNames({ 'react-grid-item--fullscreen': panel.isViewing });
- const p = (
+ panelElements.push(
{
}}
);
-
- if (!panelFilter) {
- panelElements.push(p);
- } else {
- if (panelFilter.test(panel.title)) {
- panelElements.push(p);
- }
- }
}
return panelElements;
@@ -288,69 +213,61 @@ export class DashboardGrid extends PureComponent {
}
};
- private resizeObserver?: ResizeObserver;
- private rootEl: HTMLDivElement | null = null;
- onMeasureRef = (rootEl: HTMLDivElement | null) => {
- if (!rootEl) {
- if (this.rootEl && this.resizeObserver) {
- this.resizeObserver.unobserve(this.rootEl);
- }
- return;
- }
-
- this.rootEl = rootEl;
- this.resizeObserver = new ResizeObserver((entries) => {
- entries.forEach((entry) => {
- this.setState({ width: entry.contentRect.width });
- });
- });
-
- this.resizeObserver.observe(rootEl);
- };
-
render() {
- const { isEditable, dashboard } = this.props;
- const { width } = this.state;
+ const { isEditable, dashboard, isFnDashboard } = this.props;
- if (dashboard.panels.length === 0) {
+ if (config.featureToggles.emptyDashboardPage && dashboard.panels.length === 0) {
return ;
}
- const draggable = width <= config.theme2.breakpoints.values.md ? false : isEditable;
-
- // pos: rel + z-index is required to create a new stacking context to contain
- // the escalating z-indexes of the panels
+ /**
+ * We have a parent with "flex: 1 1 0" we need to reset it to "flex: 1 1 auto" to have the AutoSizer
+ * properly working. For more information go here:
+ * https://github.com/bvaughn/react-virtualized/blob/master/docs/usingAutoSizer.md#can-i-use-autosizer-within-a-flex-container
+ */
return (
-
-
-
- {this.renderPanels(width, draggable)}
-
-
+
+
+ {({ width }) => {
+ if (width === 0) {
+ return null;
+ }
+
+ // Disable draggable if mobile device, solving an issue with unintentionally
+ // moving panels. https://github.com/grafana/grafana/issues/18497
+ const isLg = width <= config.theme2.breakpoints.values.md;
+ const draggable = isLg ? false : isEditable;
+
+ return (
+ /**
+ * The children is using a width of 100% so we need to guarantee that it is wrapped
+ * in an element that has the calculated size given by the AutoSizer. The AutoSizer
+ * has a width of 0 and will let its content overflow its div.
+ */
+
+
+ {this.renderPanels(width, draggable)}
+
+
+ );
+ }}
+
);
}
@@ -362,7 +279,7 @@ interface GrafanaGridItemProps extends React.HTMLAttributes
{
isViewing: boolean;
windowHeight: number;
windowWidth: number;
- children: any; // eslint-disable-line @typescript-eslint/no-explicit-any
+ children: any;
}
/**
@@ -403,7 +320,7 @@ const GrafanaGridItem = React.forwardRef((
// props.children[0] is our main children. RGL adds the drag handle at props.children[1]
return (
-
+
{/* Pass width and height to children as render props */}
{[props.children[0](width, height), props.children.slice(1)]}
@@ -418,3 +335,11 @@ function translateGridHeightToScreenHeight(gridHeight: number): number {
}
GrafanaGridItem.displayName = 'GridItemWithDimensions';
+
+function mapStateToProps() {
+ return (state: StoreState) => ({
+ isFnDashboard: state.fnGlobalState.FNDashboard,
+ });
+}
+
+export const DashboardGrid = connect(mapStateToProps)(Component);
diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
index b0873eabb0712..b2c34f0b392b8 100644
--- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
@@ -58,7 +58,7 @@ export class DashboardPanelUnconnected extends PureComponent
{
}
}
- onInstanceStateChange = (value: unknown) => {
+ onInstanceStateChange = (value: any) => {
this.props.setPanelInstanceState({ key: this.props.stateKey, value });
};
diff --git a/public/app/features/dashboard/dashgrid/LazyLoader.tsx b/public/app/features/dashboard/dashgrid/LazyLoader.tsx
index 2bf951ce4667d..1472acda3d657 100644
--- a/public/app/features/dashboard/dashgrid/LazyLoader.tsx
+++ b/public/app/features/dashboard/dashgrid/LazyLoader.tsx
@@ -1,5 +1,4 @@
import { useId, useRef, useState } from 'react';
-import * as React from 'react';
import { useEffectOnce } from 'react-use';
export interface Props {
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx
new file mode 100644
index 0000000000000..2a727be141fe3
--- /dev/null
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx
@@ -0,0 +1,121 @@
+// import { css, cx } from '@emotion/css';
+// import { FC } from 'react';
+
+// import { DataLink, GrafanaTheme2, PanelData } from '@grafana/data';
+// import { selectors } from '@grafana/e2e-selectors';
+// import { Icon, useStyles2, ClickOutsideWrapper } from '@grafana/ui';
+// import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
+// import { PanelModel } from 'app/features/dashboard/state/PanelModel';
+// import { getPanelLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers';
+// import { StoreState, useSelector } from 'app/types';
+
+// import { PanelHeaderMenuWrapper } from './PanelHeaderMenuWrapper';
+// import { PanelHeaderNotices } from './PanelHeaderNotices';
+// import PanelHeaderCorner from '../../components/PanelEditor/PanelHeaderCorner';
+
+// export interface Props {
+// panel: PanelModel;
+// dashboard: DashboardModel;
+// title?: string;
+// description?: string;
+// links?: DataLink[];
+// error?: string;
+// alertState?: string;
+// isViewing: boolean;
+// isEditing: boolean;
+// data: PanelData;
+// }
+
+// export const PanelHeader: FC = ({ panel, error, isViewing, isEditing, data, alertState, dashboard }) => {
+// const isFnDashboard = useSelector((state: StoreState) => {
+// const {
+// fnGlobalState: { FNDashboard },
+// } = state;
+
+// return FNDashboard;
+// });
+
+// const onCancelQuery = () => panel.getQueryRunner().cancelQuery();
+// const title = panel.getDisplayTitle();
+// const className = cx('panel-header', !(isViewing || isEditing) ? 'grid-drag-handle' : '');
+// const styles = useStyles2(panelStyles);
+
+// return (
+// <>
+//
+//
+//
+//
+// {({ closeMenu, panelMenuOpen }) => {
+// return (
+//
+//
+//
+// {alertState ? (
+//
+// ) : null}
+//
{title}
+// {isFnDashboard
+// ? null
+// : !dashboard.meta.publicDashboardAccessToken && (
+//
+//
+// {panelMenuOpen ? (
+//
+// ) : null}
+//
+// )}
+// {data.request && data.request.timeInfo && (
+//
+// {data.request.timeInfo}
+//
+// )}
+//
+//
+// );
+// }}
+//
+//
+// >
+// );
+// };
+
+// const panelStyles = (theme: GrafanaTheme2) => {
+// return {
+// fnPanelHeader: css`
+// &:hover {
+// background-color: initial !important;
+// cursor: default !important;
+// }
+// `,
+// titleText: css`
+// text-overflow: ellipsis;
+// overflow: hidden;
+// white-space: nowrap;
+// max-width: calc(100% - 38px);
+// cursor: pointer;
+// font-weight: ${theme.typography.fontWeightMedium};
+// font-size: ${theme.typography.body.fontSize};
+// margin: 0;
+
+// &:hover {
+// color: ${theme.colors.text.primary};
+// }
+// .panel-has-alert & {
+// max-width: calc(100% - 54px);
+// }
+// `,
+// };
+// };
diff --git a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
index 7d21b626fa3cd..e6034feb9b124 100644
--- a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
@@ -1,5 +1,6 @@
import { debounce } from 'lodash';
import { PureComponent } from 'react';
+import { connect } from 'react-redux';
import { Subscription } from 'rxjs';
import {
@@ -41,6 +42,7 @@ import { applyFilterFromTable } from 'app/features/variables/adhoc/actions';
import { onUpdatePanelSnapshotData } from 'app/plugins/datasource/grafana/utils';
import { changeSeriesColorConfigFactory } from 'app/plugins/panel/timeseries/overrides/colorSeriesConfigFactory';
import { dispatch } from 'app/store/store';
+import { StoreState } from 'app/types';
import { RenderEvent } from 'app/types/events';
import { deleteAnnotation, saveAnnotation, updateAnnotation } from '../../annotations/api';
@@ -71,6 +73,7 @@ export interface Props {
onInstanceStateChange: (value: unknown) => void;
timezone?: string;
hideMenu?: boolean;
+ isFnDashboard?: boolean;
}
export interface State {
@@ -82,7 +85,7 @@ export interface State {
liveTime?: TimeRange;
}
-export class PanelStateWrapper extends PureComponent {
+export class PanelStateWrapperDisConnected extends PureComponent {
private readonly timeSrv: TimeSrv = getTimeSrv();
private subs = new Subscription();
private eventFilter: EventFilterOptions = { onlyLocal: true };
@@ -555,7 +558,7 @@ export class PanelStateWrapper extends PureComponent {
debouncedSetPanelAttention() {}
render() {
- const { dashboard, panel, width, height, plugin } = this.props;
+ const { dashboard, panel, width, height, plugin, isFnDashboard } = this.props;
const { errorMessage, data } = this.state;
const { transparent } = panel;
const panelChromeProps = getPanelChromeProps({ ...this.props, data });
@@ -590,6 +593,7 @@ export class PanelStateWrapper extends PureComponent {
onFocus={() => this.setPanelAttention()}
onMouseEnter={() => this.setPanelAttention()}
onMouseMove={() => this.debouncedSetPanelAttention()}
+ isFNPanel={isFnDashboard}
>
{(innerWidth, innerHeight) => (
<>
@@ -611,3 +615,11 @@ export class PanelStateWrapper extends PureComponent {
);
}
}
+
+function mapStateToProps() {
+ return (state: StoreState) => ({
+ isFnDashboard: state.fnGlobalState.FNDashboard,
+ });
+}
+
+export const PanelStateWrapper = connect(mapStateToProps)(PanelStateWrapperDisConnected);
diff --git a/public/app/features/dashboard/dashgrid/liveTimer.ts b/public/app/features/dashboard/dashgrid/liveTimer.ts
index fe686e0185d50..8b3866c83abe9 100644
--- a/public/app/features/dashboard/dashgrid/liveTimer.ts
+++ b/public/app/features/dashboard/dashgrid/liveTimer.ts
@@ -2,7 +2,9 @@ import { BehaviorSubject } from 'rxjs';
import { dateMath, dateTime, TimeRange } from '@grafana/data';
-import { PanelStateWrapper } from './PanelStateWrapper';
+import { PanelStateWrapperDisConnected as Wrapper } from './PanelStateWrapper';
+
+type PanelStateWrapper = Wrapper;
// target is 20hz (50ms), but we poll at 100ms to smooth out jitter
const interval = 100;
diff --git a/public/app/features/dashboard/services/DashboardLoaderSrv.ts b/public/app/features/dashboard/services/DashboardLoaderSrv.ts
index ba06819bc6c79..797ccdc3d0d17 100644
--- a/public/app/features/dashboard/services/DashboardLoaderSrv.ts
+++ b/public/app/features/dashboard/services/DashboardLoaderSrv.ts
@@ -7,12 +7,10 @@ import { getBackendSrv, locationService } from '@grafana/runtime';
import { backendSrv } from 'app/core/services/backend_srv';
import impressionSrv from 'app/core/services/impression_srv';
import kbn from 'app/core/utils/kbn';
-import { getDashboardScenePageStateManager } from 'app/features/dashboard-scene/pages/DashboardScenePageStateManager';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { DashboardDTO } from 'app/types';
import { appEvents } from '../../../core/core';
-import { getDashboardAPI } from '../api/dashboard_api';
import { getDashboardSrv } from './DashboardSrv';
import { getDashboardSnapshotSrv } from './SnapshotSrv';
@@ -35,8 +33,7 @@ export class DashboardLoaderSrv {
};
}
- loadDashboard(type: UrlQueryValue, slug: string | undefined, uid: string | undefined): Promise {
- const stateManager = getDashboardScenePageStateManager();
+ loadDashboard(type: UrlQueryValue, slug: any, uid: any, version?: any) {
let promise;
if (type === 'script' && slug) {
@@ -76,15 +73,23 @@ export class DashboardLoaderSrv {
},
};
});
- } else if (uid) {
- const cachedDashboard = stateManager.getDashboardFromCache(uid);
- if (cachedDashboard) {
- return Promise.resolve(cachedDashboard);
- }
-
- promise = getDashboardAPI()
- .getDashboardDTO(uid)
- .then((result) => {
+ } else if (version !== undefined) {
+ promise = backendSrv
+ .getDashboardByUidVersion(uid, version)
+ .then((result: any) => {
+ if (result.meta.isFolder) {
+ appEvents.emit(AppEvents.alertError, ['Dashboard with version not found']);
+ throw new Error('Dashboard with version not found');
+ }
+ return result;
+ })
+ .catch(() => {
+ return this._dashboardLoadFailed('Not found', true);
+ });
+ } else {
+ promise = backendSrv
+ .getDashboardByUid(uid)
+ .then((result: any) => {
if (result.meta.isFolder) {
appEvents.emit(AppEvents.alertError, ['Dashboard not found']);
throw new Error('Dashboard not found');
@@ -96,8 +101,6 @@ export class DashboardLoaderSrv {
dash.dashboard.uid = uid;
return dash;
});
- } else {
- throw new Error('Dashboard uid or slug required');
}
promise.then((result: DashboardDTO) => {
diff --git a/public/app/features/dashboard/state/initDashboard.test.ts b/public/app/features/dashboard/state/initDashboard.test.ts
index d291b62f37921..c4e149ada684a 100644
--- a/public/app/features/dashboard/state/initDashboard.test.ts
+++ b/public/app/features/dashboard/state/initDashboard.test.ts
@@ -274,7 +274,7 @@ describeInitScenario('Initializing new dashboard', (ctx) => {
expect(getTimeSrv().init).toBeCalled();
expect(getDashboardSrv().setCurrent).toBeCalled();
expect(getDashboardQueryRunner().run).toBeCalled();
- expect(ctx.args.keybindingSrv.setupDashboardBindings).toBeCalled();
+ expect(ctx.args.keybindingSrv?.setupDashboardBindings).toBeCalled();
});
});
@@ -409,7 +409,7 @@ describeInitScenario('Initializing existing dashboard', (ctx) => {
expect(getTimeSrv().init).toBeCalled();
expect(getDashboardSrv().setCurrent).toBeCalled();
expect(getDashboardQueryRunner().run).toBeCalled();
- expect(ctx.args.keybindingSrv.setupDashboardBindings).toBeCalled();
+ expect(ctx.args.keybindingSrv?.setupDashboardBindings).toBeCalled();
});
it('Should initialize redux variables if newVariables is enabled', () => {
diff --git a/public/app/features/dashboard/state/initDashboard.ts b/public/app/features/dashboard/state/initDashboard.ts
index 599c4ad2a8be9..ce057cb365f40 100644
--- a/public/app/features/dashboard/state/initDashboard.ts
+++ b/public/app/features/dashboard/state/initDashboard.ts
@@ -37,12 +37,13 @@ export interface InitDashboardArgs {
urlUid?: string;
urlSlug?: string;
urlType?: string;
- urlFolderUid?: string;
+ urlFolderId?: string;
+ version?: number;
panelType?: string;
accessToken?: string;
routeName?: string;
fixUrl: boolean;
- keybindingSrv: KeybindingSrv;
+ keybindingSrv?: KeybindingSrv;
}
async function fetchDashboard(
@@ -84,10 +85,15 @@ async function fetchDashboard(
return dashDTO;
}
case DashboardRoutes.Public: {
- return await dashboardLoaderSrv.loadDashboard('public', args.urlSlug, args.accessToken);
+ return await dashboardLoaderSrv.loadDashboard('public', args.urlSlug, args.accessToken, args.version);
}
case DashboardRoutes.Normal: {
- const dashDTO: DashboardDTO = await dashboardLoaderSrv.loadDashboard(args.urlType, args.urlSlug, args.urlUid);
+ const dashDTO: DashboardDTO = await dashboardLoaderSrv.loadDashboard(
+ args.urlType,
+ args.urlSlug,
+ args.urlUid,
+ args.version
+ );
// only the folder API has information about ancestors
// get parent folder (if it exists) and put it in the store
@@ -120,14 +126,14 @@ async function fetchDashboard(
// only the folder API has information about ancestors
// get parent folder (if it exists) and put it in the store
// this will be used to populate the full breadcrumb trail
- if (args.urlFolderUid) {
- await dispatch(getFolderByUid(args.urlFolderUid));
+ if (args.urlFolderId) {
+ await dispatch(getFolderByUid(args.urlFolderId));
}
- return await buildNewDashboardSaveModel(args.urlFolderUid);
+ return await buildNewDashboardSaveModel(args.urlFolderId);
}
case DashboardRoutes.Path: {
const path = args.urlSlug ?? '';
- return await dashboardLoaderSrv.loadDashboard(DashboardRoutes.Path, path, path);
+ return await dashboardLoaderSrv.loadDashboard(DashboardRoutes.Path, path, path, args.version);
}
default:
throw { message: 'Unknown route ' + args.routeName };
@@ -215,7 +221,7 @@ export function initDashboard(args: InitDashboardArgs): ThunkResult {
}
// init services
- const timeSrv: TimeSrv = getTimeSrv();
+ const timeSrv: TimeSrv = getTimeSrv(); // FN: We might need to return this to main app so that we can render it elsewhere
const dashboardSrv: DashboardSrv = getDashboardSrv();
// legacy srv state, we need this value updated for built-in annotations
@@ -252,9 +258,7 @@ export function initDashboard(args: InitDashboardArgs): ThunkResult {
dashboard.autoFitPanels(window.innerHeight, queryParams.kiosk);
}
- if (!config.publicDashboardAccessToken) {
- args.keybindingSrv.setupDashboardBindings(dashboard);
- }
+ args.keybindingSrv?.setupDashboardBindings(dashboard);
} catch (err) {
if (err instanceof Error) {
dispatch(notifyApp(createErrorNotification('Dashboard init failed', err)));
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx
index efed2c92f06cc..b55ccdbdf7604 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx
@@ -15,7 +15,7 @@
import { css } from '@emotion/css';
import { SpanStatusCode } from '@opentelemetry/api';
import { uniq } from 'lodash';
-import React, { useState, useEffect, memo, useCallback } from 'react';
+import { useState, useEffect, memo, useCallback } from 'react';
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
import { AccessoryButton } from '@grafana/experimental';
diff --git a/public/app/features/plugins/built_in_plugins.ts b/public/app/features/plugins/built_in_plugins.ts
index 562f4da0a8abc..940c1310678d2 100644
--- a/public/app/features/plugins/built_in_plugins.ts
+++ b/public/app/features/plugins/built_in_plugins.ts
@@ -17,39 +17,53 @@ const mixedPlugin = async () =>
await import(/* webpackChunkName: "mixedPlugin" */ 'app/plugins/datasource/mixed/module');
const prometheusPlugin = async () =>
await import(/* webpackChunkName: "prometheusPlugin" */ 'app/plugins/datasource/prometheus/module');
-const mssqlPlugin = async () =>
- await import(/* webpackChunkName: "mssqlPlugin" */ 'app/plugins/datasource/mssql/module');
const alertmanagerPlugin = async () =>
await import(/* webpackChunkName: "alertmanagerPlugin" */ 'app/plugins/datasource/alertmanager/module');
import { config } from '@grafana/runtime';
-import * as alertListPanel from 'app/plugins/panel/alertlist/module';
-import * as annoListPanel from 'app/plugins/panel/annolist/module';
-import * as barChartPanel from 'app/plugins/panel/barchart/module';
-import * as barGaugePanel from 'app/plugins/panel/bargauge/module';
-import * as candlestickPanel from 'app/plugins/panel/candlestick/module';
-import * as dashListPanel from 'app/plugins/panel/dashlist/module';
-import * as dataGridPanel from 'app/plugins/panel/datagrid/module';
-import * as debugPanel from 'app/plugins/panel/debug/module';
-import * as flamegraphPanel from 'app/plugins/panel/flamegraph/module';
-import * as gaugePanel from 'app/plugins/panel/gauge/module';
-import * as gettingStartedPanel from 'app/plugins/panel/gettingstarted/module';
-import * as histogramPanel from 'app/plugins/panel/histogram/module';
-import * as livePanel from 'app/plugins/panel/live/module';
-import * as logsPanel from 'app/plugins/panel/logs/module';
-import * as newsPanel from 'app/plugins/panel/news/module';
-import * as pieChartPanel from 'app/plugins/panel/piechart/module';
-import * as statPanel from 'app/plugins/panel/stat/module';
-import * as stateTimelinePanel from 'app/plugins/panel/state-timeline/module';
-import * as statusHistoryPanel from 'app/plugins/panel/status-history/module';
-import * as tablePanel from 'app/plugins/panel/table/module';
-import * as textPanel from 'app/plugins/panel/text/module';
-import * as timeseriesPanel from 'app/plugins/panel/timeseries/module';
-import * as tracesPanel from 'app/plugins/panel/traces/module';
-import * as trendPanel from 'app/plugins/panel/trend/module';
-import * as welcomeBanner from 'app/plugins/panel/welcome/module';
// Async loaded panels
+const alertListPanel = async () =>
+ await import(/* webpackChunkName: "alertListPanel" */ 'app/plugins/panel/alertlist/module');
+const annoListPanel = async () =>
+ await import(/* webpackChunkName: "annoListPanel" */ 'app/plugins/panel/annolist/module');
+const barChartPanel = async () =>
+ await import(/* webpackChunkName: "barChartPanel" */ 'app/plugins/panel/barchart/module');
+const barGaugePanel = async () =>
+ await import(/* webpackChunkName: "barGaugePanel" */ 'app/plugins/panel/bargauge/module');
+const candlestickPanel = async () =>
+ await import(/* webpackChunkName: "candlestickPanel" */ 'app/plugins/panel/candlestick/module');
+const dashListPanel = async () =>
+ await import(/* webpackChunkName: "dashListPanel" */ 'app/plugins/panel/dashlist/module');
+const dataGridPanel = async () =>
+ await import(/* webpackChunkName: "dataGridPanel" */ 'app/plugins/panel/datagrid/module');
+const debugPanel = async () => await import(/* webpackChunkName: "debugPanel" */ 'app/plugins/panel/debug/module');
+const flamegraphPanel = async () =>
+ await import(/* webpackChunkName: "flamegraphPanel" */ 'app/plugins/panel/flamegraph/module');
+const gaugePanel = async () => await import(/* webpackChunkName: "gaugePanel" */ 'app/plugins/panel/gauge/module');
+const gettingStartedPanel = async () =>
+ await import(/* webpackChunkName: "gettingStartedPanel" */ 'app/plugins/panel/gettingstarted/module');
+const histogramPanel = async () =>
+ await import(/* webpackChunkName: "histogramPanel" */ 'app/plugins/panel/histogram/module');
+const livePanel = async () => await import(/* webpackChunkName: "livePanel" */ 'app/plugins/panel/live/module');
+const logsPanel = async () => await import(/* webpackChunkName: "logsPanel" */ 'app/plugins/panel/logs/module');
+const newsPanel = async () => await import(/* webpackChunkName: "newsPanel" */ 'app/plugins/panel/news/module');
+const pieChartPanel = async () =>
+ await import(/* webpackChunkName: "pieChartPanel" */ 'app/plugins/panel/piechart/module');
+const statPanel = async () => await import(/* webpackChunkName: "statPanel" */ 'app/plugins/panel/stat/module');
+const stateTimelinePanel = async () =>
+ await import(/* webpackChunkName: "stateTimelinePanel" */ 'app/plugins/panel/state-timeline/module');
+const statusHistoryPanel = async () =>
+ await import(/* webpackChunkName: "statusHistoryPanel" */ 'app/plugins/panel/status-history/module');
+const tablePanel = async () => await import(/* webpackChunkName: "tablePanel" */ 'app/plugins/panel/table/module');
+const textPanel = async () => await import(/* webpackChunkName: "textPanel" */ 'app/plugins/panel/text/module');
+const timeseriesPanel = async () =>
+ await import(/* webpackChunkName: "timeseriesPanel" */ 'app/plugins/panel/timeseries/module');
+const tracesPanel = async () => await import(/* webpackChunkName: "tracesPanel" */ 'app/plugins/panel/traces/module');
+const trendPanel = async () => await import(/* webpackChunkName: "trendPanel" */ 'app/plugins/panel/trend/module');
+const welcomeBanner = async () =>
+ await import(/* webpackChunkName: "welcomeBanner" */ 'app/plugins/panel/welcome/module');
+
const geomapPanel = async () => await import(/* webpackChunkName: "geomapPanel" */ 'app/plugins/panel/geomap/module');
const canvasPanel = async () => await import(/* webpackChunkName: "canvasPanel" */ 'app/plugins/panel/canvas/module');
const graphPanel = async () => await import(/* webpackChunkName: "graphPlugin" */ 'app/plugins/panel/graph/module');
@@ -68,6 +82,9 @@ const tableOldPanel = async () =>
const nodeGraph = async () =>
await import(/* webpackChunkName: "nodeGraphPanel" */ 'app/plugins/panel/nodeGraph/module');
+const grafadruidDruidDatasourcePlugin = async () =>
+ await import(/* webpackChunkName: "druidPlugin" */ 'app/plugins/datasource/grafadruid-druid-datasource/module');
+
const builtInPlugins: Record Promise)> = {
// datasources
'core:plugin/graphite': graphitePlugin,
@@ -79,7 +96,6 @@ const builtInPlugins: Record Promise Promise {
- const variableName = var1 || var2 || var3;
- const fmt = fmt2 || fmt3 || format;
- return replace(match, variableName, fieldPath, fmt);
- });
+ return (
+ text?.replace(this.regex, (match, var1, var2, fmt2, var3, fieldPath, fmt3) => {
+ const variableName = var1 || var2 || var3;
+ const fmt = fmt2 || fmt3 || format;
+ return replace(match, variableName, fieldPath, fmt);
+ }) || ''
+ );
}
isAllValue(value: unknown) {
diff --git a/public/app/features/variables/pickers/PickerRenderer.tsx b/public/app/features/variables/pickers/PickerRenderer.tsx
index 0b796f9c02b40..50169aa291e50 100644
--- a/public/app/features/variables/pickers/PickerRenderer.tsx
+++ b/public/app/features/variables/pickers/PickerRenderer.tsx
@@ -1,18 +1,45 @@
-import { PropsWithChildren, ReactElement, useMemo } from 'react';
+// import { css } from '@emotion/css';
+import { CSSProperties, FunctionComponent, PropsWithChildren, ReactElement, useMemo } from 'react';
+// eslint-disable-next-line no-restricted-imports
+import { useSelector } from 'react-redux';
-import { TypedVariableModel, VariableHide } from '@grafana/data';
+import { VariableHide } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
-import { Stack, Tooltip } from '@grafana/ui';
+import { Tooltip } from '@grafana/ui';
+import { FnGlobalState } from 'app/core/reducers/fn-slice';
+import type { StoreState } from 'app/types';
import { variableAdapters } from '../adapters';
-import { VARIABLE_PREFIX } from '../constants';
+import { VariableModel } from '../types';
interface Props {
- variable: TypedVariableModel;
+ variable: VariableModel;
readOnly?: boolean;
}
-export const PickerRenderer = (props: Props) => {
+// not using this style for now.
+// const renderWrapperStyle = css`
+// & button,
+// & span,
+// & label,
+// & input {
+// height: 35px;
+// font-size: 14px;
+// }
+
+// /* Center align filter picker buttons */
+// & button {
+// margin-top: 2px;
+// }
+
+// /* Adhoc filter: Disable green border and make input height similar to others */
+// & div[class*='input-wrapper'] {
+// min-height: 0 !important;
+// box-shadow: none !important;
+// }
+// `;
+
+export const PickerRenderer: FunctionComponent = (props) => {
const PickerToRender = useMemo(() => variableAdapters.get(props.variable.type).picker, [props.variable]);
if (!props.variable) {
@@ -20,44 +47,67 @@ export const PickerRenderer = (props: Props) => {
}
return (
-
+
{props.variable.hide !== VariableHide.hideVariable && PickerToRender && (
-
+
)}
-
+
);
};
+const COMMON_PICKER_LABEL_STYLE: CSSProperties = {
+ border: 'none',
+ fontWeight: 500,
+ fontSize: '14px',
+ padding: '3px 6px',
+ letterSpacing: '0.15px',
+ height: '24px',
+ marginTop: '2px',
+};
+
function PickerLabel({ variable }: PropsWithChildren): ReactElement | null {
const labelOrName = useMemo(() => variable.label || variable.name, [variable]);
+ const { FNDashboard, mode } = useSelector(({ fnGlobalState }) => fnGlobalState);
+
+ const fnLabelStyle = useMemo(
+ () => ({
+ ...COMMON_PICKER_LABEL_STYLE,
+ color: mode === 'light' ? '#2D333E' : '#DBD9D7',
+ }),
+ [mode]
+ );
if (variable.hide !== VariableHide.dontHide) {
return null;
}
+ const fnLabelOrName = FNDashboard ? labelOrName.replace('druid_adhoc_filters', 'ad-hoc') : labelOrName;
- const elementId = VARIABLE_PREFIX + variable.id;
+ const elementId = `var-${variable.id}`;
if (variable.description) {
return (
- {labelOrName}
+ {fnLabelOrName}
);
}
-
return (
- {labelOrName}
+ {fnLabelOrName}
);
}
diff --git a/public/app/fn-app/create-mfe.ts b/public/app/fn-app/create-mfe.ts
new file mode 100644
index 0000000000000..d6661429f88bc
--- /dev/null
+++ b/public/app/fn-app/create-mfe.ts
@@ -0,0 +1,309 @@
+declare let __webpack_public_path__: string;
+
+// This is a path to the public folder without '/build'
+window.__grafana_public_path__ =
+ __webpack_public_path__.substring(0, __webpack_public_path__.lastIndexOf('build/')) || __webpack_public_path__;
+
+import { isNull, merge, noop, pick } from 'lodash';
+import React, { ComponentType } from 'react';
+import { createRoot } from 'react-dom/client';
+
+import { createTheme, GrafanaThemeType } from '@grafana/data';
+import { createColors } from '@grafana/data/src/themes/createColors';
+import { GrafanaTheme2 } from '@grafana/data/src/themes/types';
+import { ThemeChangedEvent } from '@grafana/runtime';
+import { GrafanaBootConfig } from '@grafana/runtime/src/config';
+import { getTheme } from '@grafana/ui';
+import appEvents from 'app/core/app_events';
+import config from 'app/core/config';
+import {
+ FnGlobalState,
+ updatePartialFnStates,
+ updateFnState,
+ INITIAL_FN_STATE,
+ FnPropMappedFromState,
+ fnStateProps,
+} from 'app/core/reducers/fn-slice';
+import { backendSrv } from 'app/core/services/backend_srv';
+import fn_app from 'app/fn_app';
+import { FnLoggerService } from 'app/fn_logger';
+import { dispatch } from 'app/store/store';
+
+import { FNDashboardProps, FailedToMountGrafanaErrorName } from './types';
+
+/**
+ * NOTE:
+ * Qiankun expects Promise. Otherwise warnings are logged and life cycle hooks do not work
+ */
+/* eslint-disable-next-line */
+export declare type LifeCycleFn = (app: any, global: typeof window) => Promise;
+
+/**
+ * NOTE: single-spa and qiankun lifeCycles
+ */
+/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
+export declare type FrameworkLifeCycles = {
+ beforeLoad: LifeCycleFn | LifeCycleFn[];
+ beforeMount: LifeCycleFn | LifeCycleFn[];
+ afterMount: LifeCycleFn | LifeCycleFn[];
+ beforeUnmount: LifeCycleFn | LifeCycleFn[];
+ afterUnmount: LifeCycleFn | LifeCycleFn[];
+ bootstrap: LifeCycleFn | LifeCycleFn[];
+ mount: LifeCycleFn | LifeCycleFn[];
+ unmount: LifeCycleFn | LifeCycleFn[];
+ update: LifeCycleFn | LifeCycleFn[];
+};
+
+type DeepPartial = {
+ [P in keyof T]?: DeepPartial;
+};
+
+class createMfe {
+ private static readonly containerSelector = '#grafanaRoot';
+ private static logger = FnLoggerService;
+
+ mode: FNDashboardProps['mode'];
+ static Component: ComponentType>;
+ constructor(readonly props: FNDashboardProps) {
+ this.mode = props.mode;
+ }
+
+ static getLifeCycles(component: ComponentType>) {
+ const lifeCycles: FrameworkLifeCycles = {
+ bootstrap: this.boot(),
+ mount: this.mountFnApp(component),
+ unmount: this.unMountFnApp(),
+ update: this.updateFnApp(),
+ afterMount: () => Promise.resolve(),
+ beforeMount: () => Promise.resolve(),
+ afterUnmount: () => Promise.resolve(),
+ beforeUnmount: () => Promise.resolve(),
+ beforeLoad: () => Promise.resolve(),
+ };
+
+ return lifeCycles;
+ }
+
+ static create(component: ComponentType>) {
+ return createMfe.getLifeCycles(component);
+ }
+
+ static boot() {
+ return () => fn_app.init();
+ }
+
+ private static toggleTheme = (mode: FNDashboardProps['mode']): GrafanaThemeType.Light | GrafanaThemeType.Dark =>
+ mode === 'dark' ? GrafanaThemeType.Light : GrafanaThemeType.Dark;
+
+ private static get styleSheetLink() {
+ const stylesheetLink = document.createElement('link');
+ stylesheetLink.rel = 'stylesheet';
+
+ return stylesheetLink;
+ }
+
+ private static createGrafanaTheme2(mode: FNDashboardProps['mode']) {
+ config.theme2 = createTheme({
+ colors: {
+ mode,
+ },
+ });
+
+ config.theme2.colors = createColors({ mode });
+
+ config.theme2.v1 = getTheme(mode);
+
+ config.theme2.v1.colors = config.theme.colors;
+
+ return config.theme2;
+ }
+
+ private static getPartialBootConfigWithTheme(theme2: GrafanaTheme2) {
+ const partial: DeepPartial = {
+ theme: theme2.v1,
+ bootData: { user: { lightTheme: theme2.isLight } },
+ };
+
+ return partial;
+ }
+
+ private static mergeBootConfigs(bootConfig: GrafanaBootConfig, partialBootConfig: DeepPartial) {
+ return merge({}, bootConfig, partialBootConfig);
+ }
+
+ private static publishTheme(theme: GrafanaTheme2) {
+ appEvents.publish(new ThemeChangedEvent(theme));
+ }
+
+ // NOTE: based on grafana function: 'toggleTheme'
+ private static removeThemeLinks(modeToBeTurnedOff: GrafanaThemeType.Light | GrafanaThemeType.Dark, timeout?: number) {
+ Array.from(document.getElementsByTagName('link')).forEach(createMfe.removeThemeLink(modeToBeTurnedOff, timeout));
+ }
+
+ private static removeThemeLink(modeToBeTurnedOff: FNDashboardProps['mode'], timeout?: number) {
+ return (link: HTMLLinkElement) => {
+ if (!link.href?.includes(`build/grafana.${modeToBeTurnedOff}`)) {
+ return;
+ }
+
+ if (isNull(timeout)) {
+ link.remove();
+
+ return;
+ }
+
+ // Remove existing link after a 500ms to allow new css to load to avoid flickering
+ // If we add new css at the same time we remove current one the page will be rendered without css
+ // As the new css file is loading
+ setTimeout(link.remove, timeout);
+ };
+ }
+
+ /**
+ * NOTE:
+ * If isRuntimeOnly then the stylesheets of the turned off theme are not removed
+ */
+ private static loadFnTheme = (mode: FNDashboardProps['mode'] = GrafanaThemeType.Light, isRuntimeOnly = false) => {
+ createMfe.logger.info('Trying to load theme.', { mode });
+
+ const grafanaTheme2 = createMfe.createGrafanaTheme2(mode);
+
+ const partialBootConfigWithTheme = createMfe.getPartialBootConfigWithTheme(grafanaTheme2);
+
+ const bootConfigWithTheme = createMfe.mergeBootConfigs(config, partialBootConfigWithTheme);
+
+ createMfe.publishTheme(bootConfigWithTheme.theme2);
+
+ if (isRuntimeOnly) {
+ createMfe.logger.info('Successfully loaded theme', { mode });
+
+ return;
+ }
+
+ createMfe.removeThemeLinks(createMfe.toggleTheme(mode));
+
+ const newCssLink = createMfe.styleSheetLink;
+ newCssLink.href = config.bootData.themePaths[mode];
+ document.body.appendChild(newCssLink);
+
+ createMfe.logger.info('Successfully loaded theme.', { mode });
+ };
+
+ private static getContainer(props: FNDashboardProps) {
+ const parentElement = props.container || document;
+
+ return parentElement.querySelector(createMfe.containerSelector);
+ }
+
+ static mountFnApp(Component: ComponentType>) {
+ const lifeCycleFn: FrameworkLifeCycles['mount'] = (props: FNDashboardProps) => {
+ return new Promise((res, rej) => {
+ try {
+ createMfe.loadFnTheme(props.mode);
+ createMfe.Component = Component;
+
+ const initialState: FnGlobalState = {
+ ...INITIAL_FN_STATE,
+ FNDashboard: true,
+ ...pick(props, ...fnStateProps),
+ };
+
+ createMfe.logger.info('[FN Grafana] Dispatching initial state.', { initialState });
+
+ dispatch(updateFnState(initialState));
+
+ createMfe.renderMfeComponent(props, () => {
+ createMfe.logger.info('Mounted grafana.', { props });
+
+ return res(true);
+ });
+ } catch (err) {
+ const message = `[FN Grafana]: Failed to mount grafana. ${err}`;
+
+ FnLoggerService.info(null, message);
+
+ const fnError = new Error(message);
+
+ const name: FailedToMountGrafanaErrorName = 'FailedToMountGrafana';
+ fnError.name = name;
+
+ return rej(fnError);
+ }
+ });
+ };
+
+ return lifeCycleFn;
+ }
+
+ static unMountFnApp() {
+ const lifeCycleFn: FrameworkLifeCycles['unmount'] = (props: FNDashboardProps) => {
+ const container = createMfe.getContainer(props);
+
+ if (container) {
+ createMfe.logger.info('Trying to unmount grafana...');
+
+ createRoot(container).unmount();
+
+ createMfe.logger.info('Successfully unmounted grafana.');
+ } else {
+ createMfe.logger.error('Failed to unmount grafana. Container does not exist.');
+ }
+
+ backendSrv.cancelAllInFlightRequests();
+
+ return Promise.resolve(!!container);
+ };
+
+ return lifeCycleFn;
+ }
+
+ static updateFnApp() {
+ const lifeCycleFn: FrameworkLifeCycles['update'] = ({ mode, ...other }: FNDashboardProps) => {
+ if (mode) {
+ dispatch(
+ updatePartialFnStates({
+ mode,
+ })
+ );
+
+ createMfe.loadFnTheme(mode);
+ }
+
+ if (other.uid) {
+ createMfe.logger.info('Trying to render dashboard using update: ', { updatedProps: other });
+
+ dispatch(
+ updatePartialFnStates({
+ uid: other.uid,
+ hiddenVariables: other.hiddenVariables,
+ slug: other.slug,
+ version: other.version,
+ queryParams: other.queryParams,
+ controlsContainer: other.controlsContainer,
+ })
+ );
+ }
+
+ // NOTE: The false/true value does not change anything
+ return Promise.resolve(true);
+ };
+
+ return lifeCycleFn;
+ }
+
+ static renderMfeComponent(props: FNDashboardProps, onSuccess = noop) {
+ const container = createMfe.getContainer(props);
+ if (!container) {
+ createMfe.logger.error('Failed to render mfe component. Container does not exist.', { props });
+
+ return;
+ }
+
+ const root = createRoot(container);
+ root.render(React.createElement(createMfe.Component, props));
+ createMfe.logger.info('Created mfe component.', { props, container });
+ onSuccess();
+ }
+}
+
+export { createMfe };
diff --git a/public/app/fn-app/fn-app-provider.tsx b/public/app/fn-app/fn-app-provider.tsx
new file mode 100644
index 0000000000000..04d749ecd15c0
--- /dev/null
+++ b/public/app/fn-app/fn-app-provider.tsx
@@ -0,0 +1,54 @@
+import { useState, useEffect, FC, PropsWithChildren } from 'react';
+import { Provider } from 'react-redux';
+import { BrowserRouter } from 'react-router-dom';
+
+import { config, navigationLogger } from '@grafana/runtime';
+import { ErrorBoundaryAlert, GlobalStyles } from '@grafana/ui';
+import { loadAndInitAngularIfEnabled } from 'app/angular/loadAndInitAngularIfEnabled';
+import { ThemeProvider } from 'app/core/utils/ConfigProvider';
+import { FnLoader } from 'app/features/dashboard/components/DashboardLoading/FnLoader';
+import { FnLoggerService } from 'app/fn_logger';
+import { store } from 'app/store/store';
+
+import { GrafanaContext } from '../core/context/GrafanaContext';
+import app from '../fn_app';
+
+import { FNDashboardProps } from './types';
+
+type FnAppProviderProps = Pick;
+
+export const FnAppProvider: FC> = (props) => {
+ const { children } = props;
+
+ const [ready, setReady] = useState(false);
+ navigationLogger('AppWrapper', false, 'rendering');
+ useEffect(() => {
+ loadAndInitAngularIfEnabled()
+ .then(() => {
+ setReady(true);
+ $('.preloader').remove();
+ })
+ .catch(FnLoggerService.error);
+ }, []);
+
+ if (!store || !ready) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+ <>
+
+ {children}
+ >
+
+
+
+
+
+ );
+};
diff --git a/public/app/fn-app/fn-dashboard-page/fn-dashboard.tsx b/public/app/fn-app/fn-dashboard-page/fn-dashboard.tsx
new file mode 100644
index 0000000000000..031c2858941f7
--- /dev/null
+++ b/public/app/fn-app/fn-dashboard-page/fn-dashboard.tsx
@@ -0,0 +1,65 @@
+import { pick } from 'lodash';
+import { FC, useMemo } from 'react';
+
+import { FnPropMappedFromState, fnPropsMappedFromState } from 'app/core/reducers/fn-slice';
+import { StoreState, useSelector } from 'app/types';
+
+import { FnAppProvider } from '../fn-app-provider';
+import { FNDashboardProps } from '../types';
+import { RenderPortal } from '../utils';
+
+import { RenderFNDashboard } from './render-fn-dashboard';
+
+type FNDashboardComponentProps = Omit;
+
+export const FNDashboard: FC = (props) => {
+ return (
+
+
+
+ );
+};
+
+function mapStateToProps() {
+ return ({ fnGlobalState }: StoreState) => pick(fnGlobalState, ...fnPropsMappedFromState);
+}
+
+export const DashboardPortal: FC = (p) => {
+ const globalFnProps = useSelector(mapStateToProps());
+
+ const props = useMemo(
+ () => ({
+ ...p,
+ ...globalFnProps,
+ }),
+ [p, globalFnProps]
+ );
+
+ const content = useMemo(() => {
+ if (!props.FNDashboard) {
+ return null;
+ }
+
+ const { uid, queryParams = {} } = props;
+
+ if (!uid) {
+ return null;
+ }
+
+ return (
+
+ );
+ }, [props]);
+
+ return (
+
+ {content}
+
+ );
+};
diff --git a/public/app/fn-app/fn-dashboard-page/index.ts b/public/app/fn-app/fn-dashboard-page/index.ts
new file mode 100644
index 0000000000000..95956b40a98c9
--- /dev/null
+++ b/public/app/fn-app/fn-dashboard-page/index.ts
@@ -0,0 +1 @@
+export * from './fn-dashboard';
diff --git a/public/app/fn-app/fn-dashboard-page/render-fn-dashboard.tsx b/public/app/fn-app/fn-dashboard-page/render-fn-dashboard.tsx
new file mode 100644
index 0000000000000..e9dac0f5ce0cf
--- /dev/null
+++ b/public/app/fn-app/fn-dashboard-page/render-fn-dashboard.tsx
@@ -0,0 +1,75 @@
+import { merge, isFunction } from 'lodash';
+import { useEffect, FC, useMemo } from 'react';
+
+import { locationService as locationSrv, HistoryWrapper } from '@grafana/runtime';
+import DashboardPage, { DashboardPageProps } from 'app/features/dashboard/containers/DashboardPage';
+import { DashboardRoutes, StoreState, useSelector } from 'app/types';
+
+import { FNDashboardProps } from '../types';
+
+const locationService = locationSrv as HistoryWrapper;
+
+const DEFAULT_DASHBOARD_PAGE_PROPS: Pick & {
+ match: Pick;
+} = {
+ match: {
+ isExact: true,
+ path: '/d/:uid/:slug?',
+ url: '',
+ },
+ history: {} as DashboardPageProps['history'],
+ route: {
+ routeName: DashboardRoutes.Normal,
+ path: '/d/:uid/:slug?',
+ pageClass: 'page-dashboard',
+ component: DashboardPage,
+ },
+};
+
+export const RenderFNDashboard: FC = (props) => {
+ const { queryParams, controlsContainer, setErrors, hiddenVariables, isLoading } = props;
+
+ const firstError = useSelector((state: StoreState) => {
+ const { appNotifications } = state;
+
+ return Object.values(appNotifications.byId).find(({ severity }) => severity === 'error');
+ });
+
+ /**
+ * NOTE:
+ * Grafana renders notifications in StoredNotifications component.
+ * We do not use this component in FN.
+ * But we would like to propagate grafana's errors to FN.
+ */
+ useEffect(() => {
+ if (!isFunction(setErrors)) {
+ return;
+ }
+
+ setErrors(firstError ? { [firstError.timestamp]: firstError.text } : {});
+ }, [firstError, setErrors]);
+
+ useEffect(() => {
+ locationService.fnPathnameChange(window.location.pathname, queryParams);
+ }, [queryParams]);
+
+ const dashboardPageProps: DashboardPageProps = useMemo(
+ () =>
+ merge({}, DEFAULT_DASHBOARD_PAGE_PROPS, {
+ ...DEFAULT_DASHBOARD_PAGE_PROPS,
+ match: {
+ params: {
+ ...props,
+ },
+ },
+ location: locationService.getLocation(),
+ queryParams,
+ hiddenVariables,
+ controlsContainer,
+ isLoading,
+ }),
+ [controlsContainer, hiddenVariables, isLoading, props, queryParams]
+ );
+
+ return ;
+};
diff --git a/public/app/fn-app/index.tsx b/public/app/fn-app/index.tsx
new file mode 100644
index 0000000000000..09a5b402a42ef
--- /dev/null
+++ b/public/app/fn-app/index.tsx
@@ -0,0 +1,2 @@
+export * from './fn-dashboard-page';
+export * from './create-mfe';
diff --git a/public/app/fn-app/types.ts b/public/app/fn-app/types.ts
new file mode 100644
index 0000000000000..4a1bf55f26909
--- /dev/null
+++ b/public/app/fn-app/types.ts
@@ -0,0 +1,34 @@
+import { ReactNode } from 'react';
+
+import { GrafanaThemeType } from '@grafana/data';
+
+export type FailedToMountGrafanaErrorName = 'FailedToMountGrafana';
+
+export interface GrafanaMicroFrontendState {
+ errors: Map;
+}
+
+export type GrafanaMicroFrontendActions = {
+ setErrors: (errors: GrafanaMicroFrontendState['errors']) => void;
+};
+
+/* eslint-disable-next-line */
+export type AnyObject = {
+ [key in K]: V;
+};
+
+export interface FNDashboardProps {
+ name: string;
+ uid: string;
+ slug: string;
+ version: number;
+ mode: GrafanaThemeType.Dark | GrafanaThemeType.Light;
+ queryParams: Record;
+ fnError?: ReactNode;
+ pageTitle?: string;
+ controlsContainer: string | null;
+ isLoading: (isLoading: boolean) => void;
+ setErrors: (errors?: { [K: number | string]: string }) => void;
+ hiddenVariables: readonly string[];
+ container?: HTMLElement | null;
+}
diff --git a/public/app/fn-app/utils.tsx b/public/app/fn-app/utils.tsx
new file mode 100644
index 0000000000000..44110ffc2fd6e
--- /dev/null
+++ b/public/app/fn-app/utils.tsx
@@ -0,0 +1,16 @@
+import { Portal } from '@mui/material';
+import { FC, PropsWithChildren } from 'react';
+
+export interface RenderPortalProps {
+ ID: string;
+}
+
+export const RenderPortal: FC> = ({ ID, children }) => {
+ const container = document.getElementById(ID);
+
+ if (!container) {
+ return null;
+ }
+
+ return {children} ;
+};
diff --git a/public/app/fn_app.ts b/public/app/fn_app.ts
new file mode 100644
index 0000000000000..88032cd92d251
--- /dev/null
+++ b/public/app/fn_app.ts
@@ -0,0 +1,374 @@
+import 'symbol-observable';
+import 'core-js';
+import 'regenerator-runtime/runtime';
+
+import 'whatwg-fetch'; // fetch polyfill needed for PhantomJs rendering
+import 'file-saver';
+import 'jquery';
+
+import 'app/features/all';
+
+import _ from 'lodash'; // eslint-disable-line lodash/import-scope
+
+import {
+ locationUtil,
+ monacoLanguageRegistry,
+ setLocale,
+ setTimeZoneResolver,
+ setWeekStart,
+ standardEditorsRegistry,
+ standardFieldConfigEditorRegistry,
+ standardTransformersRegistry,
+} from '@grafana/data';
+import {
+ locationService,
+ registerEchoBackend,
+ setBackendSrv,
+ setDataSourceSrv,
+ setEchoSrv,
+ setLocationSrv,
+ setQueryRunnerFactory,
+ setRunRequest,
+ setPluginImportUtils,
+ setPluginExtensionGetter,
+ setAppEvents,
+ setPluginExtensionsHook,
+ setPluginComponentHook,
+ setReturnToPreviousHook,
+ setChromeHeaderHeightHook,
+} from '@grafana/runtime';
+import { setPanelDataErrorView } from '@grafana/runtime/src/components/PanelDataErrorView';
+import { setPanelRenderer } from '@grafana/runtime/src/components/PanelRenderer';
+import { setPluginPage } from '@grafana/runtime/src/components/PluginPage';
+import { getScrollbarWidth } from '@grafana/ui';
+import config, { Settings, updateConfig } from 'app/core/config';
+import { arrayMove } from 'app/core/utils/arrayMove';
+import { getStandardTransformers } from 'app/features/transformers/standardTransformers';
+
+import getDefaultMonacoLanguages from '../lib/monaco-languages';
+
+import appEvents from './core/app_events';
+import { AppChromeService } from './core/components/AppChrome/AppChromeService';
+import { getAllOptionEditors, getAllStandardFieldConfigs } from './core/components/OptionsUI/registry';
+import { PluginPage } from './core/components/Page/PluginPage';
+import { GrafanaContextType, useChromeHeaderHeight, useReturnToPreviousInternal } from './core/context/GrafanaContext';
+import { initializeI18n } from './core/internationalization';
+import { interceptLinkClicks } from './core/navigation/patch/interceptLinkClicks';
+import { NewFrontendAssetsChecker } from './core/services/NewFrontendAssetsChecker';
+import { backendSrv } from './core/services/backend_srv';
+import { contextSrv } from './core/services/context_srv';
+import { Echo } from './core/services/echo/Echo';
+import { reportPerformance } from './core/services/echo/EchoSrv';
+import { PerformanceBackend } from './core/services/echo/backends/PerformanceBackend';
+import { ApplicationInsightsBackend } from './core/services/echo/backends/analytics/ApplicationInsightsBackend';
+// import { GA4EchoBackend } from './core/services/echo/backends/analytics/GA4Backend';
+// import { GAEchoBackend } from './core/services/echo/backends/analytics/GABackend';
+import { RudderstackBackend } from './core/services/echo/backends/analytics/RudderstackBackend';
+import { GrafanaJavascriptAgentBackend } from './core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend';
+import { KeybindingSrv } from './core/services/keybindingSrv';
+import { startMeasure, stopMeasure } from './core/utils/metrics';
+import { initDevFeatures } from './dev';
+import { getTimeSrv } from './features/dashboard/services/TimeSrv';
+// import { initGrafanaLive } from './features/live';
+import { PanelDataErrorView } from './features/panel/components/PanelDataErrorView';
+import { PanelRenderer } from './features/panel/components/PanelRenderer';
+import { DatasourceSrv } from './features/plugins/datasource_srv';
+import { getCoreExtensionConfigurations } from './features/plugins/extensions/getCoreExtensionConfigurations';
+import { createPluginExtensionsGetter } from './features/plugins/extensions/getPluginExtensions';
+import { ReactivePluginExtensionsRegistry } from './features/plugins/extensions/reactivePluginExtensionRegistry';
+import { ExposedComponentsRegistry } from './features/plugins/extensions/registry/ExposedComponentsRegistry';
+import { createUsePluginComponent } from './features/plugins/extensions/usePluginComponent';
+import { createUsePluginExtensions } from './features/plugins/extensions/usePluginExtensions';
+import { importPanelPlugin, syncGetPanelPlugin } from './features/plugins/importPanelPlugin';
+import { preloadPlugins } from './features/plugins/pluginPreloader';
+import { QueryRunner } from './features/query/state/QueryRunner';
+import { runRequest } from './features/query/state/runRequest';
+import { initWindowRuntime } from './features/runtime/init';
+import { initializeScopes } from './features/scopes';
+import { variableAdapters } from './features/variables/adapters';
+import { createAdHocVariableAdapter } from './features/variables/adhoc/adapter';
+import { createConstantVariableAdapter } from './features/variables/constant/adapter';
+import { createCustomVariableAdapter } from './features/variables/custom/adapter';
+import { createDataSourceVariableAdapter } from './features/variables/datasource/adapter';
+import { getVariablesUrlParams } from './features/variables/getAllVariableValuesForUrl';
+import { createIntervalVariableAdapter } from './features/variables/interval/adapter';
+import { setVariableQueryRunner, VariableQueryRunner } from './features/variables/query/VariableQueryRunner';
+import { createQueryVariableAdapter } from './features/variables/query/adapter';
+import { createSystemVariableAdapter } from './features/variables/system/adapter';
+import { createTextBoxVariableAdapter } from './features/variables/textbox/adapter';
+import { configureStore } from './store/configureStore';
+
+// add move to lodash for backward compatabilty with plugins
+// @ts-ignore
+_.move = arrayMove;
+
+// import symlinked extensions
+const extensionsIndex = require.context('.', true, /extensions\/index.ts/);
+const extensionsExports = extensionsIndex.keys().map((key) => {
+ return extensionsIndex(key);
+});
+
+if (process.env.NODE_ENV === 'development') {
+ initDevFeatures();
+}
+
+export class GrafanaApp {
+ context!: GrafanaContextType;
+
+ async init() {
+ try {
+ // Let iframe container know grafana has started loading
+ parent.postMessage('GrafanaAppInit', '*');
+
+ const initI18nPromise = initializeI18n(config.bootData.user.language);
+ initI18nPromise.then(({ language }) => updateConfig({ language }));
+
+ backendSrv.setGrafanaPrefix(true);
+ setBackendSrv(backendSrv);
+ const settings: Settings = await backendSrv.get('/api/frontend/settings');
+
+ config.panels = settings.panels;
+ config.datasources = settings.datasources;
+ config.defaultDatasource = settings.defaultDatasource;
+
+ initEchoSrv();
+ // This needs to be done after the `initEchoSrv` since it is being used under the hood.
+ startMeasure('frontend_app_init');
+ addClassIfNoOverlayScrollbar();
+ setLocale(config.bootData.user.locale);
+ setWeekStart(config.bootData.user.weekStart);
+ setPanelRenderer(PanelRenderer);
+ setPluginPage(PluginPage);
+ setPanelDataErrorView(PanelDataErrorView);
+ setLocationSrv(locationService);
+ setTimeZoneResolver(() => config.bootData.user.timezone);
+ // initGrafanaLive();
+
+ // Expose the app-wide eventbus
+ setAppEvents(appEvents);
+
+ // We must wait for translations to load because some preloaded store state requires translating
+ await initI18nPromise;
+
+ // Important that extension reducers are initialized before store
+ addExtensionReducers();
+ configureStore();
+ initExtensions();
+
+ standardEditorsRegistry.setInit(getAllOptionEditors);
+ standardFieldConfigEditorRegistry.setInit(getAllStandardFieldConfigs);
+ standardTransformersRegistry.setInit(getStandardTransformers);
+ variableAdapters.setInit(() => [
+ createQueryVariableAdapter(),
+ createCustomVariableAdapter(),
+ createTextBoxVariableAdapter(),
+ createConstantVariableAdapter(),
+ createDataSourceVariableAdapter(),
+ createIntervalVariableAdapter(),
+ createAdHocVariableAdapter(),
+ createSystemVariableAdapter(),
+ ]);
+ monacoLanguageRegistry.setInit(getDefaultMonacoLanguages);
+
+ setQueryRunnerFactory(() => new QueryRunner());
+ setVariableQueryRunner(new VariableQueryRunner());
+
+ // Provide runRequest implementation to packages, @grafana/scenes in particular
+ setRunRequest(runRequest);
+
+ // Privide plugin import utils to packages, @grafana/scenes in particular
+ setPluginImportUtils({
+ importPanelPlugin,
+ getPanelPluginFromCache: syncGetPanelPlugin,
+ });
+
+ locationUtil.initialize({
+ config,
+ getTimeRangeForUrl: getTimeSrv().timeRangeForUrl,
+ getVariablesUrlParams: getVariablesUrlParams,
+ });
+
+ // intercept anchor clicks and forward it to custom history instead of relying on browser's history
+ document.addEventListener('click', interceptLinkClicks);
+
+ // Init DataSourceSrv
+ const dataSourceSrv = new DatasourceSrv();
+ dataSourceSrv.init(config.datasources, config.defaultDatasource);
+ setDataSourceSrv(dataSourceSrv);
+ initWindowRuntime();
+
+ // Initialize plugin extensions
+ const extensionsRegistry = new ReactivePluginExtensionsRegistry();
+ extensionsRegistry.register({
+ pluginId: 'grafana',
+ extensionConfigs: getCoreExtensionConfigurations(),
+ exposedComponentConfigs: [],
+ });
+
+ const exposedComponentsRegistry = new ExposedComponentsRegistry();
+
+ // Preload selected app plugins
+ if (contextSrv.user.orgRole !== '') {
+ // The "cloud-home-app" is registering banners once it's loaded, and this can cause a rerender in the AppChrome if it's loaded after the Grafana app init.
+ // TODO: remove the following exception once the issue mentioned above is fixed.
+ const awaitedAppPluginIds = ['cloud-home-app'];
+ const awaitedAppPlugins = Object.values(config.apps).filter((app) => awaitedAppPluginIds.includes(app.id));
+ const appPlugins = Object.values(config.apps).filter((app) => !awaitedAppPluginIds.includes(app.id));
+
+ preloadPlugins(appPlugins, extensionsRegistry, exposedComponentsRegistry);
+ await preloadPlugins(
+ awaitedAppPlugins,
+ extensionsRegistry,
+ exposedComponentsRegistry,
+ 'frontend_awaited_plugins_preload'
+ );
+ }
+
+ setPluginExtensionGetter(createPluginExtensionsGetter(extensionsRegistry));
+ setPluginExtensionsHook(createUsePluginExtensions(extensionsRegistry));
+ setPluginComponentHook(createUsePluginComponent(exposedComponentsRegistry));
+
+ // initialize chrome service
+ const queryParams = locationService.getSearchObject();
+ const chromeService = new AppChromeService();
+ const keybindingsService = new KeybindingSrv(locationService, chromeService);
+ const newAssetsChecker = new NewFrontendAssetsChecker();
+ newAssetsChecker.start();
+
+ // Read initial kiosk mode from url at app startup
+ chromeService.setKioskModeFromUrl(queryParams.kiosk);
+
+ this.context = {
+ backend: backendSrv,
+ location: locationService,
+ chrome: chromeService,
+ keybindings: keybindingsService,
+ config,
+ newAssetsChecker,
+ };
+
+ setReturnToPreviousHook(useReturnToPreviousInternal);
+ setChromeHeaderHeightHook(useChromeHeaderHeight);
+
+ initializeScopes();
+ } catch (error) {
+ console.error('Failed to start Grafana', error);
+ window.__grafana_load_failed();
+ } finally {
+ stopMeasure('frontend_app_init');
+ }
+ }
+}
+
+function addExtensionReducers() {
+ if (extensionsExports.length > 0) {
+ extensionsExports[0].addExtensionReducers();
+ }
+}
+
+function initExtensions() {
+ if (extensionsExports.length > 0) {
+ extensionsExports[0].init();
+ }
+}
+
+function initEchoSrv() {
+ setEchoSrv(new Echo({ debug: process.env.NODE_ENV === 'development' }));
+
+ window.addEventListener('load', (e) => {
+ const loadMetricName = 'frontend_boot_load_time_seconds';
+ // Metrics below are marked in public/views/index.html
+ const jsLoadMetricName = 'frontend_boot_js_done_time_seconds';
+ const cssLoadMetricName = 'frontend_boot_css_time_seconds';
+
+ if (performance) {
+ performance.mark(loadMetricName);
+ reportMetricPerformanceMark('first-paint', 'frontend_boot_', '_time_seconds');
+ reportMetricPerformanceMark('first-contentful-paint', 'frontend_boot_', '_time_seconds');
+ reportMetricPerformanceMark(loadMetricName);
+ reportMetricPerformanceMark(jsLoadMetricName);
+ reportMetricPerformanceMark(cssLoadMetricName);
+ }
+ });
+
+ if (contextSrv.user.orgRole !== '') {
+ registerEchoBackend(new PerformanceBackend({}));
+ }
+
+ if (config.grafanaJavascriptAgent.enabled) {
+ registerEchoBackend(
+ new GrafanaJavascriptAgentBackend({
+ ...config.grafanaJavascriptAgent,
+ app: {
+ version: config.buildInfo.version,
+ environment: config.buildInfo.env,
+ },
+ buildInfo: config.buildInfo,
+ user: {
+ id: String(config.bootData.user?.id),
+ email: config.bootData.user?.email,
+ },
+ })
+ );
+ }
+
+ // if (config.googleAnalyticsId) {
+ // registerEchoBackend(
+ // new GAEchoBackend({
+ // googleAnalyticsId: config.googleAnalyticsId,
+ // })
+ // );
+ // }
+
+ // if (config.googleAnalytics4Id) {
+ // registerEchoBackend(
+ // new GA4EchoBackend({
+ // googleAnalyticsId: config.googleAnalytics4Id,
+ // googleAnalytics4SendManualPageViews: config.googleAnalytics4SendManualPageViews,
+ // })
+ // );
+ // }
+
+ if (config.rudderstackWriteKey && config.rudderstackDataPlaneUrl) {
+ registerEchoBackend(
+ new RudderstackBackend({
+ writeKey: config.rudderstackWriteKey,
+ dataPlaneUrl: config.rudderstackDataPlaneUrl,
+ user: config.bootData.user,
+ sdkUrl: config.rudderstackSdkUrl,
+ configUrl: config.rudderstackConfigUrl,
+ integrationsUrl: config.rudderstackIntegrationsUrl,
+ buildInfo: config.buildInfo,
+ })
+ );
+ }
+
+ if (config.applicationInsightsConnectionString) {
+ registerEchoBackend(
+ new ApplicationInsightsBackend({
+ connectionString: config.applicationInsightsConnectionString,
+ endpointUrl: config.applicationInsightsEndpointUrl,
+ })
+ );
+ }
+}
+
+function addClassIfNoOverlayScrollbar() {
+ if (getScrollbarWidth() > 0) {
+ document.body.classList.add('no-overlay-scrollbar');
+ }
+}
+
+/**
+ * Report when a metric of a given name was marked during the document lifecycle. Works for markers with no duration,
+ * like PerformanceMark or PerformancePaintTiming (e.g. created with performance.mark, or first-contentful-paint)
+ */
+function reportMetricPerformanceMark(metricName: string, prefix = '', suffix = ''): void {
+ const metric = _.first(performance.getEntriesByName(metricName));
+ if (metric) {
+ const metricName = metric.name.replace(/-/g, '_');
+ reportPerformance(`${prefix}${metricName}${suffix}`, Math.round(metric.startTime) / 1000);
+ }
+}
+
+export default new GrafanaApp();
diff --git a/public/app/fn_dashboard.ts b/public/app/fn_dashboard.ts
new file mode 100644
index 0000000000000..360a559c8fbf8
--- /dev/null
+++ b/public/app/fn_dashboard.ts
@@ -0,0 +1,26 @@
+import { config } from '@grafana/runtime';
+
+import { FNDashboard, createMfe } from './fn-app';
+
+config.featureToggles = {
+ ...config.featureToggles,
+ publicDashboards: true,
+};
+interface FnData {
+ themePaths: {
+ light: string;
+ dark: string;
+ };
+}
+
+declare global {
+ interface Window {
+ fnData: FnData;
+ }
+}
+
+// config.isPublicDashboardView = false;
+config.bootData.themePaths = window.fnData.themePaths;
+
+export const { bootstrap, mount, unmount, update, afterMount, afterUnmount, beforeLoad, beforeMount, beforeUnmount } =
+ createMfe.create(FNDashboard);
diff --git a/public/app/fn_logger.ts b/public/app/fn_logger.ts
new file mode 100644
index 0000000000000..edc06d448d853
--- /dev/null
+++ b/public/app/fn_logger.ts
@@ -0,0 +1,9 @@
+import log from 'loglevel';
+
+const SHOULD_LOG = process.env.SHOULD_LOG === 'true';
+
+const FnLoggerService = log.getLogger('[FN Grafana]');
+
+FnLoggerService.setLevel(SHOULD_LOG ? log.levels.DEBUG : log.levels.ERROR);
+
+export { FnLoggerService };
diff --git a/public/app/grafana_index.ts b/public/app/grafana_index.ts
new file mode 100644
index 0000000000000..5b68d3e94fa95
--- /dev/null
+++ b/public/app/grafana_index.ts
@@ -0,0 +1,21 @@
+declare let __webpack_public_path__: string;
+declare let __webpack_nonce__: string;
+
+// Check if we are hosting files on cdn and set webpack public path
+if (window.public_cdn_path) {
+ __webpack_public_path__ = window.public_cdn_path;
+}
+
+// This is a path to the public folder without '/build'
+window.__grafana_public_path__ =
+ __webpack_public_path__.substring(0, __webpack_public_path__.lastIndexOf('build/')) || __webpack_public_path__;
+
+if (window.nonce) {
+ __webpack_nonce__ = window.nonce;
+}
+
+// This is an indication to the window.onLoad failure check that the app bundle has loaded.
+window.__grafana_app_bundle_loaded = true;
+
+import app from './app';
+app.init();
diff --git a/public/app/plugins/datasource/cloudwatch/components/Account.test.tsx b/public/app/plugins/datasource/cloudwatch/components/Account.test.tsx
new file mode 100644
index 0000000000000..c2e420e21b100
--- /dev/null
+++ b/public/app/plugins/datasource/cloudwatch/components/Account.test.tsx
@@ -0,0 +1,64 @@
+import { render, screen } from '@testing-library/react';
+import selectEvent from 'react-select-event';
+
+import { Account } from './Account';
+
+export const AccountOptions = [
+ {
+ value: '123456789',
+ label: 'test-account1',
+ description: '123456789',
+ },
+ {
+ value: '432156789013',
+ label: 'test-account2',
+ description: '432156789013',
+ },
+ {
+ value: '999999999999',
+ label: 'test-account3',
+ description: '999999999999',
+ },
+ {
+ label: 'Template Variables',
+ options: [
+ {
+ value: '$fakeVar',
+ label: '$fakeVar',
+ },
+ ],
+ },
+];
+describe('Account', () => {
+ const props = {
+ accountOptions: AccountOptions,
+ region: 'us-east-2',
+ onChange: jest.fn(),
+ accountId: '123456789012',
+ };
+
+ it('should not render if there are no accounts', async () => {
+ render( );
+ expect(screen.queryByLabelText('Account Selection')).not.toBeInTheDocument();
+ });
+
+ it('should render a selectable field of accounts if there are accounts', async () => {
+ const onChange = jest.fn();
+ render( );
+ expect(screen.getByLabelText('Account Selection')).toBeInTheDocument();
+ await selectEvent.select(screen.getByLabelText('Account Selection'), 'test-account3', { container: document.body });
+ expect(onChange).toBeCalledWith('999999999999');
+ });
+
+ it("should default to 'all' if there is no selection", () => {
+ render( );
+ expect(screen.getByLabelText('Account Selection')).toBeInTheDocument();
+ expect(screen.getByText('All')).toBeInTheDocument();
+ });
+
+ it('should select an uninterpolated template variable if it has been selected', () => {
+ render( );
+ expect(screen.getByLabelText('Account Selection')).toBeInTheDocument();
+ expect(screen.getByText('$fakeVar')).toBeInTheDocument();
+ });
+});
diff --git a/public/app/plugins/datasource/cloudwatch/components/Account.tsx b/public/app/plugins/datasource/cloudwatch/components/Account.tsx
new file mode 100644
index 0000000000000..8078e752db1a1
--- /dev/null
+++ b/public/app/plugins/datasource/cloudwatch/components/Account.tsx
@@ -0,0 +1,54 @@
+import { useMemo } from 'react';
+
+import { SelectableValue } from '@grafana/data';
+import { EditorField } from '@grafana/experimental';
+import { Select } from '@grafana/ui';
+
+export interface Props {
+ onChange: (accountId?: string) => void;
+ accountOptions: Array>;
+ accountId?: string;
+}
+
+export const ALL_ACCOUNTS_OPTION = {
+ label: 'All',
+ value: 'all',
+ description: 'Target all linked accounts',
+};
+
+export function Account({ accountId, onChange, accountOptions }: Props) {
+ const selectedAccountExistsInOptions = useMemo(
+ () =>
+ accountOptions.find((a) => {
+ if (a.options) {
+ const matchingTemplateVar = a.options.find((tempVar: SelectableValue) => {
+ return tempVar.value === accountId;
+ });
+ return matchingTemplateVar;
+ }
+ return a.value === accountId;
+ }),
+ [accountOptions, accountId]
+ );
+
+ if (accountOptions.length === 0) {
+ return null;
+ }
+
+ return (
+
+ {
+ onChange(value);
+ }}
+ />
+
+ );
+}
diff --git a/public/app/plugins/datasource/cloudwatch/tracking.ts b/public/app/plugins/datasource/cloudwatch/tracking.ts
index 3607b3ef99a94..aa3ec58675094 100644
--- a/public/app/plugins/datasource/cloudwatch/tracking.ts
+++ b/public/app/plugins/datasource/cloudwatch/tracking.ts
@@ -116,6 +116,9 @@ export const onDashboardLoadedHandler = ({
e.metrics_queries_with_account_count += +Boolean(
config.featureToggles.cloudWatchCrossAccountQuerying && isMetricSearchBuilder(q) && q.accountId
);
+ e.metrics_queries_with_account_count += +Boolean(
+ config.featureToggles.cloudWatchCrossAccountQuerying && isMetricSearchBuilder(q) && q.accountId
+ );
}
reportInteraction('grafana_ds_cloudwatch_dashboard_loaded', e);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/ConfigEditor.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/ConfigEditor.tsx
new file mode 100644
index 0000000000000..77e7c669b4c2e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/ConfigEditor.tsx
@@ -0,0 +1,136 @@
+import { PureComponent } from 'react';
+
+//import '@emotion/react';
+import { DataSourcePluginOptionsEditorProps, SelectableValue, KeyValue } from '@grafana/data';
+import { TabsBar, Tab, TabContent, IconName } from '@grafana/ui';
+
+import { DruidConnectionSettings } from './configuration/ConnectionSettings';
+import { ConnectionSettingsOptions } from './configuration/ConnectionSettings/types';
+import { DruidQueryDefaultSettings } from './configuration/QuerySettings';
+import { QuerySettingsOptions } from './configuration/QuerySettings/types';
+import { DruidSettings, DruidSecureSettings } from './types';
+
+enum Tabs {
+ Connection,
+ Query,
+}
+
+interface Props extends DataSourcePluginOptionsEditorProps {}
+
+interface State {
+ activeTab: Tabs;
+}
+
+export class ConfigEditor extends PureComponent {
+ state: State = {
+ activeTab: Tabs.Connection,
+ };
+
+ normalizeData = (data: Record, namespaced: boolean, namespace: string): object => {
+ const keyPrefix = namespace + '.';
+ const keys = Object.keys(data).filter((key) => {
+ if (namespaced) {
+ return !key.includes('.');
+ } else {
+ return key.startsWith(keyPrefix);
+ }
+ });
+ if (keys.length === 0) {
+ return {};
+ }
+ return keys
+ .map((key, index) => {
+ let newKey: string = keyPrefix + key;
+ if (!namespaced) {
+ newKey = key.replace(keyPrefix, '');
+ }
+ return { [newKey]: data[key] };
+ })
+ .reduce((acc, item) => {
+ return { ...acc, ...item };
+ });
+ };
+
+ onSelectTab = (item: SelectableValue) => {
+ this.setState({ activeTab: item.value! });
+ };
+
+ onConnectionOptionsChange = (connectionSettingsOptions: ConnectionSettingsOptions) => {
+ const { options, onOptionsChange } = this.props;
+ const { settings, secretSettings, secretSettingsFields, jsonData: connectionJsonData } = connectionSettingsOptions;
+ const connectionSettings = this.normalizeData(settings, true, 'connection');
+ const jsonData = { ...options.jsonData, ...connectionSettings, ...connectionJsonData };
+ const connectionSecretSettings = this.normalizeData(secretSettings, true, 'connection');
+ const secureJsonData = { ...options.secureJsonData, ...connectionSecretSettings };
+ const connectionSecretSettingsFields = this.normalizeData(
+ secretSettingsFields,
+ true,
+ 'connection'
+ ) as KeyValue;
+ const secureJsonFields = { ...options.secureJsonFields, ...connectionSecretSettingsFields };
+ onOptionsChange({ ...options, jsonData, secureJsonData, secureJsonFields });
+ };
+
+ onQueryOptionsChange = (querySettingsOptions: QuerySettingsOptions) => {
+ const { onOptionsChange, options } = this.props;
+ const { settings } = querySettingsOptions;
+ const querySettings = this.normalizeData(settings, true, 'query');
+ const jsonData = { ...options.jsonData, ...querySettings };
+ onOptionsChange({ ...options, jsonData });
+ };
+
+ connectionOptions = (): ConnectionSettingsOptions => {
+ const { jsonData, secureJsonData, secureJsonFields } = this.props.options;
+ return {
+ settings: this.normalizeData(jsonData, false, 'connection'),
+ secretSettings: this.normalizeData(secureJsonData || {}, false, 'connection'),
+ secretSettingsFields: this.normalizeData(secureJsonFields || {}, false, 'connection') as KeyValue,
+ jsonData: { keepCookies: (jsonData as ConnectionSettingsOptions['jsonData'])?.keepCookies || [] },
+ };
+ };
+
+ queryOptions = (): QuerySettingsOptions => {
+ const { jsonData } = this.props.options;
+ return {
+ settings: this.normalizeData(jsonData, false, 'query'),
+ };
+ };
+
+ render() {
+ const connectionOptions = this.connectionOptions();
+ const queryOptions = this.queryOptions();
+
+ const ConnectionTab = {
+ label: 'Connection',
+ value: Tabs.Connection,
+ content: ,
+ icon: 'signal',
+ };
+ const QueryTab = {
+ label: 'Query defaults',
+ value: Tabs.Query,
+ content: ,
+ icon: 'database',
+ };
+
+ const tabs = [ConnectionTab, QueryTab];
+ const { activeTab } = this.state;
+
+ return (
+ <>
+
+ {tabs.map((t) => (
+ this.onSelectTab(t)}
+ icon={t.icon as IconName}
+ />
+ ))}
+
+ {tabs.find((t) => t.value === activeTab)?.content}
+ >
+ );
+ }
+}
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/DruidDataSource.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/DruidDataSource.ts
new file mode 100644
index 0000000000000..336cec3440376
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/DruidDataSource.ts
@@ -0,0 +1,217 @@
+/* eslint-disable */
+import { DataSourceInstanceSettings, MetricFindValue } from '@grafana/data';
+import { DataSourceWithBackend } from '@grafana/runtime';
+import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
+
+import { DruidSettings, DruidQuery } from './types';
+
+const druidVariableRegex = /\"\[\[(\w+)(?::druid:(\w+))?\]\]\"|\"\${(\w+)(?::druid:(\w+))?}\"/g;
+
+interface AdHocFilter {
+ key: string;
+ operator: string;
+ value: string;
+}
+
+export class DruidDataSource extends DataSourceWithBackend {
+ constructor(
+ instanceSettings: DataSourceInstanceSettings,
+ private readonly templateSrv: TemplateSrv = getTemplateSrv()
+ ) {
+ super(instanceSettings);
+ }
+
+ filterQuery(query: DruidQuery) {
+ return !query.hide;
+ }
+
+ applyTemplateVariables(templatedQuery: DruidQuery) {
+ const shouldEnhanceWithAdHocFilters =
+ templatedQuery.datasource && templatedQuery.datasource.type === 'grafadruid-druid-datasource';
+ let template = JSON.stringify({ ...templatedQuery, expr: undefined });
+
+ if (shouldEnhanceWithAdHocFilters) {
+ template = this.enhanceExprWithAdHocFilters(template);
+ }
+
+ template = template.replace(druidVariableRegex, (match, variable1, format1, variable2, format2) => {
+ if (format1 || format2 === 'json') {
+ return '${' + (variable1 || variable2) + ':doublequote}';
+ }
+ return match;
+ });
+
+ let expr = templatedQuery.expr;
+ if (shouldEnhanceWithAdHocFilters) {
+ expr = this.enhanceExprWithAdHocFilters(expr);
+ }
+
+ return { ...JSON.parse(this.templateSrv.replace(template)), expr };
+ }
+
+ enhanceExprWithAdHocFilters(expr: string) {
+ const adhocFilters = this.templateSrv.getAdhocFilters(this.name);
+
+ const exprParsed = JSON.parse(expr);
+
+ const filterMap: Record> = adhocFilters.reduce(
+ (acc, filter: AdHocFilter) => {
+ let operatorKey = filter.operator;
+
+ if (filter.operator === '>' || filter.operator === '<') {
+ operatorKey = '><';
+ }
+
+ if (!acc[operatorKey]) {
+ acc[operatorKey] = {};
+ }
+
+ if (!acc[operatorKey][filter.key]) {
+ acc[operatorKey][filter.key] = [filter];
+ } else {
+ acc[operatorKey][filter.key].push(filter);
+ }
+ return acc;
+ // eslint-disable-next-line
+ },
+ {} as Record>
+ );
+
+ const equalFilterFields = Object.values(filterMap['='] || {}).map(this.getEqualityFilterField);
+ const notEqualFilterFields = Object.values(filterMap['!='] || {}).map(this.getEqualityFilterField);
+ const boundFilterFields = Object.values(filterMap['><'] || {}).map(this.getBoundFilterField);
+ const regexFilterFields = Object.values(filterMap['=~'] || {})
+ .map(this.getRegexFilterField)
+ .flat();
+ const negatedRegexFilterFields = Object.values(filterMap['!~'] || {})
+ .map(this.getRegexFilterField)
+ .flat();
+
+ if (exprParsed.builder && exprParsed.builder.filter) {
+ if (exprParsed.builder.filter.type === 'and') {
+ exprParsed.builder.filter.fields = exprParsed.builder.filter.fields
+ .concat(equalFilterFields)
+ .concat(boundFilterFields)
+ .concat(regexFilterFields);
+
+ if (notEqualFilterFields.length !== 0 || negatedRegexFilterFields.length !== 0) {
+ exprParsed.builder.filter.fields.push({
+ type: 'not',
+ field: {
+ type: 'and',
+ fields: [...notEqualFilterFields, ...negatedRegexFilterFields],
+ },
+ });
+ }
+ }
+ }
+
+ return JSON.stringify(exprParsed);
+ }
+
+ getBoundFilterField = (filters: AdHocFilter[]) => {
+ if (filters.length === 1) {
+ if (Number.isNaN(Number(filters[0].value))) {
+ throw Error(`Bound value should be a number. "${filters[0].value}" is not a number`);
+ }
+ return filters[0].operator === '>'
+ ? this.getBoundFilterObject(filters[0].value, null, filters[0].key)
+ : this.getBoundFilterObject(null, filters[0].value, filters[0].key);
+ } else {
+ const operatorsMap = filters.reduce(
+ (acc, filter) => {
+ if (Number.isNaN(Number(filter.value))) {
+ throw Error(`Bound value should be a number. "${filter.value}" is not a number`);
+ }
+ if (!acc[filter.operator]) {
+ acc[filter.operator] = [Number(filter.value)];
+ } else {
+ acc[filter.operator].push(Number(filter.value));
+ }
+
+ return acc;
+ },
+ {} as Record
+ );
+
+ return this.getBoundFilterObject(
+ operatorsMap['>'] ? String(Math.max(...operatorsMap['>'])) : null,
+ operatorsMap['<'] ? String(Math.min(...operatorsMap['<'])) : null,
+ filters[0].key
+ );
+ }
+ };
+
+ getEqualityFilterField = (filters: AdHocFilter[]) => {
+ if (filters.length === 1) {
+ return {
+ dimension: filters[0].key,
+ type: 'selector',
+ value: filters[0].value,
+ };
+ } else {
+ return {
+ dimension: filters[0].key,
+ type: 'in',
+ values: filters.map((filter) => filter.value),
+ };
+ }
+ };
+
+ getRegexFilterField = (filters: AdHocFilter[]) => {
+ return filters.map((filter) => {
+ return {
+ dimension: filter.key,
+ type: 'regex',
+ pattern: filter.value,
+ };
+ });
+ };
+
+ getBoundFilterObject = (lower: string | null = null, upper: string | null = null, dimension: string) => {
+ return {
+ type: 'bound',
+ dimension,
+ lower: lower,
+ upper: upper,
+ };
+ };
+
+ async metricFindQuery(query: DruidQuery): Promise {
+ return this.postResource('query-variable', this.applyTemplateVariables(query)).then(
+ (response) => {
+ return response;
+ }
+ );
+ }
+
+ async getTagKeys() {
+ const columnNamesSql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'telemetry'";
+ const tagKeysQuery = {
+ builder: {
+ queryType: 'sql',
+ query: columnNamesSql,
+ },
+ settings: {},
+ expr: `{"builder":{"queryType":"sql","query":"${columnNamesSql}","intervals":{"type":"intervals","intervals":["\${__from:date:iso}/\${__to:date:iso}"]}},"settings":{}}`,
+ };
+
+ return this.postResource('query-variable', this.applyTemplateVariables(tagKeysQuery as any));
+ }
+
+ async getTagValues(options: { key?: string } = {}) {
+ const columnValuesSql = `SELECT \"${options.key}\" FROM \"telemetry\" WHERE __time >= '\${__from:date:iso}' AND __time <= '\${__to:date:iso}' GROUP BY 1`;
+ const tagValuesQuery = {
+ builder: {
+ queryType: 'sql',
+ query: columnValuesSql,
+ },
+ settings: {},
+ expr: `{"builder":{"queryType":"sql","query":"${columnValuesSql}","intervals":{"type":"intervals","intervals":["\${__from:date:iso}/\${__to:date:iso}"]}},"settings":{}}`,
+ };
+
+ return this.postResource('query-variable', this.applyTemplateVariables(tagValuesQuery as any));
+ }
+}
+
+/* eslint-enable */
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/QueryEditor.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/QueryEditor.tsx
new file mode 100644
index 0000000000000..bf7bdbada2197
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/QueryEditor.tsx
@@ -0,0 +1,84 @@
+import { css, cx } from '@emotion/css';
+import { useState } from 'react';
+
+import { QueryEditorProps } from '@grafana/data';
+import { ToolbarButtonRow, ToolbarButton, Drawer } from '@grafana/ui';
+
+import { DruidDataSource } from './DruidDataSource';
+import { DruidQueryBuilder } from './builder/';
+import { QueryBuilderOptions } from './builder/types';
+import { DruidQuerySettings } from './configuration/QuerySettings';
+import { QuerySettingsOptions } from './configuration/QuerySettings/types';
+import { DruidSettings, DruidQuery } from './types';
+
+interface Props extends QueryEditorProps {}
+
+export const QueryEditor = (props: Props) => {
+ const { builder, settings } = props.query;
+ const builderOptions = { builder: builder || {}, settings: settings || {} };
+ const settingsOptions = { settings: settings || {} };
+ const onBuilderOptionsChange = (queryBuilderOptions: QueryBuilderOptions) => {
+ const { query, onChange, onRunQuery } = props;
+ //todo: need to implement some kind of hook system to alter a query from modules
+ if (
+ queryBuilderOptions.builder !== null &&
+ (queryBuilderOptions.builder.intervals === undefined ||
+ (Array.isArray(queryBuilderOptions.builder.intervals.intervals) &&
+ queryBuilderOptions.builder.intervals.intervals.length === 0))
+ ) {
+ queryBuilderOptions.builder.intervals = {
+ type: 'intervals',
+ intervals: ['${__from:date:iso}/${__to:date:iso}'],
+ };
+ }
+ //workaround: https://github.com/grafana/grafana/issues/30013
+ const expr = JSON.stringify(queryBuilderOptions);
+ onChange({ ...query, ...queryBuilderOptions, expr: expr });
+ onRunQuery();
+ };
+ const onSettingsOptionsChange = (querySettingsOptions: QuerySettingsOptions) => {
+ const { query, onChange, onRunQuery } = props;
+ //workaround: https://github.com/grafana/grafana/issues/30013
+ const expr = JSON.stringify({ builder: query.builder, ...querySettingsOptions });
+ onChange({ ...query, ...querySettingsOptions, expr: expr });
+ onRunQuery();
+ };
+ const [showDrawer, setShowDrawer] = useState(false);
+ return (
+ <>
+
+ {
+ setShowDrawer(true);
+ event.preventDefault();
+ }}
+ >
+ Query settings
+
+
+ {showDrawer && (
+ {
+ setShowDrawer(false);
+ }}
+ >
+
+
+ )}
+
+ >
+ );
+};
+
+const styles = {
+ toolbar: css`
+ margin-bottom: 4px;
+ `,
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/VariableQueryEditor.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/VariableQueryEditor.tsx
new file mode 100644
index 0000000000000..d998d98f4a22e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/VariableQueryEditor.tsx
@@ -0,0 +1,83 @@
+import { css, cx } from '@emotion/css';
+import { useState } from 'react';
+
+import { ToolbarButtonRow, ToolbarButton, Drawer } from '@grafana/ui';
+
+import { DruidQueryBuilder } from './builder/';
+import { QueryBuilderOptions } from './builder/types';
+import { DruidQuerySettings } from './configuration/QuerySettings';
+import { QuerySettingsOptions } from './configuration/QuerySettings/types';
+import { DruidQuery } from './types';
+
+interface Props {
+ query: DruidQuery;
+ onChange: (query: DruidQuery, definition: string) => void;
+}
+
+export const VariableQueryEditor = (props: Props) => {
+ const { builder, settings } = props.query;
+ const builderOptions = { builder: builder || {}, settings: settings || {} };
+ const settingsOptions = { settings: settings || {} };
+ const onBuilderOptionsChange = (queryBuilderOptions: QueryBuilderOptions) => {
+ const { query, onChange } = props;
+ //todo: need to implement some kind of hook system to alter a query from modules
+ if (
+ queryBuilderOptions.builder !== null &&
+ (queryBuilderOptions.builder.intervals === undefined ||
+ (Array.isArray(queryBuilderOptions.builder.intervals.intervals) &&
+ queryBuilderOptions.builder.intervals.intervals.length === 0))
+ ) {
+ queryBuilderOptions.builder.intervals = {
+ type: 'intervals',
+ intervals: ['${__from:date:iso}/${__to:date:iso}'],
+ };
+ }
+ //workaround: https://github.com/grafana/grafana/issues/30013
+ const expr = JSON.stringify(queryBuilderOptions);
+ onChange({ ...query, ...queryBuilderOptions, expr: expr }, expr);
+ };
+ const onSettingsOptionsChange = (querySettingsOptions: QuerySettingsOptions) => {
+ const { query, onChange } = props;
+ //workaround: https://github.com/grafana/grafana/issues/30013
+ const expr = JSON.stringify({ builder: query.builder, ...querySettingsOptions });
+ onChange({ ...query, ...querySettingsOptions, expr: expr }, expr);
+ };
+ const [showDrawer, setShowDrawer] = useState(false);
+ return (
+ <>
+
+ {
+ setShowDrawer(true);
+ event.preventDefault();
+ }}
+ >
+ Query settings
+
+
+ {showDrawer && (
+ {
+ setShowDrawer(false);
+ }}
+ >
+
+
+ )}
+
+ >
+ );
+};
+
+const styles = {
+ toolbar: css`
+ margin-bottom: 4px;
+ `,
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/DruidQueryBuilder.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/DruidQueryBuilder.tsx
new file mode 100644
index 0000000000000..37cb917cdb4b3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/DruidQueryBuilder.tsx
@@ -0,0 +1,10 @@
+import { debounce } from 'lodash';
+
+import { Query } from './query';
+import { QueryBuilderProps } from './types';
+
+export const DruidQueryBuilder = (props: QueryBuilderProps) => {
+ return (
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Checkbox.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Checkbox.tsx
new file mode 100644
index 0000000000000..851b0ba30d2a7
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Checkbox.tsx
@@ -0,0 +1,30 @@
+import { css, cx } from '@emotion/css';
+import { ChangeEvent } from 'react';
+
+import { Checkbox as CheckboxField } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+
+export const Checkbox = (props: QueryBuilderFieldProps) => {
+ const onChange = (event: ChangeEvent) => {
+ onBuilderChange(props, event.currentTarget.checked);
+ };
+
+ return (
+
+ );
+};
+
+const styles = {
+ checkbox: css`
+ padding-right: 16px;
+ `,
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Code.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Code.tsx
new file mode 100644
index 0000000000000..ba19c253752d9
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Code.tsx
@@ -0,0 +1,47 @@
+import { uniqueId } from 'lodash';
+import AceEditor from 'react-ace';
+
+import { InlineField } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+import 'ace-builds/src-noconflict/mode-javascript';
+import 'ace-builds/src-noconflict/mode-hjson';
+import 'ace-builds/src-noconflict/mode-sql';
+import 'ace-builds/src-noconflict/theme-twilight';
+
+interface Props extends QueryBuilderFieldProps {
+ lang: string;
+}
+
+export const Code = (props: Props) => {
+ const onChange = (value: string) => {
+ onBuilderChange(props, value);
+ };
+ return (
+
+
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/DateInterval.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/DateInterval.tsx
new file mode 100644
index 0000000000000..9f00cfafdfc33
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/DateInterval.tsx
@@ -0,0 +1,127 @@
+import { css, cx, injectGlobal } from '@emotion/css';
+import DatePicker from 'react-datepicker';
+
+import { GrafanaTheme } from '@grafana/data';
+import { InlineLabel, stylesFactory, useTheme } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+
+import 'react-datepicker/dist/react-datepicker.css';
+
+injectGlobal(`
+ .react-datepicker__triangle {
+ display: none;
+ }
+ .react-datepicker-popper {
+ z-index: 1000 !important;
+ }
+`);
+
+interface Props extends QueryBuilderFieldProps {
+ format: string;
+ time: boolean;
+}
+
+const ISO8601DURATIONPATTERN = new RegExp(
+ '([-+]?)P(?:([-+]?[0-9]+)D)?(T(?:([-+]?[0-9]+)H)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)(?:[.,]([0-9]{0,9}))?S)?)?',
+ 'i'
+);
+
+const useInterval = (interval = ''): any => {
+ const intervalPartToDate = (part: string): any => {
+ let date: Date | undefined = undefined;
+ let datePlaceholder: string | undefined = undefined;
+ const d = new Date(part);
+ if (d instanceof Date && !isNaN(d.getFullYear())) {
+ date = d;
+ } else {
+ datePlaceholder = part;
+ }
+ return [date, datePlaceholder, part];
+ };
+ const [start, stop] = interval.split('/');
+ return [...intervalPartToDate(start), ...intervalPartToDate(stop)];
+};
+
+export const DateInterval = (props: Props) => {
+ const [startDate, startDatePlaceholder, intervalStart, stopDate, stopDatePlaceholder, intervalStop] = useInterval(
+ props.options.builder
+ );
+
+ const onStartDateChangeRaw = (event?: React.MouseEvent | React.KeyboardEvent) => {
+ const value = event?.currentTarget?.textContent;
+ if (value && value.indexOf('$') !== -1) {
+ onBuilderChange(props, value + '/' + intervalStop);
+ }
+ };
+ const onStartDateChange = (
+ date: Date | null,
+ event?: React.MouseEvent | React.KeyboardEvent
+ ) => {
+ const value = date?.toISOString();
+ onBuilderChange(props, value + '/' + intervalStop);
+ };
+ const onStopDateChangeRaw = (event?: React.MouseEvent | React.KeyboardEvent) => {
+ const value = event?.currentTarget?.textContent;
+ if (value && (value.indexOf('$') !== -1 || ISO8601DURATIONPATTERN.exec(value) !== null)) {
+ onBuilderChange(props, intervalStart + '/' + value);
+ }
+ };
+ const onStopDateChange = (
+ date: Date | null,
+ event?: React.MouseEvent | React.KeyboardEvent
+ ) => {
+ const value = date?.toISOString();
+ onBuilderChange(props, intervalStart + '/' + value);
+ };
+ const { label, description, format, time } = props;
+ const theme = useTheme();
+ const styles = getStyles(theme);
+ return (
+ <>
+
+ {label}
+
+ Start
+
+ Stop
+
+ >
+ );
+};
+
+const getStyles = stylesFactory((theme: GrafanaTheme) => {
+ return {
+ picker: css`
+ & input {
+ border: 1px solid ${theme.colors.border2};
+ height: 32px;
+ margin-right: 4px;
+ }
+ `,
+ };
+});
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/DateTime.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/DateTime.tsx
new file mode 100644
index 0000000000000..c9b4f931b2a97
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/DateTime.tsx
@@ -0,0 +1,86 @@
+import { css, cx, injectGlobal } from '@emotion/css';
+import DatePicker from 'react-datepicker';
+
+import { GrafanaTheme } from '@grafana/data';
+import { InlineLabel, stylesFactory, useTheme } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+
+import 'react-datepicker/dist/react-datepicker.css';
+
+injectGlobal(`
+ .react-datepicker__triangle {
+ display: none;
+ }
+ .react-datepicker-popper {
+ z-index: 1000 !important;
+ }
+`);
+
+interface Props extends QueryBuilderFieldProps {
+ format: string;
+ time: boolean;
+}
+
+const useDate = (value = ''): any => {
+ let date: Date | undefined = undefined;
+ let datePlaceholder: string | undefined = undefined;
+ const d = new Date(value);
+ if (d instanceof Date && !isNaN(d.getFullYear())) {
+ date = d;
+ } else {
+ datePlaceholder = value;
+ }
+ return [date, datePlaceholder];
+};
+
+export const DateTime = (props: Props) => {
+ const [date, datePlaceholder] = useDate(props.options.builder);
+ const onDateChangeRaw = (event?: React.MouseEvent | React.KeyboardEvent) => {
+ const value = event?.currentTarget?.textContent;
+ if (value && value.indexOf('$') !== -1) {
+ onBuilderChange(props, value);
+ }
+ };
+ const onDateChange = (
+ date: Date | null,
+ event?: React.MouseEvent | React.KeyboardEvent
+ ) => {
+ if (date) {
+ onBuilderChange(props, date.toISOString());
+ }
+ };
+ const { label, description, format, time } = props;
+ const theme = useTheme();
+ const styles = getStyles(theme);
+ return (
+ <>
+
+ {label}
+
+
+ >
+ );
+};
+
+const getStyles = stylesFactory((theme: GrafanaTheme) => {
+ return {
+ picker: css`
+ & input {
+ border: 1px solid ${theme.colors.border2};
+ height: 32px;
+ margin-right: 4px;
+ }
+ `,
+ };
+});
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Input.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Input.tsx
new file mode 100644
index 0000000000000..7f7543e690a43
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Input.tsx
@@ -0,0 +1,33 @@
+import { ChangeEvent } from 'react';
+
+import { Input as InputField, InlineField } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+
+interface Props extends QueryBuilderFieldProps {
+ type: string;
+}
+
+export const Input = (props: Props) => {
+ const onChange = (event: ChangeEvent) => {
+ let value: string | number = event.target.value;
+ if (
+ props.type === 'number' &&
+ !(value.indexOf('$') === 0 || value.indexOf('[') === 0 || value.indexOf('.') === value.length - 1)
+ ) {
+ //must be a number, but is not a variable, nor an incomplete float, so, convert to Number or fallback to previous valid value
+ value = Number(value);
+ if (isNaN(value)) {
+ value = props.options.builder || '';
+ }
+ }
+ onBuilderChange(props, value);
+ };
+ return (
+
+
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/KeyValue.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/KeyValue.tsx
new file mode 100644
index 0000000000000..72139ae83a82e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/KeyValue.tsx
@@ -0,0 +1,35 @@
+import { ChangeEvent } from 'react';
+
+import { Input as InputField, InlineField } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+
+interface Props extends QueryBuilderFieldProps {
+ type?: string;
+}
+
+export const KeyValue = (props: Props) => {
+ const onChange = (event: ChangeEvent) => {
+ let value: string | number = event.target.value;
+ if (
+ props.type === 'number' &&
+ !(value.indexOf('$') === 0 || value.indexOf('[') === 0 || value.indexOf('.') === value.length - 1)
+ ) {
+ //must be a number, but is not a variable, nor an incomplete float, so, convert to Number or fallback to previous valid value
+ value = Number(value);
+ if (isNaN(value)) {
+ value = props.options.builder || '';
+ }
+ }
+ if (value !== props.options.builder) {
+ props.onChange !== undefined ? props.onChange(value) : onBuilderChange(props, value);
+ }
+ };
+ return (
+
+
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Multiple.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Multiple.tsx
new file mode 100644
index 0000000000000..b1d58c5993139
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Multiple.tsx
@@ -0,0 +1,77 @@
+import { ComponentType } from 'react';
+
+import { InlineLabel, Button, Icon } from '@grafana/ui';
+
+import { QueryBuilderOptions } from '../types';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange, Row } from '.';
+
+interface Props extends QueryBuilderFieldProps {
+ component: ComponentType;
+ componentExtraProps: any;
+}
+
+const useProxyBuilder = (props: Props): any => {
+ let proxyBuilder: any = {};
+ const componentBuilder = props.options.builder !== undefined ? props.options.builder : [];
+ componentBuilder.forEach((value: any, index: number) => {
+ proxyBuilder[props.name + '_' + index] = value;
+ });
+ const setBuilderWithProps = (builder: any) => {
+ onBuilderChange(
+ props,
+ Object.entries(builder).map((builderEntry: any) => builderEntry[1])
+ );
+ };
+ return [proxyBuilder, setBuilderWithProps];
+};
+
+export const Multiple = (props: Props) => {
+ const Component = props.component;
+ const [proxyBuilder, setProxyBuilder] = useProxyBuilder(props);
+ const onComponentOptionsChange = (name: string, options: QueryBuilderOptions) => {
+ setProxyBuilder({ ...proxyBuilder, [name]: options.builder });
+ };
+ return (
+ <>
+
+ {props.label}
+
+ {Object.entries(proxyBuilder).map((builderEntry: any, index: number) => (
+
+
+ {
+ setProxyBuilder(
+ Object.fromEntries(Object.entries(proxyBuilder).filter((_: any, i: number) => i !== index))
+ );
+ event.preventDefault();
+ }}
+ >
+
+
+
+ ))}
+ {
+ setProxyBuilder({ ...proxyBuilder, [props.name + '_' + Object.entries(proxyBuilder).length]: undefined });
+ event.preventDefault();
+ }}
+ >
+ Add
+
+ >
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Multiselect.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Multiselect.tsx
new file mode 100644
index 0000000000000..4ca1002ed73af
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Multiselect.tsx
@@ -0,0 +1,35 @@
+import { SelectableValue } from '@grafana/data';
+import { InlineField, MultiSelect as MultiSelectField } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+
+interface Props extends QueryBuilderFieldProps {
+ entries: Record;
+}
+
+export const MultiSelect = (props: Props) => {
+ const onChange = (options: Array>) => {
+ if (null !== options) {
+ onBuilderChange(
+ props,
+ options.map((option) => option.value)
+ );
+ }
+ };
+ const entries = Object.entries(props.entries).map((entry) => {
+ return { value: entry[0], label: String(entry[1]) };
+ });
+ return (
+
+
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/QueryBuilderComponent.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/QueryBuilderComponent.tsx
new file mode 100644
index 0000000000000..7ec69fe87fc3f
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/QueryBuilderComponent.tsx
@@ -0,0 +1,100 @@
+import { cloneDeep } from 'lodash';
+
+import { QueryBuilderProps, QueryBuilderOptions } from '../types';
+
+import { QueryBuilderFieldProps, QueryBuilderComponent, QueryComponent, Component } from './types';
+
+export const enum ScopeType {
+ Builder,
+ Settings,
+}
+
+export const initBuilder = (prevBuilder: any, component: QueryBuilderComponent): any => {
+ let builder: any = {};
+ if ('type' in component) {
+ builder.type = component.type;
+ }
+ if ('queryType' in component) {
+ builder.queryType = component.queryType;
+ }
+ component.fields.forEach((field) => {
+ builder[field] = prevBuilder[field];
+ });
+ return builder;
+};
+
+export const useScopedQueryBuilderProps = (
+ props: QueryBuilderProps,
+ component: QueryBuilderComponent
+) => {
+ const builder = initBuilder(props.options.builder || {}, component);
+ return (name: string | undefined, scopeType: ScopeType = ScopeType.Builder): QueryBuilderProps => {
+ if (name === undefined) {
+ name = '';
+ }
+ let scopedProps = cloneDeep(props);
+ scopedProps.options.builder = name in builder ? builder[name] : undefined;
+ scopedProps.onOptionsChange = (options: QueryBuilderOptions) => {
+ let newBuilder: any = {};
+ if (name === undefined) {
+ name = '';
+ }
+ if (name in builder) {
+ newBuilder = { ...builder, [name]: options.builder };
+ } else {
+ newBuilder = { ...builder, ...options.builder };
+ }
+ let newOptions = { ...options, builder: newBuilder };
+ props.onOptionsChange(newOptions);
+ };
+ return scopedProps;
+ };
+};
+
+export const useScopedQueryBuilderFieldProps = (
+ props: QueryBuilderProps,
+ component: QueryBuilderComponent
+) => {
+ const builder = initBuilder(props.options.builder || {}, component);
+ return (name: string | undefined, scopeType: ScopeType = ScopeType.Builder): QueryBuilderFieldProps => {
+ if (name === undefined) {
+ name = '';
+ }
+ let scopedProps: QueryBuilderFieldProps = { name: name, label: '', description: '', ...cloneDeep(props) };
+ scopedProps.options.builder = name in builder ? builder[name] : undefined;
+ scopedProps.onOptionsChange = (options: QueryBuilderOptions) => {
+ let newBuilder: any = {};
+ if (name === undefined) {
+ name = '';
+ }
+ if (name in builder) {
+ newBuilder = { ...builder, [name]: options.builder };
+ } else {
+ newBuilder = { ...builder, ...options.builder };
+ }
+ let newOptions = { ...options, builder: newBuilder };
+ props.onOptionsChange(newOptions);
+ };
+ return scopedProps;
+ };
+};
+
+export const onBuilderChange = (props: QueryBuilderProps | QueryBuilderFieldProps | undefined, builder: any) => {
+ if (undefined !== props && builder !== props.options.builder) {
+ 'onChange' in props && props.onChange !== undefined
+ ? props.onChange(builder)
+ : props.onOptionsChange({ ...props.options, builder: builder });
+ }
+};
+
+export const useQueryBuilderAutoSubmit = (props: QueryBuilderProps, component: QueryBuilderComponent) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, component);
+ if (
+ props.options.builder === null ||
+ props.options.builder === undefined ||
+ props.options.builder.type !== component.type
+ ) {
+ const { options, onOptionsChange } = scopedProps(undefined);
+ onOptionsChange(options);
+ }
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/QueryBuilderComponentSelector.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/QueryBuilderComponentSelector.tsx
new file mode 100644
index 0000000000000..358af59e546c8
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/QueryBuilderComponentSelector.tsx
@@ -0,0 +1,91 @@
+import { cloneDeep } from 'lodash';
+import { useState } from 'react';
+
+import { SelectableValue } from '@grafana/data';
+import { InlineField, Select } from '@grafana/ui';
+
+import { QueryBuilderProps } from '../types';
+
+import { QueryBuilderComponent, QueryComponent, Component } from './types';
+
+const useComponentsRegistry = (
+ components: Record>
+): Record> => {
+ let registry: Record> = {};
+ for (let key of Object.keys(components)) {
+ registry[key.toLowerCase()] = components[key];
+ }
+ return registry;
+};
+
+const useComponentKey = (
+ builder: any,
+ defaultComponent: QueryBuilderComponent | undefined = undefined
+): string | undefined => {
+ let key = builder !== null && typeof builder === 'object' ? builder.type || builder.queryType : undefined;
+ if (key === undefined && defaultComponent !== undefined) {
+ key =
+ 'type' in defaultComponent
+ ? defaultComponent.type
+ : 'queryType' in defaultComponent
+ ? defaultComponent.queryType
+ : undefined;
+ }
+ if (key !== undefined) {
+ key = key.toLowerCase();
+ }
+ return key;
+};
+
+const useSelectOptions = (
+ components: Record>,
+ selectedComponentKey: string | undefined
+): [SelectableValue | undefined, Array>] => {
+ const options = Object.keys(components).map((key, index) => {
+ return { label: key, value: key.toLowerCase() };
+ });
+ let selectedOption = undefined;
+ if (undefined !== selectedComponentKey) {
+ const selectedOptions = options.filter((option) => option.value === selectedComponentKey.toLowerCase());
+ if (selectedOptions.length > 0) {
+ selectedOption = selectedOptions[0];
+ }
+ }
+ return [selectedOption, options];
+};
+
+export interface QueryBuilderComponentSelectorProps extends QueryBuilderProps {
+ label: string;
+ components: Record>;
+ default?: QueryBuilderComponent | undefined;
+}
+
+export const QueryBuilderComponentSelector = (props: QueryBuilderComponentSelectorProps) => {
+ const { label, components, ...queryBuilderComponentProps } = props;
+ const componentsRegistry = useComponentsRegistry(components);
+ const [selectedComponentKey, selectComponentKey] = useState(
+ useComponentKey(queryBuilderComponentProps.options.builder, props.default)
+ );
+ const [selectedOption, options] = useSelectOptions(components, selectedComponentKey);
+ const onSelection = (selection: SelectableValue) => {
+ let componentKey = undefined;
+ if (null === selection) {
+ let options = cloneDeep(queryBuilderComponentProps.options);
+ options.builder = null;
+ queryBuilderComponentProps.onOptionsChange(options);
+ } else {
+ componentKey = selection.value;
+ }
+ selectComponentKey(componentKey);
+ };
+ const Component = selectedComponentKey === undefined ? undefined : componentsRegistry[selectedComponentKey];
+
+ return (
+ <>
+
+
+
+ {Component && }
+ >
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Row.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Row.tsx
new file mode 100644
index 0000000000000..48022dd11759b
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Row.tsx
@@ -0,0 +1,28 @@
+import { css, cx } from '@emotion/css';
+import { ReactNode } from 'react';
+
+import { GrafanaTheme } from '@grafana/data';
+import { InlineFieldRow, stylesFactory, useTheme } from '@grafana/ui';
+
+interface Props {
+ children: ReactNode | ReactNode[];
+}
+
+export const Row = (props: Props) => {
+ const theme = useTheme();
+ const styles = getStyles(theme);
+ return {props.children} ;
+};
+
+const getStyles = stylesFactory((theme: GrafanaTheme) => {
+ return {
+ row: css`
+ width: 100%;
+ padding-bottom: 5px;
+ & > & {
+ border-left: 1px solid ${theme.colors.border2};
+ padding: 5px 0 5px 10px;
+ }
+ `,
+ };
+});
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Select.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Select.tsx
new file mode 100644
index 0000000000000..d7983b300dded
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Select.tsx
@@ -0,0 +1,40 @@
+import { SelectableValue } from '@grafana/data';
+import { InlineField, Select as SelectField } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+
+interface Props extends QueryBuilderFieldProps {
+ entries: Record;
+}
+
+export const Select = (props: Props) => {
+ const onChange = (option: SelectableValue) => {
+ if (null !== option) {
+ onBuilderChange(props, option.value);
+ }
+ };
+ const entries = Object.entries(props.entries).map((entry) => {
+ return { value: entry[0], label: String(entry[1]) };
+ });
+ const hasCustomValue = entries.filter((entry) => entry.value === props.options.builder).length === 0;
+ if (hasCustomValue) {
+ entries.push({ value: props.options.builder, label: props.options.builder });
+ }
+ return (
+
+ {
+ onChange({ value: v, label: v });
+ }}
+ allowCustomValue
+ isClearable
+ />
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Table.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Table.tsx
new file mode 100644
index 0000000000000..45c1162443916
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/Table.tsx
@@ -0,0 +1,90 @@
+import { uniqueId } from 'lodash';
+import AceEditor from 'react-ace';
+
+import { InlineField } from '@grafana/ui';
+
+import { QueryBuilderFieldProps } from './types';
+
+import { onBuilderChange } from '.';
+import 'ace-builds/src-noconflict/mode-javascript';
+import 'ace-builds/src-noconflict/mode-hjson';
+import 'ace-builds/src-noconflict/mode-sql';
+import 'ace-builds/src-noconflict/theme-terminal';
+
+interface Props extends QueryBuilderFieldProps {
+ namesFieldName: string;
+ typesFieldName: string;
+ rowsFieldName: string;
+}
+
+const encodeInline = (names: string[], types: string[], rows: string[][]): string => {
+ let inline = '';
+ if (undefined !== names && names.length > 0) {
+ for (let i in names) {
+ inline += names[i] + ':' + types[i] + ',';
+ }
+ inline = inline.slice(0, -1) + '\n';
+ for (let row of rows) {
+ for (let col of row) {
+ inline += col + ',';
+ }
+ inline = inline.slice(0, -1) + '\n';
+ }
+ }
+ return inline;
+};
+
+const decodeInline = (inline: string): [string[], string[], string[][]] => {
+ const lines = inline.split('\n');
+ const header = lines[0];
+ const fields = header.split(',');
+ let names = [];
+ let types = [];
+ let rows = [];
+ for (let field of fields) {
+ let name_type = field.split(':');
+ if (name_type[0] !== '' && name_type[1] !== undefined) {
+ names.push(name_type[0]);
+ types.push(name_type[1]);
+ }
+ }
+ for (let line of lines.slice(1)) {
+ rows.push(line.split(','));
+ }
+ return [names, types, rows];
+};
+
+export const Table = (props: Props) => {
+ const onChange = (value: string) => {
+ const [names, types, rows] = decodeInline(value);
+ onBuilderChange(props, { columnNames: names, columnTypes: types, rows: rows });
+ };
+ return (
+
+
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/index.ts
new file mode 100644
index 0000000000000..2dd900a16ede2
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/index.ts
@@ -0,0 +1,19 @@
+export { QueryBuilderComponentSelector } from './QueryBuilderComponentSelector';
+export {
+ useScopedQueryBuilderProps,
+ useScopedQueryBuilderFieldProps,
+ ScopeType,
+ onBuilderChange,
+ useQueryBuilderAutoSubmit,
+} from './QueryBuilderComponent';
+export { Input } from './Input';
+export { Multiple } from './Multiple';
+export { Checkbox } from './Checkbox';
+export { Select } from './Select';
+export { MultiSelect } from './Multiselect';
+export { Code } from './Code';
+export { Table } from './Table';
+export { KeyValue } from './KeyValue';
+export { DateTime } from './DateTime';
+export { DateInterval } from './DateInterval';
+export { Row } from './Row';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/types.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/types.ts
new file mode 100644
index 0000000000000..8136a12ae13bd
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/abstract/types.ts
@@ -0,0 +1,23 @@
+import { ComponentType } from 'react';
+
+import { QueryBuilderProps } from '../types';
+
+export interface QueryBuilderFieldProps extends QueryBuilderProps {
+ name: string;
+ label: string | undefined;
+ description: string;
+ onChange?: (newBuilder: any) => void;
+}
+
+export interface QueryComponent {
+ queryType: string;
+}
+
+export interface Component {
+ type: string;
+}
+
+export type QueryBuilderComponent = ComponentType &
+ Type & {
+ fields: string[];
+ };
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Aggregation.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Aggregation.tsx
new file mode 100644
index 0000000000000..c2ec4b75cf7e8
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Aggregation.tsx
@@ -0,0 +1,76 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import {
+ Cardinality,
+ Count,
+ DoubleAny,
+ DoubleFirst,
+ DoubleLast,
+ DoubleMax,
+ DoubleMean,
+ DoubleMin,
+ DoubleSum,
+ Filtered,
+ FloatAny,
+ FloatFirst,
+ FloatLast,
+ FloatMax,
+ FloatMin,
+ FloatSum,
+ Histogram,
+ HyperUnique,
+ Javascript,
+ LongAny,
+ LongFirst,
+ LongLast,
+ LongMax,
+ LongMin,
+ LongSum,
+ QuantilesDoublesSketch,
+ StringAny,
+ StringFirstFolding,
+ StringFirst,
+ StringLastFolding,
+ StringLast,
+} from './';
+
+export const Aggregation = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Cardinality.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Cardinality.tsx
new file mode 100644
index 0000000000000..9955d84429eaa
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Cardinality.tsx
@@ -0,0 +1,40 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Cardinality = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Cardinality);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Cardinality.type = 'cardinality';
+Cardinality.fields = ['name', 'fields', 'byRow', 'round'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Count.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Count.tsx
new file mode 100644
index 0000000000000..679bd5e5dd575
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Count.tsx
@@ -0,0 +1,13 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Count = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Count);
+ return (
+
+
+
+ );
+};
+Count.type = 'count';
+Count.fields = ['name'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleAny.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleAny.tsx
new file mode 100644
index 0000000000000..781e42b58ae23
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleAny.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const DoubleAny = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleAny);
+ return (
+
+
+
+
+ );
+};
+DoubleAny.type = 'doubleAny';
+DoubleAny.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleFirst.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleFirst.tsx
new file mode 100644
index 0000000000000..aa5f0cfc96002
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleFirst.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const DoubleFirst = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleFirst);
+ return (
+
+
+
+
+ );
+};
+DoubleFirst.type = 'doubleFirst';
+DoubleFirst.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleLast.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleLast.tsx
new file mode 100644
index 0000000000000..d873177056b54
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleLast.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const DoubleLast = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleLast);
+ return (
+
+
+
+
+ );
+};
+DoubleLast.type = 'doubleLast';
+DoubleLast.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMax.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMax.tsx
new file mode 100644
index 0000000000000..d8d696e247d80
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMax.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const DoubleMax = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleMax);
+ return (
+
+
+
+
+
+ );
+};
+DoubleMax.type = 'doubleMax';
+DoubleMax.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMean.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMean.tsx
new file mode 100644
index 0000000000000..9a776b20f9e87
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMean.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const DoubleMean = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleMean);
+ return (
+
+
+
+
+ );
+};
+DoubleMean.type = 'doubleMean';
+DoubleMean.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMin.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMin.tsx
new file mode 100644
index 0000000000000..3a86f8d3c2702
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleMin.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const DoubleMin = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleMin);
+ return (
+
+
+
+
+
+ );
+};
+DoubleMin.type = 'doubleMin';
+DoubleMin.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleSum.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleSum.tsx
new file mode 100644
index 0000000000000..03db09af5ebc8
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/DoubleSum.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const DoubleSum = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleSum);
+ return (
+
+
+
+
+
+ );
+};
+DoubleSum.type = 'doubleSum';
+DoubleSum.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Filtered.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Filtered.tsx
new file mode 100644
index 0000000000000..b492dcab91d07
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Filtered.tsx
@@ -0,0 +1,18 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { Filter } from '../filter';
+import { QueryBuilderProps } from '../types';
+
+import { Aggregation } from './';
+
+export const Filtered = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Filtered);
+ return (
+
+
+
+
+
+ );
+};
+Filtered.type = 'filtered';
+Filtered.fields = ['name', 'filter', 'aggregator'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatAny.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatAny.tsx
new file mode 100644
index 0000000000000..23b0f9e32be9a
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatAny.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FloatAny = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FloatAny);
+ return (
+
+
+
+
+ );
+};
+FloatAny.type = 'floatAny';
+FloatAny.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatFirst.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatFirst.tsx
new file mode 100644
index 0000000000000..b262bd8490f96
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatFirst.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FloatFirst = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FloatFirst);
+ return (
+
+
+
+
+ );
+};
+FloatFirst.type = 'floatFirst';
+FloatFirst.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatLast.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatLast.tsx
new file mode 100644
index 0000000000000..a0b15e4b5d527
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatLast.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FloatLast = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FloatLast);
+ return (
+
+
+
+
+ );
+};
+FloatLast.type = 'floatLast';
+FloatLast.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatMax.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatMax.tsx
new file mode 100644
index 0000000000000..6868adb1008e0
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatMax.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FloatMax = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FloatMax);
+ return (
+
+
+
+
+
+ );
+};
+FloatMax.type = 'floatMax';
+FloatMax.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatMin.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatMin.tsx
new file mode 100644
index 0000000000000..ca73eee15ae50
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatMin.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FloatMin = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FloatMin);
+ return (
+
+
+
+
+
+ );
+};
+FloatMin.type = 'floatMin';
+FloatMin.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatSum.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatSum.tsx
new file mode 100644
index 0000000000000..d4e792bd94cac
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/FloatSum.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FloatSum = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FloatSum);
+ return (
+
+
+
+
+
+ );
+};
+FloatSum.type = 'floatSum';
+FloatSum.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Histogram.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Histogram.tsx
new file mode 100644
index 0000000000000..1abde984a5d82
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Histogram.tsx
@@ -0,0 +1,30 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Histogram = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Histogram);
+ return (
+
+
+
+
+
+ );
+};
+Histogram.type = 'histogram';
+Histogram.fields = ['name', 'fieldName', 'breaks'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/HyperUnique.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/HyperUnique.tsx
new file mode 100644
index 0000000000000..ed75a81063eb6
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/HyperUnique.tsx
@@ -0,0 +1,24 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const HyperUnique = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, HyperUnique);
+ return (
+
+
+
+
+
+ );
+};
+HyperUnique.type = 'hyperUnique';
+HyperUnique.fields = ['name', 'fieldName', 'round'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Javascript.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Javascript.tsx
new file mode 100644
index 0000000000000..1a03f45918670
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/Javascript.tsx
@@ -0,0 +1,44 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Code, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Javascript = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Javascript);
+ return (
+
+
+
+
+
+
+
+ );
+};
+Javascript.type = 'javascript';
+Javascript.fields = ['name', 'fieldNames', 'fnAggregate', 'fnCombine', 'fnReset'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongAny.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongAny.tsx
new file mode 100644
index 0000000000000..061893b485a70
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongAny.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const LongAny = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LongAny);
+ return (
+
+
+
+
+ );
+};
+LongAny.type = 'longAny';
+LongAny.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongFirst.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongFirst.tsx
new file mode 100644
index 0000000000000..13f032032b934
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongFirst.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const LongFirst = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LongFirst);
+ return (
+
+
+
+
+ );
+};
+LongFirst.type = 'longFirst';
+LongFirst.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongLast.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongLast.tsx
new file mode 100644
index 0000000000000..5eacae95d88b0
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongLast.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const LongLast = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LongLast);
+ return (
+
+
+
+
+ );
+};
+LongLast.type = 'count';
+LongLast.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongMax.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongMax.tsx
new file mode 100644
index 0000000000000..b5e1f2ec792b3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongMax.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const LongMax = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LongMax);
+ return (
+
+
+
+
+
+ );
+};
+LongMax.type = 'longMax';
+LongMax.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongMin.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongMin.tsx
new file mode 100644
index 0000000000000..ecf61198fcddc
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongMin.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const LongMin = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LongMin);
+ return (
+
+
+
+
+
+ );
+};
+LongMin.type = 'longMin';
+LongMin.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongSum.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongSum.tsx
new file mode 100644
index 0000000000000..804dc6d24dcaa
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/LongSum.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const LongSum = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LongSum);
+ return (
+
+
+
+
+
+ );
+};
+LongSum.type = 'longSum';
+LongSum.fields = ['name', 'fieldName', 'expression'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/QuantilesDoublesSketch.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/QuantilesDoublesSketch.tsx
new file mode 100644
index 0000000000000..b7c7cba19429c
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/QuantilesDoublesSketch.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const QuantilesDoublesSketch = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, QuantilesDoublesSketch);
+ return (
+
+
+
+
+
+ );
+};
+QuantilesDoublesSketch.type = 'quantilesDoublesSketch';
+QuantilesDoublesSketch.fields = ['name', 'fieldName', 'k'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringAny.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringAny.tsx
new file mode 100644
index 0000000000000..01935858b3418
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringAny.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const StringAny = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, StringAny);
+ return (
+
+
+
+
+
+ );
+};
+StringAny.type = 'stringAny';
+StringAny.fields = ['name', 'fieldName', 'maxStringBytes'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringFirst.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringFirst.tsx
new file mode 100644
index 0000000000000..6c7ce15a7253a
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringFirst.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const StringFirst = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, StringFirst);
+ return (
+
+
+
+
+
+ );
+};
+StringFirst.type = 'stringFirst';
+StringFirst.fields = ['name', 'fieldName', 'maxStringBytes'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringFirstFolding.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringFirstFolding.tsx
new file mode 100644
index 0000000000000..177d163a7adfe
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringFirstFolding.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const StringFirstFolding = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, StringFirstFolding);
+ return (
+
+
+
+
+
+ );
+};
+StringFirstFolding.type = 'stringFirstFolding';
+StringFirstFolding.fields = ['name', 'fieldName', 'maxStringBytes'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringLast.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringLast.tsx
new file mode 100644
index 0000000000000..42b4f1209c1c9
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringLast.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const StringLast = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, StringLast);
+ return (
+
+
+
+
+
+ );
+};
+StringLast.type = 'stringLast';
+StringLast.fields = ['name', 'fieldName', 'maxStringBytes'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringLastFolding.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringLastFolding.tsx
new file mode 100644
index 0000000000000..d7de2df4bc422
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/StringLastFolding.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const StringLastFolding = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, StringLastFolding);
+ return (
+
+
+
+
+
+ );
+};
+StringLastFolding.type = 'stringLastFolding';
+StringLastFolding.fields = ['name', 'fieldName', 'maxStringBytes'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/index.ts
new file mode 100644
index 0000000000000..e5d50ab65aefa
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/aggregation/index.ts
@@ -0,0 +1,32 @@
+export { Aggregation } from './Aggregation';
+export { Cardinality } from './Cardinality';
+export { Count } from './Count';
+export { DoubleAny } from './DoubleAny';
+export { DoubleFirst } from './DoubleFirst';
+export { DoubleLast } from './DoubleLast';
+export { DoubleMax } from './DoubleMax';
+export { DoubleMean } from './DoubleMean';
+export { DoubleMin } from './DoubleMin';
+export { DoubleSum } from './DoubleSum';
+export { Filtered } from './Filtered';
+export { FloatAny } from './FloatAny';
+export { FloatFirst } from './FloatFirst';
+export { FloatLast } from './FloatLast';
+export { FloatMax } from './FloatMax';
+export { FloatMin } from './FloatMin';
+export { FloatSum } from './FloatSum';
+export { Histogram } from './Histogram';
+export { HyperUnique } from './HyperUnique';
+export { Javascript } from './Javascript';
+export { LongAny } from './LongAny';
+export { LongFirst } from './LongFirst';
+export { LongLast } from './LongLast';
+export { LongMax } from './LongMax';
+export { LongMin } from './LongMin';
+export { LongSum } from './LongSum';
+export { QuantilesDoublesSketch } from './QuantilesDoublesSketch';
+export { StringAny } from './StringAny';
+export { StringFirstFolding } from './StringFirstFolding';
+export { StringFirst } from './StringFirst';
+export { StringLastFolding } from './StringLastFolding';
+export { StringLast } from './StringLast';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Bound.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Bound.tsx
new file mode 100644
index 0000000000000..fd6cbe6036647
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Bound.tsx
@@ -0,0 +1,12 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Polygon, Radius, Rectangular } from './';
+
+export const Bound = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Polygon.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Polygon.tsx
new file mode 100644
index 0000000000000..3117c6401d540
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Polygon.tsx
@@ -0,0 +1,24 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Polygon = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Polygon);
+ return (
+
+
+
+
+ );
+};
+Polygon.type = 'polygon';
+Polygon.fields = ['abscissa', 'ordinate'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Radius.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Radius.tsx
new file mode 100644
index 0000000000000..378a6daad96a4
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Radius.tsx
@@ -0,0 +1,28 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Radius = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Radius);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+Radius.type = 'radius';
+Radius.fields = ['coords', 'radius'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Rectangular.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Rectangular.tsx
new file mode 100644
index 0000000000000..08a5a2585fe6a
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/Rectangular.tsx
@@ -0,0 +1,38 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Rectangular = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Rectangular);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+Rectangular.type = 'rectangular';
+Rectangular.fields = ['minCoords', 'maxCoords'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/index.ts
new file mode 100644
index 0000000000000..231023d82e0ef
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/bound/index.ts
@@ -0,0 +1,4 @@
+export { Bound } from './Bound';
+export { Polygon } from './Polygon';
+export { Radius } from './Radius';
+export { Rectangular } from './Rectangular';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/DataSource.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/DataSource.tsx
new file mode 100644
index 0000000000000..319926342377e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/DataSource.tsx
@@ -0,0 +1,20 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { GlobalTable, Inline, Join, Lookup, Query, Table, Union } from './';
+
+export const DataSource = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/GlobalTable.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/GlobalTable.tsx
new file mode 100644
index 0000000000000..3257b18c53baa
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/GlobalTable.tsx
@@ -0,0 +1,13 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const GlobalTable = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, GlobalTable);
+ return (
+
+
+
+ );
+};
+GlobalTable.type = 'globalTable';
+GlobalTable.fields = ['name'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Inline.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Inline.tsx
new file mode 100644
index 0000000000000..3caee9c76511b
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Inline.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Table, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Inline = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Inline);
+ return (
+
+
+
+ );
+};
+Inline.type = 'inline';
+Inline.fields = ['columnNames', 'columnTypes', 'rows'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Join.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Join.tsx
new file mode 100644
index 0000000000000..68afed706fc1c
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Join.tsx
@@ -0,0 +1,41 @@
+import { useScopedQueryBuilderProps, useScopedQueryBuilderFieldProps, Input, Select, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { DataSource } from '.';
+
+export const Join = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Join);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, Join);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Join.type = 'join';
+Join.fields = ['left', 'right', 'rightPrefix', 'condition', 'joinType'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Lookup.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Lookup.tsx
new file mode 100644
index 0000000000000..0f3eab5e73ad2
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Lookup.tsx
@@ -0,0 +1,13 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Lookup = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Lookup);
+ return (
+
+
+
+ );
+};
+Lookup.type = 'lookup';
+Lookup.fields = ['lookup'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Query.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Query.tsx
new file mode 100644
index 0000000000000..3e1b37ea03b5a
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Query.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderProps, Row } from '../abstract';
+import { Query as QuerySelector } from '../query';
+import { QueryBuilderProps } from '../types';
+
+export const Query = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderProps(props, Query);
+ return (
+
+
+
+ );
+};
+Query.type = 'query';
+Query.fields = ['query'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Table.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Table.tsx
new file mode 100644
index 0000000000000..6068d915e5149
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Table.tsx
@@ -0,0 +1,13 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Table = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Table);
+ return (
+
+
+
+ );
+};
+Table.type = 'table';
+Table.fields = ['name'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Union.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Union.tsx
new file mode 100644
index 0000000000000..b9ed736e67a83
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/Union.tsx
@@ -0,0 +1,23 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Union = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Union);
+ return (
+
+
+
+ );
+};
+Union.type = 'union';
+Union.fields = ['dataSources'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/index.ts
new file mode 100644
index 0000000000000..3cfa376037904
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/datasource/index.ts
@@ -0,0 +1,8 @@
+export { DataSource } from './DataSource';
+export { GlobalTable } from './GlobalTable';
+export { Inline } from './Inline';
+export { Join } from './Join';
+export { Lookup } from './Lookup';
+export { Query } from './Query';
+export { Table } from './Table';
+export { Union } from './Union';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Default.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Default.tsx
new file mode 100644
index 0000000000000..1f17a7ed96f98
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Default.tsx
@@ -0,0 +1,25 @@
+import { useScopedQueryBuilderFieldProps, Input, Select, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Default = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Default);
+ return (
+
+
+
+
+
+ );
+};
+Default.type = 'default';
+Default.fields = ['dimension', 'outputName', 'outputType'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Dimension.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Dimension.tsx
new file mode 100644
index 0000000000000..179020f96e01e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Dimension.tsx
@@ -0,0 +1,20 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Default, Extraction, ListFiltered, Lookup, RegisteredLookup, PrefixFiltered, RegexFiltered } from './';
+
+export const Dimension = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Extraction.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Extraction.tsx
new file mode 100644
index 0000000000000..11e414f52ef01
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Extraction.tsx
@@ -0,0 +1,31 @@
+import { useScopedQueryBuilderFieldProps, Input, Select, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+export const Extraction = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Extraction);
+ return (
+ <>
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Extraction.type = 'extraction';
+Extraction.fields = ['dimension', 'outputName', 'outputType', 'extractionFn'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/ListFiltered.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/ListFiltered.tsx
new file mode 100644
index 0000000000000..b262901ab11cf
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/ListFiltered.tsx
@@ -0,0 +1,37 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Dimension } from './Dimension';
+
+export const ListFiltered = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, ListFiltered);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+ListFiltered.type = 'listFiltered';
+ListFiltered.fields = ['delegate', 'values', 'isWhitelist'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Lookup.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Lookup.tsx
new file mode 100644
index 0000000000000..f258605ec4d74
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/Lookup.tsx
@@ -0,0 +1,69 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { Lookup as LookupExtractor } from '../lookup';
+import { QueryBuilderProps } from '../types';
+
+export const Lookup = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Lookup);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Lookup.type = 'lookup';
+Lookup.fields = [
+ 'dimension',
+ 'outputName',
+ 'name',
+ 'lookup',
+ 'retainMissingValue',
+ 'replaceMissingValueWith',
+ 'injective',
+ 'optimize',
+];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/PrefixFiltered.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/PrefixFiltered.tsx
new file mode 100644
index 0000000000000..e07aac37309ef
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/PrefixFiltered.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { Dimension } from '../dimension';
+import { QueryBuilderProps } from '../types';
+
+export const PrefixFiltered = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, PrefixFiltered);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+PrefixFiltered.type = 'prefixFiltered';
+PrefixFiltered.fields = ['delegate', 'prefix'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/RegexFiltered.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/RegexFiltered.tsx
new file mode 100644
index 0000000000000..b7820817bb127
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/RegexFiltered.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { Dimension } from '../dimension';
+import { QueryBuilderProps } from '../types';
+
+export const RegexFiltered = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, RegexFiltered);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+RegexFiltered.type = 'regexFiltered';
+RegexFiltered.fields = ['delegate', 'pattern'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/RegisteredLookup.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/RegisteredLookup.tsx
new file mode 100644
index 0000000000000..a2afdb35c3626
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/RegisteredLookup.tsx
@@ -0,0 +1,59 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const RegisteredLookup = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, RegisteredLookup);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+RegisteredLookup.type = 'registeredLookup';
+RegisteredLookup.fields = [
+ 'dimension',
+ 'outputName',
+ 'lookup',
+ 'retainMissingValue',
+ 'replaceMissingValueWith',
+ 'injective',
+ 'optimize',
+];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/index.ts
new file mode 100644
index 0000000000000..8c19466b61c5c
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/dimension/index.ts
@@ -0,0 +1,8 @@
+export { Default } from './Default';
+export { Dimension } from './Dimension';
+export { Extraction } from './Extraction';
+export { ListFiltered } from './ListFiltered';
+export { Lookup } from './Lookup';
+export { RegisteredLookup } from './RegisteredLookup';
+export { PrefixFiltered } from './PrefixFiltered';
+export { RegexFiltered } from './RegexFiltered';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Bucket.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Bucket.tsx
new file mode 100644
index 0000000000000..0f99564b6f9ce
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Bucket.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Bucket = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Bucket);
+ return (
+
+
+
+
+ );
+};
+Bucket.type = 'bucket';
+Bucket.fields = ['size', 'offset'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Cascade.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Cascade.tsx
new file mode 100644
index 0000000000000..6a753205bfb4a
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Cascade.tsx
@@ -0,0 +1,21 @@
+import { useScopedQueryBuilderFieldProps, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { ExtractionFn } from './';
+
+export const Cascade = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Cascade);
+ return (
+
+
+
+ );
+};
+Cascade.type = 'cascade';
+Cascade.fields = ['extractionFns'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/ExtractionFn.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/ExtractionFn.tsx
new file mode 100644
index 0000000000000..d2ae0202b4f14
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/ExtractionFn.tsx
@@ -0,0 +1,46 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import {
+ Bucket,
+ Cascade,
+ Identity,
+ Javascript,
+ Lookup,
+ Lower,
+ Partial,
+ Regex,
+ RegisteredLookup,
+ SearchQuery,
+ StringFormat,
+ StrLen,
+ Substring,
+ TimeFormat,
+ Time,
+ Upper,
+} from './';
+
+export const ExtractionFn = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Identity.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Identity.tsx
new file mode 100644
index 0000000000000..c7af24fb0a6b7
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Identity.tsx
@@ -0,0 +1,29 @@
+import { useState } from 'react';
+
+import { InfoBox } from '@grafana/ui';
+
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Identity = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, Identity);
+ const [showInfo, setShowInfo] = useState(true);
+ return (
+ <>
+ {showInfo && (
+
+ {
+ setShowInfo(false);
+ }}
+ >
+ Identity. Whatever it does.
+
+
+ )}
+ >
+ );
+};
+Identity.type = 'identity';
+Identity.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Javascript.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Javascript.tsx
new file mode 100644
index 0000000000000..1041466e91656
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Javascript.tsx
@@ -0,0 +1,27 @@
+import { useScopedQueryBuilderFieldProps, Code, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Javascript = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Javascript);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+Javascript.type = 'javascript';
+Javascript.fields = ['function', 'injective'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Lookup.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Lookup.tsx
new file mode 100644
index 0000000000000..7de74988dde59
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Lookup.tsx
@@ -0,0 +1,35 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { Map } from '../lookup';
+import { QueryBuilderProps } from '../types';
+
+export const Lookup = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Lookup);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Lookup.type = 'lookup';
+Lookup.fields = ['lookup', 'retainMissingValue', 'replaceMissingValueWith', 'injective', 'optimize'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Lower.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Lower.tsx
new file mode 100644
index 0000000000000..62f27ea926d60
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Lower.tsx
@@ -0,0 +1,18 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Lower = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Lower);
+ return (
+
+
+
+ );
+};
+Lower.type = 'lower';
+Lower.fields = ['locale'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Partial.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Partial.tsx
new file mode 100644
index 0000000000000..fd38cf87ff4d0
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Partial.tsx
@@ -0,0 +1,13 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Partial = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Partial);
+ return (
+
+
+
+ );
+};
+Partial.type = 'partial';
+Partial.fields = ['expr'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Regex.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Regex.tsx
new file mode 100644
index 0000000000000..696bb3a6c70e6
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Regex.tsx
@@ -0,0 +1,29 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Regex = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Regex);
+ return (
+ <>
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Regex.type = 'regex';
+Regex.fields = ['expr', 'index', 'replaceMissingValue', 'replaceMissingValueWith'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/RegisteredLookup.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/RegisteredLookup.tsx
new file mode 100644
index 0000000000000..e9f479ab945ee
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/RegisteredLookup.tsx
@@ -0,0 +1,36 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const RegisteredLookup = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, RegisteredLookup);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+RegisteredLookup.type = 'registeredLookup';
+RegisteredLookup.fields = ['lookup', 'retainMissingValue', 'replaceMissingValueWith', 'injective', 'optimize'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/SearchQuery.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/SearchQuery.tsx
new file mode 100644
index 0000000000000..34f8b66753fb7
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/SearchQuery.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderProps, Row } from '../abstract';
+import { SearchQuerySpec } from '../searchqueryspec';
+import { QueryBuilderProps } from '../types';
+
+export const SearchQuery = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderProps(props, SearchQuery);
+ return (
+
+
+
+ );
+};
+SearchQuery.type = 'searchQuery';
+SearchQuery.fields = ['query'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/StrLen.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/StrLen.tsx
new file mode 100644
index 0000000000000..605402d07cfa7
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/StrLen.tsx
@@ -0,0 +1,29 @@
+import { useState } from 'react';
+
+import { InfoBox } from '@grafana/ui';
+
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const StrLen = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, StrLen);
+ const [showInfo, setShowInfo] = useState(true);
+ return (
+ <>
+ {showInfo && (
+
+ {
+ setShowInfo(false);
+ }}
+ >
+ Returns the length of dimension values (as if they were encoded in UTF-16)
+
+
+ )}
+ >
+ );
+};
+StrLen.type = 'strlen';
+StrLen.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/StringFormat.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/StringFormat.tsx
new file mode 100644
index 0000000000000..692225ae27b7b
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/StringFormat.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Select, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const StringFormat = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, StringFormat);
+ return (
+
+
+
+
+ );
+};
+StringFormat.type = 'stringFormat';
+StringFormat.fields = ['format', 'nullHandling'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Substring.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Substring.tsx
new file mode 100644
index 0000000000000..8f66ae9d47d69
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Substring.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Substring = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Substring);
+ return (
+
+
+
+
+ );
+};
+Substring.type = 'substring';
+Substring.fields = ['index', 'length'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Time.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Time.tsx
new file mode 100644
index 0000000000000..be50bc868130d
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Time.tsx
@@ -0,0 +1,19 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Time = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Time);
+ return (
+ <>
+
+
+
+
+
+
+
+ >
+ );
+};
+Time.type = 'time';
+Time.fields = ['timeFormat', 'resultFormat', 'joda'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/TimeFormat.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/TimeFormat.tsx
new file mode 100644
index 0000000000000..ac867cd3c2be8
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/TimeFormat.tsx
@@ -0,0 +1,29 @@
+import { useScopedQueryBuilderProps, useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { Granularity } from '../granularity';
+import { QueryBuilderProps } from '../types';
+
+export const TimeFormat = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, TimeFormat);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, TimeFormat);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+TimeFormat.type = 'timeFormat';
+TimeFormat.fields = ['format', 'timeZone', 'locale', 'asMillis', 'granularity'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Upper.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Upper.tsx
new file mode 100644
index 0000000000000..dd28b8c457ffa
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/Upper.tsx
@@ -0,0 +1,18 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Upper = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Upper);
+ return (
+
+
+
+ );
+};
+Upper.type = 'upper';
+Upper.fields = ['locale'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/index.ts
new file mode 100644
index 0000000000000..a41778ca90843
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/extractionfn/index.ts
@@ -0,0 +1,17 @@
+export { Bucket } from './Bucket';
+export { Cascade } from './Cascade';
+export { ExtractionFn } from './ExtractionFn';
+export { Identity } from './Identity';
+export { Javascript } from './Javascript';
+export { Lookup } from './Lookup';
+export { Lower } from './Lower';
+export { Partial } from './Partial';
+export { Regex } from './Regex';
+export { RegisteredLookup } from './RegisteredLookup';
+export { SearchQuery } from './SearchQuery';
+export { StringFormat } from './StringFormat';
+export { StrLen } from './StrLen';
+export { Substring } from './Substring';
+export { TimeFormat } from './TimeFormat';
+export { Time } from './Time';
+export { Upper } from './Upper';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/And.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/And.tsx
new file mode 100644
index 0000000000000..bdc10e10bb612
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/And.tsx
@@ -0,0 +1,21 @@
+import { useScopedQueryBuilderFieldProps, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Filter } from './';
+
+export const And = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, And);
+ return (
+
+
+
+ );
+};
+And.type = 'and';
+And.fields = ['fields'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Bound.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Bound.tsx
new file mode 100644
index 0000000000000..0970377172802
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Bound.tsx
@@ -0,0 +1,63 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Select, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Bound = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Bound);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Bound.type = 'bound';
+Bound.fields = [
+ 'dimension',
+ 'lower',
+ 'lowerStrict',
+ 'upper',
+ 'upperStrict',
+ 'ordering',
+ 'extractionFn',
+ 'filterTuning',
+];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/ColumnComparison.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/ColumnComparison.tsx
new file mode 100644
index 0000000000000..3bc871eb50e82
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/ColumnComparison.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Multiple, Row } from '../abstract';
+import { Dimension } from '../dimension';
+import { QueryBuilderProps } from '../types';
+
+export const ColumnComparison = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, ColumnComparison);
+ return (
+
+
+
+ );
+};
+ColumnComparison.type = 'columnComparison';
+ColumnComparison.fields = ['dimensions'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Expression.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Expression.tsx
new file mode 100644
index 0000000000000..37fab97759fc6
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Expression.tsx
@@ -0,0 +1,20 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Expression = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Expression);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+Expression.type = 'expression';
+Expression.fields = ['expression', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Extraction.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Extraction.tsx
new file mode 100644
index 0000000000000..d89ceb17a0d49
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Extraction.tsx
@@ -0,0 +1,41 @@
+import { useState } from 'react';
+
+import { InfoBox } from '@grafana/ui';
+
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+export const Extraction = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Extraction);
+ const [showInfo, setShowInfo] = useState(true);
+ return (
+ <>
+ {showInfo && (
+
+ {
+ setShowInfo(false);
+ }}
+ >
+
+ The extraction filter is now deprecated. The selector filter with an extraction function specified
+ provides identical functionality and should be used instead.
+
+
+
+ )}
+
+
+
+
+
+
+
+ >
+ );
+};
+Extraction.type = 'extraction';
+Extraction.fields = ['dimension', 'value', 'extractionFn'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/False.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/False.tsx
new file mode 100644
index 0000000000000..848955c793dde
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/False.tsx
@@ -0,0 +1,32 @@
+import { useState } from 'react';
+
+import { InfoBox } from '@grafana/ui';
+
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const False = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, False);
+ const [showInfo, setShowInfo] = useState(true);
+ return (
+ <>
+ {showInfo && (
+
+ {
+ setShowInfo(false);
+ }}
+ >
+
+ The false filter is a filter which matches no value. It can be used to temporarily disable other filters
+ without removing the filter.
+
+
+
+ )}
+ >
+ );
+};
+False.type = 'false';
+False.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Filter.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Filter.tsx
new file mode 100644
index 0000000000000..ff9f6f264720b
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Filter.tsx
@@ -0,0 +1,48 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import {
+ And,
+ Bound,
+ ColumnComparison,
+ Expression,
+ Extraction,
+ False,
+ Interval,
+ In,
+ Javascript,
+ Like,
+ Not,
+ Or,
+ Regex,
+ Search,
+ Selector,
+ Spatial,
+ True,
+} from './';
+
+export const Filter = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/FilterTuning.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/FilterTuning.tsx
new file mode 100644
index 0000000000000..69c54e303caf5
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/FilterTuning.tsx
@@ -0,0 +1,41 @@
+import { InlineLabel } from '@grafana/ui';
+
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FilterTuning = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FilterTuning);
+ return (
+ <>
+
+ Filter tuning
+
+
+
+
+
+
+
+
+ >
+ );
+};
+FilterTuning.type = 'filterTuning';
+FilterTuning.fields = ['minCardinalityToUseBitmapIndex', 'maxCardinalityToUseBitmapIndex', 'useBitmapIndex'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/In.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/In.tsx
new file mode 100644
index 0000000000000..277ed814492d9
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/In.tsx
@@ -0,0 +1,37 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const In = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, In);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+In.type = 'in';
+In.fields = ['dimension', 'values', 'extractionFn', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Interval.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Interval.tsx
new file mode 100644
index 0000000000000..43cb27a54e6e3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Interval.tsx
@@ -0,0 +1,29 @@
+import { useScopedQueryBuilderFieldProps, useScopedQueryBuilderProps, Input, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { Intervals } from '../querysegmentspec';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Interval = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Interval);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, Interval);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Interval.type = 'interval';
+Interval.fields = ['dimension', 'intervals', 'extractionFn', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Javascript.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Javascript.tsx
new file mode 100644
index 0000000000000..e0daebbe26c53
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Javascript.tsx
@@ -0,0 +1,32 @@
+import { useScopedQueryBuilderFieldProps, Input, Code, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Javascript = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Javascript);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Javascript.type = 'javascript';
+Javascript.fields = ['dimension', 'function', 'extractionFn', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Like.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Like.tsx
new file mode 100644
index 0000000000000..e826f359769f4
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Like.tsx
@@ -0,0 +1,36 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Like = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Like);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Like.type = 'like';
+Like.fields = ['dimension', 'pattern', 'escape', 'extractionFn', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Not.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Not.tsx
new file mode 100644
index 0000000000000..0bf5c93d6546c
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Not.tsx
@@ -0,0 +1,15 @@
+import { useScopedQueryBuilderFieldProps, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Filter } from './';
+
+export const Not = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Not);
+ return (
+
+
+
+ );
+};
+Not.type = 'not';
+Not.fields = ['field'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Or.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Or.tsx
new file mode 100644
index 0000000000000..47c138dc773e3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Or.tsx
@@ -0,0 +1,23 @@
+import { useScopedQueryBuilderFieldProps, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Filter } from './';
+
+export const Or = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Or);
+ return (
+ <>
+
+
+
+ >
+ );
+};
+Or.type = 'or';
+Or.fields = ['fields'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Regex.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Regex.tsx
new file mode 100644
index 0000000000000..57740dec9a147
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Regex.tsx
@@ -0,0 +1,25 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Regex = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Regex);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Regex.type = 'regex';
+Regex.fields = ['dimension', 'pattern', 'extractionFn', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Search.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Search.tsx
new file mode 100644
index 0000000000000..b057ae43e7bb4
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Search.tsx
@@ -0,0 +1,28 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { SearchQuerySpec } from '../searchqueryspec';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Search = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Search);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Search.type = 'search';
+Search.fields = ['dimension', 'query', 'extractionFn', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Selector.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Selector.tsx
new file mode 100644
index 0000000000000..55c40b0e5974c
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Selector.tsx
@@ -0,0 +1,25 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Selector = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Selector);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Selector.type = 'selector';
+Selector.fields = ['dimension', 'value', 'extractionFn', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Spatial.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Spatial.tsx
new file mode 100644
index 0000000000000..db3d0b8a29f6f
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/Spatial.tsx
@@ -0,0 +1,28 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { Bound } from '../bound';
+import { ExtractionFn } from '../extractionfn';
+import { QueryBuilderProps } from '../types';
+
+import { FilterTuning } from '.';
+
+export const Spatial = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Spatial);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Spatial.type = 'spatial';
+Spatial.fields = ['dimension', 'bound', 'extractionFn', 'filterTuning'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/True.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/True.tsx
new file mode 100644
index 0000000000000..c3458caf2316e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/True.tsx
@@ -0,0 +1,32 @@
+import { useState } from 'react';
+
+import { InfoBox } from '@grafana/ui';
+
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const True = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, True);
+ const [showInfo, setShowInfo] = useState(true);
+ return (
+ <>
+ {showInfo && (
+
+ {
+ setShowInfo(false);
+ }}
+ >
+
+ The true filter is a filter which matches all values. It can be used to temporarily disable other filters
+ without removing the filter.
+
+
+
+ )}
+ >
+ );
+};
+True.type = 'true';
+True.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/index.ts
new file mode 100644
index 0000000000000..7a06f85aeeade
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/filter/index.ts
@@ -0,0 +1,19 @@
+export { And } from './And';
+export { Bound } from './Bound';
+export { ColumnComparison } from './ColumnComparison';
+export { Expression } from './Expression';
+export { Extraction } from './Extraction';
+export { False } from './False';
+export { Filter } from './Filter';
+export { FilterTuning } from './FilterTuning';
+export { Interval } from './Interval';
+export { In } from './In';
+export { Javascript } from './Javascript';
+export { Like } from './Like';
+export { Not } from './Not';
+export { Or } from './Or';
+export { Regex } from './Regex';
+export { Search } from './Search';
+export { Selector } from './Selector';
+export { Spatial } from './Spatial';
+export { True } from './True';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Duration.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Duration.tsx
new file mode 100644
index 0000000000000..22519c0a7e5df
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Duration.tsx
@@ -0,0 +1,24 @@
+import { useScopedQueryBuilderFieldProps, Input, DateTime, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Duration = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Duration);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+Duration.type = 'duration';
+Duration.fields = ['duration', 'origin'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Granularity.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Granularity.tsx
new file mode 100644
index 0000000000000..b06e3a6b58229
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Granularity.tsx
@@ -0,0 +1,16 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Duration, Period, Simple } from './';
+
+export const Granularity = (props: QueryBuilderProps) => {
+ const defaultComponent = typeof props.options.builder === 'string' ? Simple : undefined;
+ return (
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Period.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Period.tsx
new file mode 100644
index 0000000000000..5d5daecf4f022
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Period.tsx
@@ -0,0 +1,26 @@
+import { useScopedQueryBuilderFieldProps, Input, DateTime, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Period = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Period);
+ return (
+
+
+
+
+
+ );
+};
+Period.type = 'period';
+Period.fields = ['origin', 'period', 'timeZone'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Simple.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Simple.tsx
new file mode 100644
index 0000000000000..9f952aed1c268
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/Simple.tsx
@@ -0,0 +1,33 @@
+import { Select, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Simple = (props: QueryBuilderProps) => {
+ const { options, onOptionsChange } = props;
+ return (
+
+
+
+ );
+};
+Simple.type = 'simple';
+Simple.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/index.ts
new file mode 100644
index 0000000000000..0a2f7dabf5e5f
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/granularity/index.ts
@@ -0,0 +1,4 @@
+export { Duration } from './Duration';
+export { Granularity } from './Granularity';
+export { Period } from './Period';
+export { Simple } from './Simple';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/And.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/And.tsx
new file mode 100644
index 0000000000000..ec642e044c059
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/And.tsx
@@ -0,0 +1,21 @@
+import { useScopedQueryBuilderFieldProps, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { HavingSpec } from './';
+
+export const And = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, And);
+ return (
+
+
+
+ );
+};
+And.type = 'and';
+And.fields = ['havingSpecs'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/DimSelector.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/DimSelector.tsx
new file mode 100644
index 0000000000000..d0ab663dda2b6
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/DimSelector.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const DimSelector = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DimSelector);
+ return (
+
+
+
+
+ );
+};
+DimSelector.type = 'dimSelector';
+DimSelector.fields = ['aggregation', 'value'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/EqualTo.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/EqualTo.tsx
new file mode 100644
index 0000000000000..f42da66064260
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/EqualTo.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const EqualTo = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, EqualTo);
+ return (
+
+
+
+
+ );
+};
+EqualTo.type = 'equalTo';
+EqualTo.fields = ['aggregation', 'value'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Filter.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Filter.tsx
new file mode 100644
index 0000000000000..8fd8f087167f4
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Filter.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Row } from '../abstract';
+import { Filter as FilterField } from '../filter';
+import { QueryBuilderProps } from '../types';
+
+export const Filter = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Filter);
+ return (
+
+
+
+ );
+};
+Filter.type = 'filter';
+Filter.fields = ['filter'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/GreaterThan.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/GreaterThan.tsx
new file mode 100644
index 0000000000000..ff91d5ca4865b
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/GreaterThan.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const GreaterThan = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, GreaterThan);
+ return (
+
+
+
+
+ );
+};
+GreaterThan.type = 'greaterThan';
+GreaterThan.fields = ['aggregation', 'value'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/HavingSpec.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/HavingSpec.tsx
new file mode 100644
index 0000000000000..db47275696ef3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/HavingSpec.tsx
@@ -0,0 +1,21 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { And, DimSelector, EqualTo, Filter, GreaterThan, LessThan, Not, Or } from './';
+
+export const HavingSpec = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/LessThan.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/LessThan.tsx
new file mode 100644
index 0000000000000..8a6c0ec69d5c5
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/LessThan.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const LessThan = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LessThan);
+ return (
+
+
+
+
+ );
+};
+LessThan.type = 'lessThan';
+LessThan.fields = ['aggregation', 'value'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Not.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Not.tsx
new file mode 100644
index 0000000000000..fd7e0caee00d9
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Not.tsx
@@ -0,0 +1,15 @@
+import { useScopedQueryBuilderFieldProps, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { HavingSpec } from './';
+
+export const Not = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Not);
+ return (
+
+
+
+ );
+};
+Not.type = 'not';
+Not.fields = ['havingSpec'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Or.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Or.tsx
new file mode 100644
index 0000000000000..34545f18f9133
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/Or.tsx
@@ -0,0 +1,21 @@
+import { useScopedQueryBuilderFieldProps, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { HavingSpec } from './';
+
+export const Or = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Or);
+ return (
+
+
+
+ );
+};
+Or.type = 'or';
+Or.fields = ['havingSpecs'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/index.ts
new file mode 100644
index 0000000000000..b9399e41c42f6
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/havingspec/index.ts
@@ -0,0 +1,9 @@
+export { And } from './And';
+export { DimSelector } from './DimSelector';
+export { EqualTo } from './EqualTo';
+export { Filter } from './Filter';
+export { GreaterThan } from './GreaterThan';
+export { HavingSpec } from './HavingSpec';
+export { LessThan } from './LessThan';
+export { Not } from './Not';
+export { Or } from './Or';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/index.ts
new file mode 100644
index 0000000000000..8418bac8b17c7
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/index.ts
@@ -0,0 +1 @@
+export { DruidQueryBuilder } from './DruidQueryBuilder';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/Default.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/Default.tsx
new file mode 100644
index 0000000000000..b6dae727f0ac4
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/Default.tsx
@@ -0,0 +1,31 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { OrderByColumnSpecs } from '.';
+
+export const Default = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Default);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+Default.type = 'default';
+Default.fields = ['limit', 'columns'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/LimitSpec.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/LimitSpec.tsx
new file mode 100644
index 0000000000000..977001c6490a3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/LimitSpec.tsx
@@ -0,0 +1,8 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Default } from './';
+
+export const LimitSpec = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/OrderByColumnSpecs.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/OrderByColumnSpecs.tsx
new file mode 100644
index 0000000000000..591e2459ca323
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/OrderByColumnSpecs.tsx
@@ -0,0 +1,34 @@
+import { useScopedQueryBuilderFieldProps, Input, Select, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const OrderByColumnSpecs = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, OrderByColumnSpecs);
+ return (
+
+
+
+
+
+ );
+};
+OrderByColumnSpecs.type = '';
+OrderByColumnSpecs.fields = ['direction', 'dimensionOrder'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/index.ts
new file mode 100644
index 0000000000000..ed99129793202
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/limitspec/index.ts
@@ -0,0 +1,3 @@
+export { Default } from './Default';
+export { OrderByColumnSpecs } from './OrderByColumnSpecs';
+export { LimitSpec } from './LimitSpec';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/Lookup.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/Lookup.tsx
new file mode 100644
index 0000000000000..7b6b490950c46
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/Lookup.tsx
@@ -0,0 +1,8 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Map } from './';
+
+export const Lookup = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/Map.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/Map.tsx
new file mode 100644
index 0000000000000..8f4211d226990
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/Map.tsx
@@ -0,0 +1,18 @@
+import { useScopedQueryBuilderFieldProps, KeyValue, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Map = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Map);
+ return (
+
+
+
+
+ );
+};
+Map.type = 'map';
+Map.fields = ['map', 'isOneToOne'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/index.ts
new file mode 100644
index 0000000000000..c6e30bf0b815e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/lookup/index.ts
@@ -0,0 +1,2 @@
+export { Lookup } from './Lookup';
+export { Map } from './Map';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Arithmetic.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Arithmetic.tsx
new file mode 100644
index 0000000000000..acb5aa99e1be3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Arithmetic.tsx
@@ -0,0 +1,49 @@
+import { useScopedQueryBuilderFieldProps, Input, Select, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { PostAggregation } from './.';
+
+export const Arithmetic = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Arithmetic);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Arithmetic.type = 'arithmetic';
+Arithmetic.fields = ['name', 'fn', 'fields', 'ordering'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Constant.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Constant.tsx
new file mode 100644
index 0000000000000..618e7337b7a84
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Constant.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Constant = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Constant);
+ return (
+
+
+
+
+ );
+};
+Constant.type = 'constant';
+Constant.fields = ['name', 'value'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/DoubleGreatest.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/DoubleGreatest.tsx
new file mode 100644
index 0000000000000..6f89226074a05
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/DoubleGreatest.tsx
@@ -0,0 +1,26 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { PostAggregation } from './.';
+
+export const DoubleGreatest = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleGreatest);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+DoubleGreatest.type = 'doubleGreatest';
+DoubleGreatest.fields = ['name', 'fields'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/DoubleLeast.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/DoubleLeast.tsx
new file mode 100644
index 0000000000000..b8339627fecc2
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/DoubleLeast.tsx
@@ -0,0 +1,26 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { PostAggregation } from './.';
+
+export const DoubleLeast = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, DoubleLeast);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+DoubleLeast.type = 'doubleLeast';
+DoubleLeast.fields = ['name', 'fields'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/FieldAccess.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/FieldAccess.tsx
new file mode 100644
index 0000000000000..17d06ddd7e045
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/FieldAccess.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FieldAccess = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FieldAccess);
+ return (
+
+
+
+
+ );
+};
+FieldAccess.type = 'fieldAccess';
+FieldAccess.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/FinalizingFieldAccess.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/FinalizingFieldAccess.tsx
new file mode 100644
index 0000000000000..99c1ad863a355
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/FinalizingFieldAccess.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const FinalizingFieldAccess = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, FinalizingFieldAccess);
+ return (
+
+
+
+
+ );
+};
+FinalizingFieldAccess.type = 'finalizingFieldAccess';
+FinalizingFieldAccess.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/HyperUniqueCardinality.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/HyperUniqueCardinality.tsx
new file mode 100644
index 0000000000000..9f72502dde9d5
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/HyperUniqueCardinality.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const HyperUniqueCardinality = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, HyperUniqueCardinality);
+ return (
+
+
+
+
+ );
+};
+HyperUniqueCardinality.type = 'hyperUniqueCardinality';
+HyperUniqueCardinality.fields = ['name', 'fieldName'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Javascript.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Javascript.tsx
new file mode 100644
index 0000000000000..61769382e2ca0
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/Javascript.tsx
@@ -0,0 +1,36 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Code, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Javascript = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Javascript);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Javascript.type = 'javascript';
+Javascript.fields = ['name', 'fieldNames', 'function'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/LongGreatest.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/LongGreatest.tsx
new file mode 100644
index 0000000000000..02387038f6146
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/LongGreatest.tsx
@@ -0,0 +1,26 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { PostAggregation } from './.';
+
+export const LongGreatest = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LongGreatest);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+LongGreatest.type = 'longGreatest';
+LongGreatest.fields = ['name', 'fields'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/LongLeast.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/LongLeast.tsx
new file mode 100644
index 0000000000000..8bc102504e89b
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/LongLeast.tsx
@@ -0,0 +1,26 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { PostAggregation } from './.';
+
+export const LongLeast = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, LongLeast);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+LongLeast.type = 'longLeast';
+LongLeast.fields = ['name', 'fields'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/PostAggregation.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/PostAggregation.tsx
new file mode 100644
index 0000000000000..797a64faf7a3a
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/PostAggregation.tsx
@@ -0,0 +1,36 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import {
+ Arithmetic,
+ Constant,
+ DoubleGreatest,
+ DoubleLeast,
+ FieldAccess,
+ FinalizingFieldAccess,
+ HyperUniqueCardinality,
+ Javascript,
+ LongGreatest,
+ LongLeast,
+ QuantilesDoublesSketchToQuantile,
+} from './';
+
+export const PostAggregation = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/QuantilesDoublesSketchToQuantile.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/QuantilesDoublesSketchToQuantile.tsx
new file mode 100644
index 0000000000000..e7127ef42bed6
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/QuantilesDoublesSketchToQuantile.tsx
@@ -0,0 +1,36 @@
+import { useScopedQueryBuilderFieldProps, Input, Row, QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { FieldAccess, FinalizingFieldAccess, Javascript } from './';
+
+export const QuantilesDoublesSketchToQuantile = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, QuantilesDoublesSketchToQuantile);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+QuantilesDoublesSketchToQuantile.type = 'quantilesDoublesSketchToQuantile';
+QuantilesDoublesSketchToQuantile.fields = ['name', 'field', 'fraction'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/index.ts
new file mode 100644
index 0000000000000..d2e4502b0a927
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/postaggregation/index.ts
@@ -0,0 +1,12 @@
+export { Arithmetic } from './Arithmetic';
+export { Constant } from './Constant';
+export { DoubleGreatest } from './DoubleGreatest';
+export { DoubleLeast } from './DoubleLeast';
+export { FieldAccess } from './FieldAccess';
+export { FinalizingFieldAccess } from './FinalizingFieldAccess';
+export { HyperUniqueCardinality } from './HyperUniqueCardinality';
+export { Javascript } from './Javascript';
+export { LongGreatest } from './LongGreatest';
+export { LongLeast } from './LongLeast';
+export { PostAggregation } from './PostAggregation';
+export { QuantilesDoublesSketchToQuantile } from './QuantilesDoublesSketchToQuantile';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/DatasourceMetadata.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/DatasourceMetadata.tsx
new file mode 100644
index 0000000000000..1c1cda9b6f7f2
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/DatasourceMetadata.tsx
@@ -0,0 +1,14 @@
+import { useScopedQueryBuilderProps, Row } from '../abstract';
+import { DataSource } from '../datasource';
+import { QueryBuilderProps } from '../types';
+
+export const DatasourceMetadata = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderProps(props, DatasourceMetadata);
+ return (
+
+
+
+ );
+};
+DatasourceMetadata.queryType = 'dataSourceMetadata';
+DatasourceMetadata.fields = ['dataSource'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/GroupBy.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/GroupBy.tsx
new file mode 100644
index 0000000000000..956e0418df6d7
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/GroupBy.tsx
@@ -0,0 +1,97 @@
+import { useScopedQueryBuilderProps, useScopedQueryBuilderFieldProps, Multiple, Row } from '../abstract';
+import { Aggregation } from '../aggregation';
+import { DataSource } from '../datasource';
+import { Dimension } from '../dimension';
+import { Filter } from '../filter';
+import { Granularity } from '../granularity';
+import { HavingSpec } from '../havingspec';
+import { LimitSpec } from '../limitspec';
+import { PostAggregation } from '../postaggregation';
+import { Intervals } from '../querysegmentspec';
+import { QueryBuilderProps } from '../types';
+import { VirtualColumn } from '../virtualcolumn';
+
+export const GroupBy = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, GroupBy);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, GroupBy);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+GroupBy.queryType = 'groupBy';
+GroupBy.fields = [
+ 'dataSource',
+ 'dimensions',
+ 'limitSpec',
+ 'having',
+ 'granularity',
+ 'filter',
+ 'aggregations',
+ 'postAggregations',
+ 'intervals',
+ 'virtualColumns',
+];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Json.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Json.tsx
new file mode 100644
index 0000000000000..ed67df179d0ea
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Json.tsx
@@ -0,0 +1,29 @@
+import { Code, Row } from '../abstract';
+import { QueryBuilderProps, QueryBuilderOptions } from '../types';
+
+export const Json = (props: QueryBuilderProps) => {
+ const options: any = { builder: JSON.stringify(props.options.builder, null, '\t') };
+ const onChange = (options: QueryBuilderOptions) => {
+ let builder: any = {};
+ try {
+ builder = JSON.parse(options.builder);
+ } catch {
+ return;
+ }
+ props.onOptionsChange({ ...props.options, builder: builder });
+ };
+ return (
+
+
+
+ );
+};
+Json.queryType = 'json';
+Json.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Query.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Query.tsx
new file mode 100644
index 0000000000000..8deebe96d25c5
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Query.tsx
@@ -0,0 +1,34 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import {
+ DatasourceMetadata,
+ GroupBy,
+ Json,
+ Scan,
+ Search,
+ SegmentMetadata,
+ Sql,
+ TimeBoundary,
+ Timeseries,
+ TopN,
+} from './';
+
+export const Query = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Scan.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Scan.tsx
new file mode 100644
index 0000000000000..6aa9b898496b4
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Scan.tsx
@@ -0,0 +1,70 @@
+import { useScopedQueryBuilderProps, useScopedQueryBuilderFieldProps, Multiple, Input, Select, Row } from '../abstract';
+import { DataSource } from '../datasource';
+import { Filter } from '../filter';
+import { Intervals } from '../querysegmentspec';
+import { QueryBuilderProps } from '../types';
+import { VirtualColumn } from '../virtualcolumn';
+
+export const Scan = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Scan);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, Scan);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Scan.queryType = 'scan';
+Scan.fields = ['dataSource', 'intervals', 'filter', 'columns', 'order', 'limit', 'batchSize', 'virtualColumns'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Search.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Search.tsx
new file mode 100644
index 0000000000000..f19b50ae76f6d
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Search.tsx
@@ -0,0 +1,50 @@
+import { useScopedQueryBuilderProps, useScopedQueryBuilderFieldProps, Multiple, Input, Row } from '../abstract';
+import { DataSource } from '../datasource';
+import { Dimension } from '../dimension';
+import { Filter } from '../filter';
+import { Granularity } from '../granularity';
+import { Intervals } from '../querysegmentspec';
+import { SearchQuerySpec } from '../searchqueryspec';
+import { SearchSortSpec } from '../searchsortspec';
+import { QueryBuilderProps } from '../types';
+
+export const Search = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Search);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, Search);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Search.queryType = 'search';
+Search.fields = ['dataSource', 'granularity', 'filter', 'limit', 'intervals', 'searchDimensions', 'query', 'sort'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/SegmentMetadata.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/SegmentMetadata.tsx
new file mode 100644
index 0000000000000..7f72d77288ee2
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/SegmentMetadata.tsx
@@ -0,0 +1,92 @@
+import {
+ useScopedQueryBuilderProps,
+ useScopedQueryBuilderFieldProps,
+ ScopeType,
+ Select,
+ Checkbox,
+ MultiSelect,
+ Row,
+} from '../abstract';
+import { DataSource } from '../datasource';
+import { Intervals } from '../querysegmentspec';
+import { ToInclude } from '../toinclude';
+import { QueryBuilderProps } from '../types';
+
+export const SegmentMetadata = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, SegmentMetadata);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, SegmentMetadata);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+SegmentMetadata.queryType = 'segmentMetadata';
+SegmentMetadata.fields = [
+ 'dataSource',
+ 'intervals',
+ 'toInclude',
+ 'merge',
+ 'analysisTypes',
+ 'lenientAggregatorMerge',
+ 'usingDefaultInterval',
+];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Sql.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Sql.tsx
new file mode 100644
index 0000000000000..93dc262da7ab4
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Sql.tsx
@@ -0,0 +1,18 @@
+import { useScopedQueryBuilderFieldProps, Code, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Sql = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Sql);
+ return (
+
+
+
+ );
+};
+Sql.queryType = 'sql';
+Sql.fields = ['query'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/TimeBoundary.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/TimeBoundary.tsx
new file mode 100644
index 0000000000000..5657032231272
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/TimeBoundary.tsx
@@ -0,0 +1,36 @@
+import { useScopedQueryBuilderProps, useScopedQueryBuilderFieldProps, Select, Row } from '../abstract';
+import { DataSource } from '../datasource';
+import { Filter } from '../filter';
+import { Intervals } from '../querysegmentspec';
+import { QueryBuilderProps } from '../types';
+
+export const TimeBoundary = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, TimeBoundary);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, TimeBoundary);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+TimeBoundary.queryType = 'timeBoundary';
+TimeBoundary.fields = ['dataSource', 'bound', 'filter', 'intervals'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Timeseries.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Timeseries.tsx
new file mode 100644
index 0000000000000..d7edc9b1dd3f5
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/Timeseries.tsx
@@ -0,0 +1,95 @@
+import {
+ useScopedQueryBuilderProps,
+ useScopedQueryBuilderFieldProps,
+ Multiple,
+ Input,
+ Checkbox,
+ Row,
+} from '../abstract';
+import { Aggregation } from '../aggregation';
+import { DataSource } from '../datasource';
+import { Filter } from '../filter';
+import { Granularity } from '../granularity';
+import { PostAggregation } from '../postaggregation';
+import { Intervals } from '../querysegmentspec';
+import { QueryBuilderProps } from '../types';
+import { VirtualColumn } from '../virtualcolumn';
+
+export const Timeseries = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Timeseries);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, Timeseries);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+Timeseries.queryType = 'timeseries';
+Timeseries.fields = [
+ 'dataSource',
+ 'descending',
+ 'intervals',
+ 'granularity',
+ 'filter',
+ 'aggregations',
+ 'postAggregations',
+ 'limit',
+ 'virtualColumns',
+];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/TopN.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/TopN.tsx
new file mode 100644
index 0000000000000..1bdce402d594a
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/TopN.tsx
@@ -0,0 +1,95 @@
+import { useScopedQueryBuilderProps, useScopedQueryBuilderFieldProps, Multiple, Input, Row } from '../abstract';
+import { Aggregation } from '../aggregation';
+import { DataSource } from '../datasource';
+import { Dimension } from '../dimension';
+import { Filter } from '../filter';
+import { Granularity } from '../granularity';
+import { PostAggregation } from '../postaggregation';
+import { Intervals } from '../querysegmentspec';
+import { TopNMetric } from '../topnmetric';
+import { QueryBuilderProps } from '../types';
+import { VirtualColumn } from '../virtualcolumn';
+
+export const TopN = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, TopN);
+ const scopedComponentProps = useScopedQueryBuilderProps(props, TopN);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+TopN.queryType = 'topN';
+TopN.fields = [
+ 'dataSource',
+ 'intervals',
+ 'granularity',
+ 'filter',
+ 'aggregations',
+ 'postAggregations',
+ 'dimension',
+ 'threshold',
+ 'metric',
+ 'virtualColumns',
+];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/index.ts
new file mode 100644
index 0000000000000..896f90d9da31e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/query/index.ts
@@ -0,0 +1,11 @@
+export { Query } from './Query';
+export { DatasourceMetadata } from './DatasourceMetadata';
+export { GroupBy } from './GroupBy';
+export { Json } from './Json';
+export { Scan } from './Scan';
+export { Search } from './Search';
+export { SegmentMetadata } from './SegmentMetadata';
+export { Sql } from './Sql';
+export { TimeBoundary } from './TimeBoundary';
+export { Timeseries } from './Timeseries';
+export { TopN } from './TopN';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/Intervals.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/Intervals.tsx
new file mode 100644
index 0000000000000..5a1f6137e277e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/Intervals.tsx
@@ -0,0 +1,23 @@
+import { useScopedQueryBuilderFieldProps, Multiple, DateInterval } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Intervals = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Intervals);
+ return (
+
+ );
+};
+Intervals.type = 'intervals';
+Intervals.fields = ['intervals'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/QuerySegmentSpec.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/QuerySegmentSpec.tsx
new file mode 100644
index 0000000000000..0ec7ae1f66567
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/QuerySegmentSpec.tsx
@@ -0,0 +1,8 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Intervals } from './';
+
+export const QuerySegmentSpec = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/index.ts
new file mode 100644
index 0000000000000..8949c8cb2dcdd
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/querysegmentspec/index.ts
@@ -0,0 +1,2 @@
+export { QuerySegmentSpec } from './QuerySegmentSpec';
+export { Intervals } from './Intervals';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/All.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/All.tsx
new file mode 100644
index 0000000000000..a71b4239cd7bb
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/All.tsx
@@ -0,0 +1,29 @@
+import { useState } from 'react';
+
+import { InfoBox } from '@grafana/ui';
+
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const All = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, All);
+ const [showInfo, setShowInfo] = useState(true);
+ return (
+ <>
+ {showInfo && (
+
+ {
+ setShowInfo(false);
+ }}
+ >
+ All. Whatever it does.
+
+
+ )}
+ >
+ );
+};
+All.type = 'all';
+All.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Contains.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Contains.tsx
new file mode 100644
index 0000000000000..73e92969f1b4c
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Contains.tsx
@@ -0,0 +1,22 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Contains = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Contains);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+Contains.type = 'contains';
+Contains.fields = ['case_sensitive', 'value'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Fragment.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Fragment.tsx
new file mode 100644
index 0000000000000..4e23a14c9f3d3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Fragment.tsx
@@ -0,0 +1,32 @@
+import { useScopedQueryBuilderFieldProps, Input, Checkbox, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Fragment = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Fragment);
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+Fragment.type = 'fragment';
+Fragment.fields = ['case_sensitive', 'values'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/InsensitiveContains.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/InsensitiveContains.tsx
new file mode 100644
index 0000000000000..a2f60f1764122
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/InsensitiveContains.tsx
@@ -0,0 +1,13 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const InsensitiveContains = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, InsensitiveContains);
+ return (
+
+
+
+ );
+};
+InsensitiveContains.type = 'insensitive_contains';
+InsensitiveContains.fields = ['value'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Regex.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Regex.tsx
new file mode 100644
index 0000000000000..152c584ef8355
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/Regex.tsx
@@ -0,0 +1,13 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Regex = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Regex);
+ return (
+
+
+
+ );
+};
+Regex.type = 'regex';
+Regex.fields = ['pattern'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/SearchQuerySpec.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/SearchQuerySpec.tsx
new file mode 100644
index 0000000000000..be84271327fe2
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/SearchQuerySpec.tsx
@@ -0,0 +1,18 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { All, Contains, Fragment, InsensitiveContains, Regex } from './';
+
+export const SearchQuerySpec = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/index.ts
new file mode 100644
index 0000000000000..776d4283fb919
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchqueryspec/index.ts
@@ -0,0 +1,6 @@
+export { All } from './All';
+export { Contains } from './Contains';
+export { Fragment } from './Fragment';
+export { InsensitiveContains } from './InsensitiveContains';
+export { Regex } from './Regex';
+export { SearchQuerySpec } from './SearchQuerySpec';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/AlphaNumeric.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/AlphaNumeric.tsx
new file mode 100644
index 0000000000000..04ce7ff7b5834
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/AlphaNumeric.tsx
@@ -0,0 +1,9 @@
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const AlphaNumeric = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, AlphaNumeric);
+ return AlphaNumeric.
;
+};
+AlphaNumeric.type = 'alphanumeric';
+AlphaNumeric.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Lexicographic.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Lexicographic.tsx
new file mode 100644
index 0000000000000..8dfcfba3baf44
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Lexicographic.tsx
@@ -0,0 +1,9 @@
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Lexicographic = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, Lexicographic);
+ return Lexicographic.
;
+};
+Lexicographic.type = 'lexicographic';
+Lexicographic.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Numeric.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Numeric.tsx
new file mode 100644
index 0000000000000..9fe299d013c05
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Numeric.tsx
@@ -0,0 +1,9 @@
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Numeric = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, Numeric);
+ return Numeric.
;
+};
+Numeric.type = 'numeric';
+Numeric.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/SearchSortSpec.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/SearchSortSpec.tsx
new file mode 100644
index 0000000000000..d8a2d34bc0347
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/SearchSortSpec.tsx
@@ -0,0 +1,18 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { AlphaNumeric, Lexicographic, Numeric, StrLen, Version } from './';
+
+export const SearchSortSpec = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/StrLen.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/StrLen.tsx
new file mode 100644
index 0000000000000..478c7afb8bf85
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/StrLen.tsx
@@ -0,0 +1,9 @@
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const StrLen = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, StrLen);
+ return StrLen.
;
+};
+StrLen.type = 'strlen';
+StrLen.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Version.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Version.tsx
new file mode 100644
index 0000000000000..afea3b851ac3f
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/Version.tsx
@@ -0,0 +1,9 @@
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Version = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, Version);
+ return Version.
;
+};
+Version.type = 'version';
+Version.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/index.ts
new file mode 100644
index 0000000000000..db29a6e43cea8
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/searchsortspec/index.ts
@@ -0,0 +1,6 @@
+export { AlphaNumeric } from './AlphaNumeric';
+export { Lexicographic } from './Lexicographic';
+export { Numeric } from './Numeric';
+export { SearchSortSpec } from './SearchSortSpec';
+export { StrLen } from './StrLen';
+export { Version } from './Version';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/All.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/All.tsx
new file mode 100644
index 0000000000000..2ff212d2893f0
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/All.tsx
@@ -0,0 +1,29 @@
+import { useState } from 'react';
+
+import { InfoBox } from '@grafana/ui';
+
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const All = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, All);
+ const [showInfo, setShowInfo] = useState(true);
+ return (
+ <>
+ {showInfo && (
+
+ {
+ setShowInfo(false);
+ }}
+ >
+ All columns should be included in the result.
+
+
+ )}
+ >
+ );
+};
+All.type = 'all';
+All.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/List.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/List.tsx
new file mode 100644
index 0000000000000..9502b647a0822
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/List.tsx
@@ -0,0 +1,23 @@
+import { useScopedQueryBuilderFieldProps, Input, Multiple, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const List = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, List);
+ return (
+
+
+
+ );
+};
+List.type = 'list';
+List.fields = ['columns'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/None.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/None.tsx
new file mode 100644
index 0000000000000..15e44326cc7df
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/None.tsx
@@ -0,0 +1,29 @@
+import { useState } from 'react';
+
+import { InfoBox } from '@grafana/ui';
+
+import { useQueryBuilderAutoSubmit, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const None = (props: QueryBuilderProps) => {
+ useQueryBuilderAutoSubmit(props, None);
+ const [showInfo, setShowInfo] = useState(true);
+ return (
+ <>
+ {showInfo && (
+
+ {
+ setShowInfo(false);
+ }}
+ >
+ No column should be included in the result.
+
+
+ )}
+ >
+ );
+};
+None.type = 'none';
+None.fields = [] as string[];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/ToInclude.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/ToInclude.tsx
new file mode 100644
index 0000000000000..7b7b5fca57a7f
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/ToInclude.tsx
@@ -0,0 +1,8 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { All, List, None } from './';
+
+export const ToInclude = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/index.ts
new file mode 100644
index 0000000000000..675b56a504e89
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/toinclude/index.ts
@@ -0,0 +1,4 @@
+export { All } from './All';
+export { List } from './List';
+export { None } from './None';
+export { ToInclude } from './ToInclude';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/AlphaNumeric.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/AlphaNumeric.tsx
new file mode 100644
index 0000000000000..0b78cd8c14b0b
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/AlphaNumeric.tsx
@@ -0,0 +1,18 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const AlphaNumeric = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, AlphaNumeric);
+ return (
+
+
+
+ );
+};
+AlphaNumeric.type = 'alphaNumeric';
+AlphaNumeric.fields = ['previousStop'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Dimension.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Dimension.tsx
new file mode 100644
index 0000000000000..725a74d0189d8
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Dimension.tsx
@@ -0,0 +1,30 @@
+import { useScopedQueryBuilderFieldProps, Input, Select, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Dimension = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Dimension);
+ return (
+
+
+
+
+ );
+};
+Dimension.type = 'dimension';
+Dimension.fields = ['ordering', 'previousStop'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Inverted.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Inverted.tsx
new file mode 100644
index 0000000000000..d324ed4c4c174
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Inverted.tsx
@@ -0,0 +1,15 @@
+import { useScopedQueryBuilderProps, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { TopNMetric } from './';
+
+export const Inverted = (props: QueryBuilderProps) => {
+ const scopedComponentProps = useScopedQueryBuilderProps(props, Inverted);
+ return (
+
+
+
+ );
+};
+Inverted.type = 'inverted';
+Inverted.fields = ['metric'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Lexicographic.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Lexicographic.tsx
new file mode 100644
index 0000000000000..05d8d7a129caa
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Lexicographic.tsx
@@ -0,0 +1,18 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Lexicographic = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Lexicographic);
+ return (
+
+
+
+ );
+};
+Lexicographic.type = 'lexicographic';
+Lexicographic.fields = ['previousStop'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Numeric.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Numeric.tsx
new file mode 100644
index 0000000000000..12e63f382b905
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/Numeric.tsx
@@ -0,0 +1,18 @@
+import { useScopedQueryBuilderFieldProps, Input, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Numeric = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Numeric);
+ return (
+
+
+
+ );
+};
+Numeric.type = 'numeric';
+Numeric.fields = ['metric'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/TopNMetric.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/TopNMetric.tsx
new file mode 100644
index 0000000000000..1f59c6dd5f765
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/TopNMetric.tsx
@@ -0,0 +1,18 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { AlphaNumeric, Dimension, Inverted, Lexicographic, Numeric } from './';
+
+export const TopNMetric = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/index.ts
new file mode 100644
index 0000000000000..d4310c159470f
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/topnmetric/index.ts
@@ -0,0 +1,6 @@
+export { AlphaNumeric } from './AlphaNumeric';
+export { Dimension } from './Dimension';
+export { Inverted } from './Inverted';
+export { Lexicographic } from './Lexicographic';
+export { Numeric } from './Numeric';
+export { TopNMetric } from './TopNMetric';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/types.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/types.ts
new file mode 100644
index 0000000000000..39e3f54966fea
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/types.ts
@@ -0,0 +1,9 @@
+export interface QueryBuilderOptions {
+ builder: any;
+ settings: any;
+}
+
+export interface QueryBuilderProps {
+ options: QueryBuilderOptions;
+ onOptionsChange: (options: QueryBuilderOptions) => void;
+}
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/Expression.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/Expression.tsx
new file mode 100644
index 0000000000000..649fc8e4b5a9e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/Expression.tsx
@@ -0,0 +1,30 @@
+import { useScopedQueryBuilderFieldProps, Input, Select, Row } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+export const Expression = (props: QueryBuilderProps) => {
+ const scopedProps = useScopedQueryBuilderFieldProps(props, Expression);
+ return (
+
+
+
+
+
+ );
+};
+Expression.type = 'expression';
+Expression.fields = ['name', 'expression', 'outputType'];
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/VirtualColumn.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/VirtualColumn.tsx
new file mode 100644
index 0000000000000..b51a8487eee69
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/VirtualColumn.tsx
@@ -0,0 +1,8 @@
+import { QueryBuilderComponentSelector } from '../abstract';
+import { QueryBuilderProps } from '../types';
+
+import { Expression } from './';
+
+export const VirtualColumn = (props: QueryBuilderProps) => (
+
+);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/index.ts
new file mode 100644
index 0000000000000..d5a21976a600e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/builder/virtualcolumn/index.ts
@@ -0,0 +1,2 @@
+export { VirtualColumn } from './VirtualColumn';
+export { Expression } from './Expression';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidAuthSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidAuthSettings.tsx
new file mode 100644
index 0000000000000..f65c0d175c740
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidAuthSettings.tsx
@@ -0,0 +1,39 @@
+import { css } from '@emotion/css';
+import { ChangeEvent } from 'react';
+
+import { FieldSet, Field, Switch } from '@grafana/ui';
+
+import { ConnectionSettingsProps } from './types';
+
+import { DruidBasicAuthSettings } from './';
+
+export const DruidAuthSettings = (props: ConnectionSettingsProps) => {
+ const { options, onOptionsChange } = props;
+ const { settings } = options;
+
+ const onSettingChange = (event: ChangeEvent) => {
+ switch (event.target.name) {
+ case 'basicAuth': {
+ settings.basicAuth = event!.currentTarget.checked;
+ break;
+ }
+ }
+ onOptionsChange({ ...options, settings: settings });
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {settings.basicAuth && }
+ >
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidBasicAuthSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidBasicAuthSettings.tsx
new file mode 100644
index 0000000000000..1c1058f645fa5
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidBasicAuthSettings.tsx
@@ -0,0 +1,71 @@
+import { ChangeEvent } from 'react';
+
+import { LegacyForms, FieldSet } from '@grafana/ui';
+
+import { ConnectionSettingsProps } from './types';
+
+const { FormField, SecretFormField } = LegacyForms;
+
+export const DruidBasicAuthSettings = (props: ConnectionSettingsProps) => {
+ const { options, onOptionsChange } = props;
+ const { settings, secretSettings, secretSettingsFields } = options;
+ const onSettingChange = (event: ChangeEvent) => {
+ const value = event.target.value;
+ switch (event.target.name) {
+ case 'user': {
+ settings.basicAuthUser = value;
+ break;
+ }
+ }
+ onOptionsChange({ ...options, settings: settings });
+ };
+ const onSecretSettingChange = (event: ChangeEvent) => {
+ const value = event.target.value;
+ switch (event.target.name) {
+ case 'password': {
+ secretSettings.basicAuthPassword = value;
+ break;
+ }
+ }
+ onOptionsChange({ ...options, secretSettings: secretSettings });
+ };
+ const onPasswordReset = () => {
+ onOptionsChange({
+ ...options,
+ secretSettingsFields: {
+ ...secretSettings,
+ basicAuthPassword: false,
+ },
+ secretSettings: {
+ ...secretSettings,
+ basicAuthPassword: '',
+ },
+ });
+ };
+ return (
+
+
+
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidConnectionSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidConnectionSettings.tsx
new file mode 100644
index 0000000000000..284671f55d917
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidConnectionSettings.tsx
@@ -0,0 +1,12 @@
+import { ConnectionSettingsProps } from './types';
+
+import { DruidHttpSettings, DruidAuthSettings } from './';
+
+export const DruidConnectionSettings = (props: ConnectionSettingsProps) => {
+ return (
+ <>
+
+
+ >
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidHttpSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidHttpSettings.tsx
new file mode 100644
index 0000000000000..9dbe0fde336e1
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/DruidHttpSettings.tsx
@@ -0,0 +1,110 @@
+import { css } from '@emotion/css';
+import { ChangeEvent } from 'react';
+
+import { LegacyForms, FieldSet, Field, Switch, TagsInput, InlineFormLabel } from '@grafana/ui';
+
+import { ConnectionSettingsProps } from './types';
+
+const { FormField } = LegacyForms;
+
+export const DruidHttpSettings = (props: ConnectionSettingsProps) => {
+ const { options, onOptionsChange } = props;
+ const { settings } = options;
+ const onSettingChange = (event: ChangeEvent) => {
+ const value = event.target.value;
+ switch (event.target.name) {
+ case 'url': {
+ settings.url = value;
+ break;
+ }
+ case 'retryableRetryMax': {
+ settings.retryableRetryMax = +value;
+ break;
+ }
+ case 'retryableRetryWaitMin': {
+ settings.retryableRetryWaitMin = +value;
+ break;
+ }
+ case 'retryableRetryWaitMax': {
+ settings.retryableRetryWaitMax = +value;
+ break;
+ }
+ case 'skipTls': {
+ settings.skipTls = event!.currentTarget.checked;
+ break;
+ }
+ }
+ onOptionsChange({ ...options, settings: settings });
+ };
+ const isHttps = settings.url !== undefined && settings.url.indexOf('https') !== -1;
+ return (
+
+
+
+
+
+ {isHttps && (
+
+
+
+ )}
+
+
+ Allowed cookies
+
+ onOptionsChange({ ...options, jsonData: { keepCookies: cookies } })}
+ />
+
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/index.ts
new file mode 100644
index 0000000000000..0aa387a32b147
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/index.ts
@@ -0,0 +1,4 @@
+export { DruidConnectionSettings } from './DruidConnectionSettings';
+export { DruidHttpSettings } from './DruidHttpSettings';
+export { DruidAuthSettings } from './DruidAuthSettings';
+export { DruidBasicAuthSettings } from './DruidBasicAuthSettings';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/types.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/types.ts
new file mode 100644
index 0000000000000..2354e91a6de81
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/ConnectionSettings/types.ts
@@ -0,0 +1,27 @@
+import { KeyValue } from '@grafana/data';
+
+export interface ConnectionSettings {
+ url?: string;
+ retryableRetryMax?: number;
+ retryableRetryWaitMin?: number;
+ retryableRetryWaitMax?: number;
+ basicAuth?: boolean;
+ basicAuthUser?: string;
+ skipTls?: boolean;
+}
+export interface ConnectionSecretSettings {
+ basicAuthPassword?: string;
+}
+export interface ConnectionSettingsOptions {
+ settings: ConnectionSettings;
+ secretSettings: ConnectionSecretSettings;
+ secretSettingsFields: KeyValue;
+ jsonData?: {
+ keepCookies?: string[];
+ },
+}
+
+export interface ConnectionSettingsProps {
+ options: ConnectionSettingsOptions;
+ onOptionsChange: (options: ConnectionSettingsOptions) => void;
+}
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryContextSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryContextSettings.tsx
new file mode 100644
index 0000000000000..c9707e16edda1
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryContextSettings.tsx
@@ -0,0 +1,123 @@
+import { css, cx } from '@emotion/css';
+import { ChangeEvent } from 'react';
+
+import { GrafanaTheme } from '@grafana/data';
+import { InlineLabel, InlineField, InlineFieldRow, Input, Button, Icon, useTheme, stylesFactory } from '@grafana/ui';
+
+import { QuerySettingsProps } from './types';
+
+const useParameters = (props: QuerySettingsProps): any => {
+ const { options, onOptionsChange } = props;
+ const { settings } = options;
+ let parameters: any = {};
+ const contextParameters =
+ props.options.settings.contextParameters !== undefined ? props.options.settings.contextParameters : [];
+ contextParameters.forEach((value: any, index: number) => {
+ parameters['parameter_' + index] = value;
+ });
+ const setParameters = (parameters: any) => {
+ onOptionsChange({
+ ...options,
+ settings: {
+ ...settings,
+ contextParameters: Object.entries(parameters).map((parameter: any) => parameter[1]),
+ },
+ });
+ };
+ return [parameters, setParameters];
+};
+
+export const DruidQueryContextSettings = (props: QuerySettingsProps) => {
+ const theme = useTheme();
+ const styles = getStyles(theme);
+ const [parameters, setParameters] = useParameters(props);
+ const onParameterChange = (name: string, parameter: Parameter) => {
+ setParameters({ ...parameters, [name]: parameter });
+ };
+ return (
+
+
+ Context
+
+ {Object.entries(parameters).map((parameter: any, index: number) => (
+
+ {
+ onParameterChange(parameter[0], p);
+ }}
+ />
+ {
+ setParameters(Object.fromEntries(Object.entries(parameters).filter((_: any, i: number) => i !== index)));
+ event.preventDefault();
+ }}
+ >
+
+
+
+ ))}
+ {
+ setParameters({
+ ...parameters,
+ ['parameter_' + Object.entries(parameters).length]: { name: '', value: '' },
+ });
+ event.preventDefault();
+ }}
+ >
+ Add
+
+
+ );
+};
+
+const getStyles = stylesFactory((theme: GrafanaTheme) => {
+ return {
+ row: css`
+ width: 100%;
+ & > & {
+ border-left: 1px solid ${theme.colors.border2};
+ padding: 5px 0px 0px 10px;
+ }
+ `,
+ };
+});
+
+interface Parameter {
+ name: string;
+ value: any;
+}
+
+interface ParameterRowProps {
+ parameter: Parameter;
+ onChange: (value: Parameter) => void;
+}
+
+const ParameterRow = ({ parameter, onChange }: ParameterRowProps) => {
+ return (
+
+
+ ) => onChange({ ...parameter, name: e.target.value })}
+ />
+
+
+ ) => onChange({ ...parameter, value: e.target.value })}
+ />
+
+
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryDefaultSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryDefaultSettings.tsx
new file mode 100644
index 0000000000000..01732f61c4de3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryDefaultSettings.tsx
@@ -0,0 +1,26 @@
+import { css, cx } from '@emotion/css';
+
+import { FieldSet } from '@grafana/ui';
+
+import { QuerySettingsProps } from './types';
+
+import { DruidQueryRequestSettings, DruidQueryResponseSettings } from './';
+
+export const DruidQueryDefaultSettings = (props: QuerySettingsProps) => {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+
+const styles = {
+ fieldset: css`
+ padding-left: 5px;
+ `,
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryLogSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryLogSettings.tsx
new file mode 100644
index 0000000000000..48ece537716b8
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryLogSettings.tsx
@@ -0,0 +1,71 @@
+import { css, cx } from '@emotion/css';
+import { ChangeEvent } from 'react';
+
+import { GrafanaTheme } from '@grafana/data';
+import { InlineLabel, InlineFieldRow, InlineField, Input, useTheme, stylesFactory } from '@grafana/ui';
+
+import { QuerySettingsProps } from './types';
+
+export const DruidQueryLogSettings = (props: QuerySettingsProps) => {
+ const theme = useTheme();
+ const styles = getStyles(theme);
+ const { options, onOptionsChange } = props;
+ const { settings } = options;
+ const onInputChange = (event: ChangeEvent) => {
+ onOptionsChange({ ...options, settings: { ...settings, [event.target.name]: event.target.value } });
+ };
+ return (
+ <>
+
+ Log columns mapping
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+const getStyles = stylesFactory((theme: GrafanaTheme) => {
+ return {
+ row: css`
+ width: 100%;
+ & > & {
+ border-left: 1px solid ${theme.colors.border2};
+ padding: 5px 0px 0px 10px;
+ }
+ `,
+ };
+});
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryRequestSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryRequestSettings.tsx
new file mode 100644
index 0000000000000..1b4a9970771b3
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryRequestSettings.tsx
@@ -0,0 +1,31 @@
+import { ChangeEvent } from 'react';
+
+import { InlineFieldRow, InlineField, Input } from '@grafana/ui';
+
+import { DruidQueryContextSettings } from './DruidQueryContextSettings';
+import { QuerySettingsProps } from './types';
+
+export const DruidQueryRequestSettings = (props: QuerySettingsProps) => {
+ const { options, onOptionsChange } = props;
+ const { settings } = options;
+ const onDebounceTimeChange = (event: ChangeEvent) => {
+ onOptionsChange({ ...options, settings: { ...settings, debounceTime: Number(event.target.value) } });
+ };
+ return (
+ <>
+
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryResponseSettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryResponseSettings.tsx
new file mode 100644
index 0000000000000..ef748ed362e7f
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQueryResponseSettings.tsx
@@ -0,0 +1,69 @@
+import { ChangeEvent } from 'react';
+
+import { SelectableValue } from '@grafana/data';
+import { InlineFieldRow, InlineField, InlineSwitch, Select, Input } from '@grafana/ui';
+
+import { DruidQueryLogSettings } from './DruidQueryLogSettings';
+import { QuerySettingsProps } from './types';
+
+export const DruidQueryResponseSettings = (props: QuerySettingsProps) => {
+ const { options, onOptionsChange } = props;
+ const { settings } = options;
+ const formatSelectOptions: Array> = [
+ { label: 'Long', value: 'long' },
+ { label: 'Wide', value: 'wide' },
+ { label: 'Log', value: 'log' },
+ ];
+ const selectFormatOptionByValue = (value?: string): SelectableValue | undefined => {
+ if (undefined === value) {
+ return undefined;
+ }
+ const options = formatSelectOptions.filter((option) => option.value === value);
+ return options.length > 0 ? options[0] : undefined;
+ };
+ const onFormatSelectionChange = (option: SelectableValue) => {
+ onOptionsChange({ ...options, settings: { ...settings, format: option.value } });
+ };
+ const onHideEmptyColumnsChange = (event: ChangeEvent) => {
+ onOptionsChange({ ...options, settings: { ...settings, hideEmptyColumns: event!.currentTarget.checked } });
+ };
+ const onResponseLimitChange = (event: ChangeEvent) => {
+ onOptionsChange({ ...options, settings: { ...settings, responseLimit: Number(event.target.value) } });
+ };
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {settings.format === 'log' && (
+
+
+
+ )}
+ >
+ );
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQuerySettings.tsx b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQuerySettings.tsx
new file mode 100644
index 0000000000000..c8f0d53871461
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/DruidQuerySettings.tsx
@@ -0,0 +1,26 @@
+import { css, cx } from '@emotion/css';
+
+import { FieldSet } from '@grafana/ui';
+
+import { QuerySettingsProps } from './types';
+
+import { DruidQueryRequestSettings, DruidQueryResponseSettings } from './';
+
+export const DruidQuerySettings = (props: QuerySettingsProps) => {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
+
+const styles = {
+ fieldset: css`
+ padding-left: 5px;
+ `,
+};
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/index.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/index.ts
new file mode 100644
index 0000000000000..e882fbe0a4012
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/index.ts
@@ -0,0 +1,6 @@
+export { DruidQueryDefaultSettings } from './DruidQueryDefaultSettings';
+export { DruidQuerySettings } from './DruidQuerySettings';
+export { DruidQueryRequestSettings } from './DruidQueryRequestSettings';
+export { DruidQueryContextSettings } from './DruidQueryContextSettings';
+export { DruidQueryResponseSettings } from './DruidQueryResponseSettings';
+export { DruidQueryLogSettings } from './DruidQueryLogSettings';
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/types.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/types.ts
new file mode 100644
index 0000000000000..5b2c38c5aff77
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/configuration/QuerySettings/types.ts
@@ -0,0 +1,23 @@
+export interface QueryContextParameter {
+ name: string;
+ value: any;
+}
+
+export interface QuerySettings {
+ format?: string;
+ contextParameters?: QueryContextParameter[];
+ hideEmptyColumns?: boolean;
+ responseLimit?: number;
+ logColumnTime?: string;
+ logColumnLevel?: string;
+ logColumnMessage?: string;
+ debounceTime?: number;
+}
+export interface QuerySettingsOptions {
+ settings: QuerySettings;
+}
+
+export interface QuerySettingsProps {
+ options: QuerySettingsOptions;
+ onOptionsChange: (options: QuerySettingsOptions) => void;
+}
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/druid.svg b/public/app/plugins/datasource/grafadruid-druid-datasource/img/druid.svg
new file mode 100644
index 0000000000000..52db86db3fbb9
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/img/druid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-datasource-connection.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-datasource-connection.png
new file mode 100644
index 0000000000000..f7066ab4702e3
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-datasource-connection.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-datasource-default-settings.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-datasource-default-settings.png
new file mode 100644
index 0000000000000..c5b026ba6f1e1
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-datasource-default-settings.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-explore-logs.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-explore-logs.png
new file mode 100644
index 0000000000000..55ae1c16c6791
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-explore-logs.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-panels.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-panels.png
new file mode 100644
index 0000000000000..27620afbf9e2e
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-panels.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-formatter-druidjson.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-formatter-druidjson.png
new file mode 100644
index 0000000000000..3bdf32a1b8e95
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-formatter-druidjson.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-json.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-json.png
new file mode 100644
index 0000000000000..946b319e4f00b
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-json.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-settings-logs.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-settings-logs.png
new file mode 100644
index 0000000000000..4541be6e33be9
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-settings-logs.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-settings.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-settings.png
new file mode 100644
index 0000000000000..2ac0a0ccac7b8
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-settings.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-sql.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-sql.png
new file mode 100644
index 0000000000000..45e0dd6e49d5b
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-sql.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-timeseries.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-timeseries.png
new file mode 100644
index 0000000000000..c8a7e2c7b7fa3
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-querybuilder-timeseries.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-variables.png b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-variables.png
new file mode 100644
index 0000000000000..f8a47bfe33604
Binary files /dev/null and b/public/app/plugins/datasource/grafadruid-druid-datasource/img/screenshot-variables.png differ
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/module.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/module.ts
new file mode 100644
index 0000000000000..bd82dbb9e2f3b
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/module.ts
@@ -0,0 +1,12 @@
+import { DataSourcePlugin } from '@grafana/data';
+
+import { ConfigEditor } from './ConfigEditor';
+import { DruidDataSource } from './DruidDataSource';
+import { QueryEditor } from './QueryEditor';
+import { VariableQueryEditor } from './VariableQueryEditor';
+import { DruidQuery, DruidSettings } from './types';
+
+export const plugin = new DataSourcePlugin(DruidDataSource)
+ .setConfigEditor(ConfigEditor)
+ .setQueryEditor(QueryEditor)
+ .setVariableQueryEditor(VariableQueryEditor);
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/plugin.json b/public/app/plugins/datasource/grafadruid-druid-datasource/plugin.json
new file mode 100644
index 0000000000000..cdfb2a950c26e
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/plugin.json
@@ -0,0 +1,51 @@
+{
+ "type": "datasource",
+ "name": "Druid",
+ "id": "grafadruid-druid-datasource",
+ "metrics": true,
+ "backend": true,
+ "alerting": true,
+ "logs": true,
+ "executable": "grafadruid-druid-datasource",
+ "info": {
+ "description": "Connects Grafana to Druid",
+ "author": {
+ "name": "Grafadruid"
+ },
+ "keywords": ["druid"],
+ "logos": {
+ "small": "img/druid.svg",
+ "large": "img/druid.svg"
+ },
+ "links": [
+ {
+ "name": "Website",
+ "url": "https://github.com/grafadruid/druid-grafana"
+ },
+ {
+ "name": "License",
+ "url": "https://github.com/grafadruid/druid-grafana/blob/master/LICENSE"
+ }
+ ],
+ "screenshots": [
+ { "name": "datasource - connection", "path": "img/screenshot-datasource-connection.png" },
+ { "name": "datasource - default settings", "path": "img/screenshot-datasource-default-settings.png" },
+ { "name": "panels", "path": "img/screenshot-panels.png" },
+ { "name": "query builder - json", "path": "img/screenshot-querybuilder-json.png" },
+ { "name": "query builder - sql", "path": "img/screenshot-querybuilder-sql.png" },
+ { "name": "query builder - timeseries", "path": "img/screenshot-querybuilder-timeseries.png" },
+ { "name": "query builder - settings", "path": "img/screenshot-querybuilder-settings.png" },
+ { "name": "variables", "path": "img/screenshot-variables.png" },
+ { "name": "variables - formatter - druid:json", "path": "img/screenshot-querybuilder-formatter-druidjson.png" },
+ { "name": "explore - logs", "path": "img/screenshot-explore-logs.png" },
+ { "name": "query builder - settings - logs", "path": "img/screenshot-querybuilder-settings-logs.png" }
+ ],
+ "version": "%VERSION%",
+ "updated": "%TODAY%"
+ },
+ "dependencies": {
+ "grafanaDependency": ">=7.0.0",
+ "grafanaVersion": "7.x.x",
+ "plugins": []
+ }
+}
diff --git a/public/app/plugins/datasource/grafadruid-druid-datasource/types.ts b/public/app/plugins/datasource/grafadruid-druid-datasource/types.ts
new file mode 100644
index 0000000000000..44902005197b9
--- /dev/null
+++ b/public/app/plugins/datasource/grafadruid-druid-datasource/types.ts
@@ -0,0 +1,18 @@
+import { DataQuery, DataSourceJsonData } from '@grafana/data';
+
+import { ConnectionSettings } from './configuration/ConnectionSettings/types';
+import { QuerySettings } from './configuration/QuerySettings/types';
+
+//expr is a workaround: https://github.com/grafana/grafana/issues/30013
+export interface DruidQuery extends DataQuery {
+ builder: any;
+ settings: QuerySettings;
+ expr: string;
+}
+
+export interface DruidSettings extends DataSourceJsonData {
+ connection?: ConnectionSettings;
+ query?: QuerySettings;
+}
+
+export interface DruidSecureSettings {}
diff --git a/public/app/plugins/datasource/grafana-postgresql-datasource/tsconfig.json b/public/app/plugins/datasource/grafana-postgresql-datasource/tsconfig.json
index 1690bc6f49fe1..baaaea0418594 100644
--- a/public/app/plugins/datasource/grafana-postgresql-datasource/tsconfig.json
+++ b/public/app/plugins/datasource/grafana-postgresql-datasource/tsconfig.json
@@ -1,5 +1,7 @@
{
- "jsx": "react-jsx",
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ },
"extends": "@grafana/plugin-configs/tsconfig.json",
"include": ["."]
}
diff --git a/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx b/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx
index b78c1ab9fe6c6..9ca9d79ba4439 100644
--- a/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx
+++ b/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx
@@ -130,6 +130,7 @@ export const TreeNavigationEditor = ({ item }: StandardEditorProps
+ {/*@ts-ignore */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/app/plugins/panel/sankey-panel-0.5.0/.gitignore b/public/app/plugins/panel/sankey-panel-0.5.0/.gitignore
new file mode 100644
index 0000000000000..521bf24711e65
--- /dev/null
+++ b/public/app/plugins/panel/sankey-panel-0.5.0/.gitignore
@@ -0,0 +1,31 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+node_modules/
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+dist/
+artifacts/
+work/
+ci/
+e2e-results/
+
+# Editors
+.idea
+
diff --git a/public/app/plugins/panel/sankey-panel-0.5.0/.prettierignore b/public/app/plugins/panel/sankey-panel-0.5.0/.prettierignore
new file mode 100644
index 0000000000000..16c7d95a61e3b
--- /dev/null
+++ b/public/app/plugins/panel/sankey-panel-0.5.0/.prettierignore
@@ -0,0 +1,3 @@
+src/Error.tsx
+src/Sankey.js
+src/SankeyPanel.tsx
\ No newline at end of file
diff --git a/public/app/plugins/panel/sankey-panel-0.5.0/LICENSE b/public/app/plugins/panel/sankey-panel-0.5.0/LICENSE
new file mode 100644
index 0000000000000..f882365155a8a
--- /dev/null
+++ b/public/app/plugins/panel/sankey-panel-0.5.0/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Ismael
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/public/app/plugins/panel/sankey-panel-0.5.0/README.md b/public/app/plugins/panel/sankey-panel-0.5.0/README.md
new file mode 100644
index 0000000000000..ee7c9c4877838
--- /dev/null
+++ b/public/app/plugins/panel/sankey-panel-0.5.0/README.md
@@ -0,0 +1,82 @@
+# Grafana Sankey Panel
+
+Sankey diagram implementation for directed flow visualization between nodes in an acyclic network.
+
+![sankey-panel](img/sankey-panel.png)
+
+## Installing
+
+Using the grafana-cli:
+
+```bash
+grafana-cli --pluginUrl https://github.com/IsmaelMasharo/sankey-panel/raw/master/sankey-panel.zip plugins install sankey-panel
+```
+
+## Grafana Version
+
+Tested on Grafana 7.3.1
+
+## Required Fields
+
+The diagram gets constructed from a data source **formatted as table** with 3 mandatory fields: **source** (text), **target** (text), **value** (numeric, no nulls). The diagram at the beginning was created with the following table format:
+
+| source | target | value |
+|----------|----------|---------|
+| A | D | 2 |
+| B | D | 2 |
+| B | E | 2 |
+| A | F | 2 |
+| D | E | 2 |
+| D | F | 3 |
+| E | F | 4 |
+| C | D | 1 |
+| C | E | 1 |
+| E | G | 1 |
+
+Being an acyclic implementation of the Sankey diagram **loops are not allowed**:
+
+| source | target | value |
+|----------|----------|---------|
+| A | B | 2 |
+| B | A (*x*) | 2 |
+
+To avoid *circular link error* [a masked prefix](https://github.com/IsmaelMasharo/sankey-panel/issues/1#issuecomment-757972917) could be set on the target values:
+
+| source | target | value |
+|----------|----------|---------|
+| A | B | 2 |
+| B | P-A | 2 |
+
+## Display Options
+
+There are 5 options for displaying the diagram: *Alignment*, *Color*, *Edge Color*, *Display Values*, *Highlight Connections*
+
+### Alignment
+
+Arranges the nodes to one of the following sides: Left, Right, Center, Justify. See d3 [sankey nodeAlign](https://github.com/d3/d3-sankey#alignments) for image reference.
+
+### Color
+
+Nodes and links color. Based on d3 [categorical schemes](https://github.com/d3/d3-scale-chromatic#categorical).
+
+### Edge Color
+
+Represents the link's color transition from source to the target node.
+
+- Input: Link takes the color of the source node.
+- Output: Link takes the color of the target node.
+- Input-Output: The link will be colored as a gradient from source to target node colors.
+- None: Gray links.
+
+### Display Values
+
+Values are shown next to the node name.
+
+- Total: Display link weight value.
+- Percentage: Display link weight percentage value relative to the source.
+- Both: Display both total and percentage.
+- None: No values displayed (except for node name).
+
+### Highlight Connections
+
+Boolean. Highlights links and nodes with a direct connection to the hovered node.
diff --git a/public/app/plugins/panel/sankey-panel-0.5.0/img/logo.svg b/public/app/plugins/panel/sankey-panel-0.5.0/img/logo.svg
new file mode 100644
index 0000000000000..2d41fa5441e64
--- /dev/null
+++ b/public/app/plugins/panel/sankey-panel-0.5.0/img/logo.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/app/plugins/panel/sankey-panel-0.5.0/module.js b/public/app/plugins/panel/sankey-panel-0.5.0/module.js
new file mode 100644
index 0000000000000..ac5c5013f822e
--- /dev/null
+++ b/public/app/plugins/panel/sankey-panel-0.5.0/module.js
@@ -0,0 +1,1359 @@
+/*! For license information please see module.js.LICENSE.txt */
+define(['react', 'd3', '@grafana/data', '@grafana/ui'], function (t, e, n, r) {
+ return (function (t) {
+ var e = {};
+ function n(r) {
+ if (e[r]) return e[r].exports;
+ var o = (e[r] = { i: r, l: !1, exports: {} });
+ return t[r].call(o.exports, o, o.exports, n), (o.l = !0), o.exports;
+ }
+ return (
+ (n.m = t),
+ (n.c = e),
+ (n.d = function (t, e, r) {
+ n.o(t, e) || Object.defineProperty(t, e, { enumerable: !0, get: r });
+ }),
+ (n.r = function (t) {
+ 'undefined' != typeof Symbol &&
+ Symbol.toStringTag &&
+ Object.defineProperty(t, Symbol.toStringTag, { value: 'Module' }),
+ Object.defineProperty(t, '__esModule', { value: !0 });
+ }),
+ (n.t = function (t, e) {
+ if ((1 & e && (t = n(t)), 8 & e)) return t;
+ if (4 & e && 'object' == typeof t && t && t.__esModule) return t;
+ var r = Object.create(null);
+ if ((n.r(r), Object.defineProperty(r, 'default', { enumerable: !0, value: t }), 2 & e && 'string' != typeof t))
+ for (var o in t)
+ n.d(
+ r,
+ o,
+ function (e) {
+ return t[e];
+ }.bind(null, o)
+ );
+ return r;
+ }),
+ (n.n = function (t) {
+ var e =
+ t && t.__esModule
+ ? function () {
+ return t.default;
+ }
+ : function () {
+ return t;
+ };
+ return n.d(e, 'a', e), e;
+ }),
+ (n.o = function (t, e) {
+ return Object.prototype.hasOwnProperty.call(t, e);
+ }),
+ (n.p = '/'),
+ n((n.s = 5))
+ );
+ })([
+ function (e, n) {
+ e.exports = t;
+ },
+ function (t, n) {
+ t.exports = e;
+ },
+ function (t, e) {
+ t.exports = n;
+ },
+ function (t, e) {
+ t.exports = r;
+ },
+ ,
+ function (t, e, n) {
+ 'use strict';
+ n.r(e);
+ var r = {};
+ n.r(r),
+ n.d(r, 'sankey', function () {
+ return M;
+ }),
+ n.d(r, 'sankeyCenter', function () {
+ return v;
+ }),
+ n.d(r, 'sankeyLeft', function () {
+ return g;
+ }),
+ n.d(r, 'sankeyRight', function () {
+ return p;
+ }),
+ n.d(r, 'sankeyJustify', function () {
+ return _;
+ }),
+ n.d(r, 'sankeyLinkHorizontal', function () {
+ return q;
+ });
+ var o = n(2);
+ var i = function () {
+ return (i =
+ Object.assign ||
+ function (t) {
+ for (var e, n = 1, r = arguments.length; n < r; n++)
+ for (var o in (e = arguments[n])) Object.prototype.hasOwnProperty.call(e, o) && (t[o] = e[o]);
+ return t;
+ }).apply(this, arguments);
+ };
+ function a(t, e) {
+ var n = {};
+ for (var r in t) Object.prototype.hasOwnProperty.call(t, r) && e.indexOf(r) < 0 && (n[r] = t[r]);
+ if (null != t && 'function' == typeof Object.getOwnPropertySymbols) {
+ var o = 0;
+ for (r = Object.getOwnPropertySymbols(t); o < r.length; o++)
+ e.indexOf(r[o]) < 0 && Object.prototype.propertyIsEnumerable.call(t, r[o]) && (n[r[o]] = t[r[o]]);
+ }
+ return n;
+ }
+ function s(t, e) {
+ var n = 'function' == typeof Symbol && t[Symbol.iterator];
+ if (!n) return t;
+ var r,
+ o,
+ i = n.call(t),
+ a = [];
+ try {
+ for (; (void 0 === e || e-- > 0) && !(r = i.next()).done; ) a.push(r.value);
+ } catch (t) {
+ o = { error: t };
+ } finally {
+ try {
+ r && !r.done && (n = i.return) && n.call(i);
+ } finally {
+ if (o) throw o.error;
+ }
+ }
+ return a;
+ }
+ var u = n(0),
+ l = n.n(u),
+ c = n(1);
+ function f(t, e) {
+ let n = 0;
+ if (void 0 === e) for (let e of t) (e = +e) && (n += e);
+ else {
+ let r = -1;
+ for (let o of t) (o = +e(o, ++r, t)) && (n += o);
+ }
+ return n;
+ }
+ function h(t, e) {
+ let n;
+ if (void 0 === e) for (const e of t) null != e && (n < e || (void 0 === n && e >= e)) && (n = e);
+ else {
+ let r = -1;
+ for (let o of t) null != (o = e(o, ++r, t)) && (n < o || (void 0 === n && o >= o)) && (n = o);
+ }
+ return n;
+ }
+ function d(t, e) {
+ let n;
+ if (void 0 === e) for (const e of t) null != e && (n > e || (void 0 === n && e >= e)) && (n = e);
+ else {
+ let r = -1;
+ for (let o of t) null != (o = e(o, ++r, t)) && (n > o || (void 0 === n && o >= o)) && (n = o);
+ }
+ return n;
+ }
+ function y(t) {
+ return t.target.depth;
+ }
+ function g(t) {
+ return t.depth;
+ }
+ function p(t, e) {
+ return e - 1 - t.height;
+ }
+ function _(t, e) {
+ return t.sourceLinks.length ? t.depth : e - 1;
+ }
+ function v(t) {
+ return t.targetLinks.length ? t.depth : t.sourceLinks.length ? d(t.sourceLinks, y) - 1 : 0;
+ }
+ function k(t) {
+ return function () {
+ return t;
+ };
+ }
+ function m(t, e) {
+ return x(t.source, e.source) || t.index - e.index;
+ }
+ function b(t, e) {
+ return x(t.target, e.target) || t.index - e.index;
+ }
+ function x(t, e) {
+ return t.y0 - e.y0;
+ }
+ function w(t) {
+ return t.value;
+ }
+ function S(t) {
+ return t.index;
+ }
+ function L(t) {
+ return t.nodes;
+ }
+ function A(t) {
+ return t.links;
+ }
+ function O(t, e) {
+ const n = t.get(e);
+ if (!n) throw new Error('missing: ' + e);
+ return n;
+ }
+ function j({ nodes: t }) {
+ for (const e of t) {
+ let t = e.y0,
+ n = t;
+ for (const n of e.sourceLinks) (n.y0 = t + n.width / 2), (t += n.width);
+ for (const t of e.targetLinks) (t.y1 = n + t.width / 2), (n += t.width);
+ }
+ }
+ function M() {
+ let t,
+ e,
+ n,
+ r = 0,
+ o = 0,
+ i = 1,
+ a = 1,
+ s = 24,
+ u = 8,
+ l = S,
+ c = _,
+ y = L,
+ g = A,
+ p = 6;
+ function v() {
+ const t = { nodes: y.apply(null, arguments), links: g.apply(null, arguments) };
+ return M(t), T(t), V(t), P(t), E(t), j(t), t;
+ }
+ function M({ nodes: t, links: e }) {
+ for (const [e, n] of t.entries()) (n.index = e), (n.sourceLinks = []), (n.targetLinks = []);
+ const r = new Map(t.map((e, n) => [l(e, n, t), e]));
+ for (const [t, n] of e.entries()) {
+ n.index = t;
+ let { source: e, target: o } = n;
+ 'object' != typeof e && (e = n.source = O(r, e)),
+ 'object' != typeof o && (o = n.target = O(r, o)),
+ e.sourceLinks.push(n),
+ o.targetLinks.push(n);
+ }
+ if (null != n) for (const { sourceLinks: e, targetLinks: r } of t) e.sort(n), r.sort(n);
+ }
+ function T({ nodes: t }) {
+ for (const e of t)
+ e.value = void 0 === e.fixedValue ? Math.max(f(e.sourceLinks, w), f(e.targetLinks, w)) : e.fixedValue;
+ }
+ function V({ nodes: t }) {
+ const e = t.length;
+ let n = new Set(t),
+ r = new Set(),
+ o = 0;
+ for (; n.size; ) {
+ for (const t of n) {
+ t.depth = o;
+ for (const { target: e } of t.sourceLinks) r.add(e);
+ }
+ if (++o > e) throw new Error('circular link');
+ (n = r), (r = new Set());
+ }
+ }
+ function P({ nodes: t }) {
+ const e = t.length;
+ let n = new Set(t),
+ r = new Set(),
+ o = 0;
+ for (; n.size; ) {
+ for (const t of n) {
+ t.height = o;
+ for (const { source: e } of t.targetLinks) r.add(e);
+ }
+ if (++o > e) throw new Error('circular link');
+ (n = r), (r = new Set());
+ }
+ }
+ function E(n) {
+ const l = (function ({ nodes: t }) {
+ const n = h(t, (t) => t.depth) + 1,
+ o = (i - r - s) / (n - 1),
+ a = new Array(n);
+ for (const e of t) {
+ const t = Math.max(0, Math.min(n - 1, Math.floor(c.call(null, e, n))));
+ (e.layer = t), (e.x0 = r + t * o), (e.x1 = e.x0 + s), a[t] ? a[t].push(e) : (a[t] = [e]);
+ }
+ if (e) for (const t of a) t.sort(e);
+ return a;
+ })(n);
+ (t = Math.min(u, (a - o) / (h(l, (t) => t.length) - 1))),
+ (function (e) {
+ const n = d(e, (e) => (a - o - (e.length - 1) * t) / f(e, w));
+ for (const r of e) {
+ let e = o;
+ for (const o of r) {
+ (o.y0 = e), (o.y1 = e + o.value * n), (e = o.y1 + t);
+ for (const t of o.sourceLinks) t.width = t.value * n;
+ }
+ e = (a - e + t) / (r.length + 1);
+ for (let t = 0; t < r.length; ++t) {
+ const n = r[t];
+ (n.y0 += e * (t + 1)), (n.y1 += e * (t + 1));
+ }
+ J(r);
+ }
+ })(l);
+ for (let t = 0; t < p; ++t) {
+ const e = Math.pow(0.99, t),
+ n = Math.max(1 - e, (t + 1) / p);
+ N(l, e, n), C(l, e, n);
+ }
+ }
+ function C(t, n, r) {
+ for (let o = 1, i = t.length; o < i; ++o) {
+ const i = t[o];
+ for (const t of i) {
+ let e = 0,
+ r = 0;
+ for (const { source: n, value: o } of t.targetLinks) {
+ let i = o * (t.layer - n.layer);
+ (e += G(n, t) * i), (r += i);
+ }
+ if (!(r > 0)) continue;
+ let o = (e / r - t.y0) * n;
+ (t.y0 += o), (t.y1 += o), F(t);
+ }
+ void 0 === e && i.sort(x), B(i, r);
+ }
+ }
+ function N(t, n, r) {
+ for (let o = t.length - 2; o >= 0; --o) {
+ const i = t[o];
+ for (const t of i) {
+ let e = 0,
+ r = 0;
+ for (const { target: n, value: o } of t.sourceLinks) {
+ let i = o * (n.layer - t.layer);
+ (e += I(t, n) * i), (r += i);
+ }
+ if (!(r > 0)) continue;
+ let o = (e / r - t.y0) * n;
+ (t.y0 += o), (t.y1 += o), F(t);
+ }
+ void 0 === e && i.sort(x), B(i, r);
+ }
+ }
+ function B(e, n) {
+ const r = e.length >> 1,
+ i = e[r];
+ z(e, i.y0 - t, r - 1, n), H(e, i.y1 + t, r + 1, n), z(e, a, e.length - 1, n), H(e, o, 0, n);
+ }
+ function H(e, n, r, o) {
+ for (; r < e.length; ++r) {
+ const i = e[r],
+ a = (n - i.y0) * o;
+ a > 1e-6 && ((i.y0 += a), (i.y1 += a)), (n = i.y1 + t);
+ }
+ }
+ function z(e, n, r, o) {
+ for (; r >= 0; --r) {
+ const i = e[r],
+ a = (i.y1 - n) * o;
+ a > 1e-6 && ((i.y0 -= a), (i.y1 -= a)), (n = i.y0 - t);
+ }
+ }
+ function F({ sourceLinks: t, targetLinks: e }) {
+ if (void 0 === n) {
+ for (const {
+ source: { sourceLinks: t },
+ } of e)
+ t.sort(b);
+ for (const {
+ target: { targetLinks: e },
+ } of t)
+ e.sort(m);
+ }
+ }
+ function J(t) {
+ if (void 0 === n) for (const { sourceLinks: e, targetLinks: n } of t) e.sort(b), n.sort(m);
+ }
+ function G(e, n) {
+ let r = e.y0 - ((e.sourceLinks.length - 1) * t) / 2;
+ for (const { target: o, width: i } of e.sourceLinks) {
+ if (o === n) break;
+ r += i + t;
+ }
+ for (const { source: t, width: o } of n.targetLinks) {
+ if (t === e) break;
+ r -= o;
+ }
+ return r;
+ }
+ function I(e, n) {
+ let r = n.y0 - ((n.targetLinks.length - 1) * t) / 2;
+ for (const { source: o, width: i } of n.targetLinks) {
+ if (o === e) break;
+ r += i + t;
+ }
+ for (const { target: t, width: o } of e.sourceLinks) {
+ if (t === n) break;
+ r -= o;
+ }
+ return r;
+ }
+ return (
+ (v.update = function (t) {
+ return j(t), t;
+ }),
+ (v.nodeId = function (t) {
+ return arguments.length ? ((l = 'function' == typeof t ? t : k(t)), v) : l;
+ }),
+ (v.nodeAlign = function (t) {
+ return arguments.length ? ((c = 'function' == typeof t ? t : k(t)), v) : c;
+ }),
+ (v.nodeSort = function (t) {
+ return arguments.length ? ((e = t), v) : e;
+ }),
+ (v.nodeWidth = function (t) {
+ return arguments.length ? ((s = +t), v) : s;
+ }),
+ (v.nodePadding = function (e) {
+ return arguments.length ? ((u = t = +e), v) : u;
+ }),
+ (v.nodes = function (t) {
+ return arguments.length ? ((y = 'function' == typeof t ? t : k(t)), v) : y;
+ }),
+ (v.links = function (t) {
+ return arguments.length ? ((g = 'function' == typeof t ? t : k(t)), v) : g;
+ }),
+ (v.linkSort = function (t) {
+ return arguments.length ? ((n = t), v) : n;
+ }),
+ (v.size = function (t) {
+ return arguments.length ? ((r = o = 0), (i = +t[0]), (a = +t[1]), v) : [i - r, a - o];
+ }),
+ (v.extent = function (t) {
+ return arguments.length
+ ? ((r = +t[0][0]), (i = +t[1][0]), (o = +t[0][1]), (a = +t[1][1]), v)
+ : [
+ [r, o],
+ [i, a],
+ ];
+ }),
+ (v.iterations = function (t) {
+ return arguments.length ? ((p = +t), v) : p;
+ }),
+ v
+ );
+ }
+ var T = Math.PI,
+ V = 2 * T,
+ P = V - 1e-6;
+ function E() {
+ (this._x0 = this._y0 = this._x1 = this._y1 = null), (this._ = '');
+ }
+ function C() {
+ return new E();
+ }
+ E.prototype = C.prototype = {
+ constructor: E,
+ moveTo: function (t, e) {
+ this._ += 'M' + (this._x0 = this._x1 = +t) + ',' + (this._y0 = this._y1 = +e);
+ },
+ closePath: function () {
+ null !== this._x1 && ((this._x1 = this._x0), (this._y1 = this._y0), (this._ += 'Z'));
+ },
+ lineTo: function (t, e) {
+ this._ += 'L' + (this._x1 = +t) + ',' + (this._y1 = +e);
+ },
+ quadraticCurveTo: function (t, e, n, r) {
+ this._ += 'Q' + +t + ',' + +e + ',' + (this._x1 = +n) + ',' + (this._y1 = +r);
+ },
+ bezierCurveTo: function (t, e, n, r, o, i) {
+ this._ += 'C' + +t + ',' + +e + ',' + +n + ',' + +r + ',' + (this._x1 = +o) + ',' + (this._y1 = +i);
+ },
+ arcTo: function (t, e, n, r, o) {
+ (t = +t), (e = +e), (n = +n), (r = +r), (o = +o);
+ var i = this._x1,
+ a = this._y1,
+ s = n - t,
+ u = r - e,
+ l = i - t,
+ c = a - e,
+ f = l * l + c * c;
+ if (o < 0) throw new Error('negative radius: ' + o);
+ if (null === this._x1) this._ += 'M' + (this._x1 = t) + ',' + (this._y1 = e);
+ else if (f > 1e-6)
+ if (Math.abs(c * s - u * l) > 1e-6 && o) {
+ var h = n - i,
+ d = r - a,
+ y = s * s + u * u,
+ g = h * h + d * d,
+ p = Math.sqrt(y),
+ _ = Math.sqrt(f),
+ v = o * Math.tan((T - Math.acos((y + f - g) / (2 * p * _))) / 2),
+ k = v / _,
+ m = v / p;
+ Math.abs(k - 1) > 1e-6 && (this._ += 'L' + (t + k * l) + ',' + (e + k * c)),
+ (this._ +=
+ 'A' +
+ o +
+ ',' +
+ o +
+ ',0,0,' +
+ +(c * h > l * d) +
+ ',' +
+ (this._x1 = t + m * s) +
+ ',' +
+ (this._y1 = e + m * u));
+ } else this._ += 'L' + (this._x1 = t) + ',' + (this._y1 = e);
+ else;
+ },
+ arc: function (t, e, n, r, o, i) {
+ (t = +t), (e = +e), (i = !!i);
+ var a = (n = +n) * Math.cos(r),
+ s = n * Math.sin(r),
+ u = t + a,
+ l = e + s,
+ c = 1 ^ i,
+ f = i ? r - o : o - r;
+ if (n < 0) throw new Error('negative radius: ' + n);
+ null === this._x1
+ ? (this._ += 'M' + u + ',' + l)
+ : (Math.abs(this._x1 - u) > 1e-6 || Math.abs(this._y1 - l) > 1e-6) && (this._ += 'L' + u + ',' + l),
+ n &&
+ (f < 0 && (f = (f % V) + V),
+ f > P
+ ? (this._ +=
+ 'A' +
+ n +
+ ',' +
+ n +
+ ',0,1,' +
+ c +
+ ',' +
+ (t - a) +
+ ',' +
+ (e - s) +
+ 'A' +
+ n +
+ ',' +
+ n +
+ ',0,1,' +
+ c +
+ ',' +
+ (this._x1 = u) +
+ ',' +
+ (this._y1 = l))
+ : f > 1e-6 &&
+ (this._ +=
+ 'A' +
+ n +
+ ',' +
+ n +
+ ',0,' +
+ +(f >= T) +
+ ',' +
+ c +
+ ',' +
+ (this._x1 = t + n * Math.cos(o)) +
+ ',' +
+ (this._y1 = e + n * Math.sin(o))));
+ },
+ rect: function (t, e, n, r) {
+ this._ +=
+ 'M' + (this._x0 = this._x1 = +t) + ',' + (this._y0 = this._y1 = +e) + 'h' + +n + 'v' + +r + 'h' + -n + 'Z';
+ },
+ toString: function () {
+ return this._;
+ },
+ };
+ var N = C,
+ B = Array.prototype.slice,
+ H = function (t) {
+ return function () {
+ return t;
+ };
+ };
+ function z(t) {
+ return t[0];
+ }
+ function F(t) {
+ return t[1];
+ }
+ function J(t) {
+ return t.source;
+ }
+ function G(t) {
+ return t.target;
+ }
+ function I(t) {
+ var e = J,
+ n = G,
+ r = z,
+ o = F,
+ i = null;
+ function a() {
+ var a,
+ s = B.call(arguments),
+ u = e.apply(this, s),
+ l = n.apply(this, s);
+ if (
+ (i || (i = a = N()),
+ t(
+ i,
+ +r.apply(this, ((s[0] = u), s)),
+ +o.apply(this, s),
+ +r.apply(this, ((s[0] = l), s)),
+ +o.apply(this, s)
+ ),
+ a)
+ )
+ return (i = null), a + '' || null;
+ }
+ return (
+ (a.source = function (t) {
+ return arguments.length ? ((e = t), a) : e;
+ }),
+ (a.target = function (t) {
+ return arguments.length ? ((n = t), a) : n;
+ }),
+ (a.x = function (t) {
+ return arguments.length ? ((r = 'function' == typeof t ? t : H(+t)), a) : r;
+ }),
+ (a.y = function (t) {
+ return arguments.length ? ((o = 'function' == typeof t ? t : H(+t)), a) : o;
+ }),
+ (a.context = function (t) {
+ return arguments.length ? ((i = null == t ? null : t), a) : i;
+ }),
+ a
+ );
+ }
+ function D(t, e, n, r, o) {
+ t.moveTo(e, n), t.bezierCurveTo((e = (e + r) / 2), n, e, o, r, o);
+ }
+ function R(t) {
+ return [t.source.x1, t.y0];
+ }
+ function W(t) {
+ return [t.target.x0, t.y1];
+ }
+ var q = function () {
+ return I(D).source(R).target(W);
+ };
+ function U(t, e) {
+ for (var n = 0; n < e.length; n++) {
+ var r = e[n];
+ (r.enumerable = r.enumerable || !1),
+ (r.configurable = !0),
+ 'value' in r && (r.writable = !0),
+ Object.defineProperty(t, r.key, r);
+ }
+ }
+ var Z = 'total',
+ Q = 'percentage',
+ K = 'both',
+ X = 'none',
+ Y = 'path',
+ $ = 'input',
+ tt = 'output',
+ et = (function () {
+ function t(e, n) {
+ !(function (t, e) {
+ if (!(t instanceof e)) throw new TypeError('Cannot call a class as a function');
+ })(this, t),
+ (this._svg = e),
+ (this._container = n || e),
+ (this._gBound = null),
+ (this._data = null),
+ (this._nodes = null),
+ (this._links = null),
+ (this._width = 0),
+ (this._height = 0),
+ (this._boundedWidth = 0),
+ (this._boundedHeight = 0),
+ (this._marginTop = 20),
+ (this._marginRight = 20),
+ (this._marginBottom = 20),
+ (this._marginLeft = 20),
+ (this._background = 'rgba(0, 0, 0, 0)'),
+ (this._edgeColor = 'path'),
+ (this._colorScheme = 'Tableau10'),
+ (this._colorScale = null),
+ (this._colorArray = ''),
+ (this._sankeyAlignType = 'Justify'),
+ (this._sankeyAlign = null),
+ (this._sankeyGenerator = null),
+ (this._sankeyNodeWith = 110),
+ (this._sankeyNodePadding = 20),
+ (this._svgNode = null),
+ (this._svgLink = null),
+ (this._displayValues = 'none'),
+ (this._highlightOnHover = !1);
+ }
+ var e, n, o;
+ return (
+ (e = t),
+ (n = [
+ {
+ key: '_init',
+ value: function () {
+ this._setBoundDimensions(), this._setColorScale(), this._configureSankey(), this._calculateSankey();
+ },
+ },
+ {
+ key: '_setBoundDimensions',
+ value: function () {
+ (this._boundedWidth = this._width - this._marginLeft - this._marginRight),
+ (this._boundedHeight = this._height - this._marginTop - this._marginBottom);
+ },
+ },
+ {
+ key: '_setColorScale',
+ value: function () {
+ this._colorScale = c.scaleOrdinal(c['scheme'.concat(this._colorScheme)]);
+ },
+ },
+ {
+ key: '_color',
+ value: function (t) {
+ return this._colorScale(t.name);
+ },
+ },
+ {
+ key: '_configureSankey',
+ value: function () {
+ (this._sankeyAlign = r['sankey'.concat(this._sankeyAlignType)]),
+ (this._sankeyGenerator = M()
+ .nodeId(function (t) {
+ return t.name;
+ })
+ .nodeAlign(this._sankeyAlign)
+ .nodeWidth(this._sankeyNodeWith)
+ .nodePadding(this._sankeyNodePadding)
+ .extent([
+ [0, 0],
+ [this._boundedWidth, this._boundedHeight],
+ ]));
+ },
+ },
+ {
+ key: '_calculateSankey',
+ value: function () {
+ var t = this._sankeyGenerator({
+ nodes: this._data.nodes.map(function (t) {
+ return Object.assign({}, t);
+ }),
+ links: this._data.links.map(function (t) {
+ return Object.assign({}, t);
+ }),
+ });
+ (this._nodes = t.nodes.filter(function (t) {
+ return 0 !== t.value;
+ })),
+ (this._links = t.links.filter(function (t) {
+ return 0 !== t.value;
+ }));
+ },
+ },
+ {
+ key: '_validate',
+ value: function () {
+ return (
+ this._data &&
+ this._data.nodes &&
+ this._data.links &&
+ this._data.nodes.length > 0 &&
+ this._data.links.length > 0
+ );
+ },
+ },
+ {
+ key: '_setLinkGradient',
+ value: function () {
+ var t = this,
+ e = this._svgLink
+ .append('linearGradient')
+ .attr('id', function (t) {
+ return (t.uid = 'link-'.concat(t.index, '-').concat(Math.random()));
+ })
+ .attr('gradientUnits', 'userSpaceOnUse')
+ .attr('x1', function (t) {
+ return t.source.x1;
+ })
+ .attr('x2', function (t) {
+ return t.target.x0;
+ });
+ e
+ .append('stop')
+ .attr('offset', '0%')
+ .attr('stop-color', function (e) {
+ return t._color(e.source);
+ }),
+ e
+ .append('stop')
+ .attr('offset', '100%')
+ .attr('stop-color', function (e) {
+ return t._color(e.target);
+ });
+ },
+ },
+ {
+ key: '_setLinkStroke',
+ value: function (t) {
+ switch (this._edgeColor) {
+ case X:
+ return '#aaa';
+ case Y:
+ return 'url(#'.concat(t.uid, ')');
+ case $:
+ return this._color(t.source);
+ case tt:
+ return this._color(t.target);
+ default:
+ return;
+ }
+ },
+ },
+ {
+ key: '_showLinks',
+ value: function (t) {
+ var e = [];
+ [
+ { linkType: 'sourceLinks', nodeType: 'target' },
+ { linkType: 'targetLinks', nodeType: 'source' },
+ ].forEach(function (n) {
+ t[n.linkType].forEach(function (t) {
+ e.push(t[n.nodeType]);
+ });
+ }),
+ this._gBound.selectAll('.sankey-node').style('opacity', function (n) {
+ return t.name === n.name ||
+ e.find(function (t) {
+ return t.name === n.name;
+ })
+ ? '1'
+ : '0.2';
+ }),
+ this._gBound.selectAll('.sankey-link').style('opacity', function (e) {
+ return !e || (e.source.name !== t.name && e.target.name !== t.name) ? '0.2' : '1';
+ });
+ },
+ },
+ {
+ key: '_showAll',
+ value: function () {
+ this._gBound.selectAll('.sankey-node').style('opacity', '1'),
+ this._gBound.selectAll('.sankey-link').style('opacity', '1');
+ },
+ },
+ {
+ key: '_formatValue',
+ value: function (t) {
+ return c.format('.2~f')(t);
+ },
+ },
+ {
+ key: '_formatPercent',
+ value: function (t) {
+ return c.format('.2~%')(t);
+ },
+ },
+ {
+ key: '_formatThousand',
+ value: function (t) {
+ return c.format('.3~s')(t);
+ },
+ },
+ {
+ key: '_labelNodeValue',
+ value: function (t) {
+ var e = this._nodes.filter(function (e) {
+ return e.depth === t.depth;
+ }),
+ n = c.sum(e, function (t) {
+ return t.value;
+ }),
+ r = this._formatThousand(t.value),
+ o = this._formatPercent(t.value / n),
+ i = '';
+ switch (this._displayValues) {
+ case Z:
+ i = ''.concat(r);
+ break;
+ case Q:
+ i = ''.concat(o);
+ break;
+ case K:
+ i = ''.concat(o, ' - ').concat(r);
+ }
+ return i;
+ },
+ },
+ {
+ key: '_renderSVG',
+ value: function () {
+ var t = this;
+ this._container.style('background-color', this._background),
+ (this._gBound = this._container
+ .append('g')
+ .attr('transform', 'translate('.concat(this._marginLeft, ', ').concat(this._marginTop, ')'))),
+ (this._svgNode = this._gBound
+ .append('g')
+ .attr('stroke', '#000')
+ .selectAll('.sankey-node')
+ .data(this._nodes, function (t) {
+ return t.name;
+ })
+ .join('rect')
+ .attr('class', 'sankey-node')
+ .attr('id', function (t) {
+ return t.name;
+ })
+ .attr('x', function (t) {
+ return t.x0;
+ })
+ .attr('y', function (t) {
+ return t.y0;
+ })
+ .attr('rx', 2)
+ .attr('ry', 2)
+ .attr('height', function (t) {
+ return t.y1 - t.y0;
+ })
+ .attr('width', function (t) {
+ return t.x1 - t.x0;
+ })
+ .attr('stroke', function (e) {
+ var n = JSON.parse(t._colorArray);
+ return Object.keys(n).includes(e.name) ? n[e.name] : 'rgba(148, 153, 168, 1)';
+ })
+ .attr('fill', function (e) {
+ var n = JSON.parse(t._colorArray);
+ return Object.keys(n).includes(e.name) ? n[e.name] : 'rgba(148, 153, 168, 1)';
+ })
+ .on('mouseover', function (e) {
+ var n;
+ return (
+ t._highlightOnHover &&
+ t._showLinks(null === (n = e.target) || void 0 === n ? void 0 : n.__data__)
+ );
+ })
+ .on('mouseout', function (e) {
+ return t._highlightOnHover && t._showAll();
+ })),
+ (this._svgLink = this._gBound
+ .append('g')
+ .attr('fill', 'none')
+ .attr('stroke-opacity', 0.3)
+ .selectAll('g')
+ .data(this._links, function (t) {
+ return ''.concat(t.source.name, '-').concat(t.target.name);
+ })
+ .join('g')
+ .style('mix-blend-mode', 'multiply')),
+ 'path' === this._edgeColor && this._setLinkGradient(),
+ this._svgLink
+ .append('path')
+ .attr('class', 'sankey-link')
+ .attr('d', q())
+ .attr('stroke', 'rgba(182, 185, 196, 1)')
+ .attr('stroke-width', function (t) {
+ return Math.max(1, t.width);
+ }),
+ this._gBound
+ .append('g')
+ .attr('font-family', 'sans-serif')
+ .attr('font-size', 10)
+ .selectAll('text')
+ .data(this._nodes)
+ .join('text')
+ .attr('x', function (t) {
+ return t.x0 + 8;
+ })
+ .attr('y', function (t) {
+ return (t.y1 + t.y0) / 2;
+ })
+ .attr('dy', '0.35em')
+ .text(function (t) {
+ return t.name;
+ }),
+ this._gBound
+ .append('g')
+ .attr('font-family', 'sans-serif')
+ .attr('font-size', 10)
+ .selectAll('text')
+ .data(this._nodes)
+ .join('text')
+ .attr('x', function (t) {
+ return t.x0 + 8;
+ })
+ .attr('font-size', 14)
+ .attr('font-weight', '700')
+ .attr('y', function (t) {
+ return (t.y1 + t.y0) / 2 + 16;
+ })
+ .attr('dy', '0.35em')
+ .text(function (e) {
+ return t._labelNodeValue(e);
+ }),
+ this._svgNode.append('title').text(function (e) {
+ return ''.concat(e.name, '\n').concat(t._formatValue(e.value));
+ }),
+ this._svgLink.append('title').text(function (e) {
+ return ''
+ .concat(e.source.name, ' → ')
+ .concat(e.target.name, '\n')
+ .concat(t._formatValue(e.value));
+ });
+ },
+ },
+ {
+ key: 'data',
+ value: function (t) {
+ return arguments.length ? ((this._data = t), this) : this._data;
+ },
+ },
+ {
+ key: 'width',
+ value: function (t) {
+ return arguments.length ? ((this._width = +t), this) : this._width;
+ },
+ },
+ {
+ key: 'height',
+ value: function (t) {
+ return arguments.length ? ((this._height = +t), this) : this._height;
+ },
+ },
+ {
+ key: 'align',
+ value: function (t) {
+ return arguments.length ? ((this._sankeyAlignType = t), this) : this._sankeyAlignType;
+ },
+ },
+ {
+ key: 'colorScheme',
+ value: function (t) {
+ return arguments.length ? ((this._colorScheme = t), this) : this._colorScheme;
+ },
+ },
+ {
+ key: 'colorArray',
+ value: function (t) {
+ return arguments.length ? ((this._colorArray = t), this) : this._colorArray;
+ },
+ },
+ {
+ key: 'edgeColor',
+ value: function (t) {
+ return arguments.length ? ((this._edgeColor = t), this) : this._edgeColor;
+ },
+ },
+ {
+ key: 'displayValues',
+ value: function (t) {
+ return arguments.length ? ((this._displayValues = t), this) : this._displayValues;
+ },
+ },
+ {
+ key: 'highlightOnHover',
+ value: function (t) {
+ return arguments.length ? ((this._highlightOnHover = t), this) : this._highlightOnHover;
+ },
+ },
+ {
+ key: 'render',
+ value: function () {
+ return this._validate() && (this._init(), this._renderSVG()), this;
+ },
+ },
+ ]) && U(e.prototype, n),
+ o && U(e, o),
+ t
+ );
+ })(),
+ nt = n(3),
+ rt = function (t) {
+ var e = t.message;
+ return l.a.createElement(
+ 'p',
+ { style: ot },
+ l.a.createElement(
+ 'div',
+ { style: it },
+ l.a.createElement(nt.Icon, { name: 'exclamation-triangle' }),
+ l.a.createElement('div', { style: at }, e)
+ )
+ );
+ },
+ ot = { height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' },
+ it = {
+ padding: '15px 20px',
+ marginBottom: '4px',
+ position: 'relative',
+ color: 'rgb(255, 255, 255)',
+ textShadow: 'rgb(0 0 0 / 20%) 0px 1px 0px',
+ borderRadius: '3px',
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ background: 'linear-gradient(90deg, rgb(224, 47, 68), rgb(224, 47, 68))',
+ },
+ at = { marginLeft: 10 },
+ st = (function (t) {
+ void 0 === t && (t = !0);
+ if (!t)
+ return {
+ warn: function () {
+ for (var t = [], e = 0; e < arguments.length; e++) t[e] = arguments[e];
+ },
+ error: function () {
+ for (var t = [], e = 0; e < arguments.length; e++) t[e] = arguments[e];
+ },
+ log: function () {
+ for (var t = [], e = 0; e < arguments.length; e++) t[e] = arguments[e];
+ },
+ };
+ return { warn: console.warn, error: console.error, log: console.log };
+ })();
+ var ut = function (t) {
+ var e = t.options,
+ n = t.data,
+ r = t.width,
+ o = t.height,
+ i = { source: 'source', target: 'target', value: 'value' },
+ a = 'Required fields not present: ' + Object.keys(i).join(', '),
+ f = s(Object(u.useState)({ isError: !1, message: '' }), 2),
+ h = f[0],
+ d = f[1],
+ y = s(Object(u.useState)({ nodes: [], links: [] }), 2),
+ g = y[0],
+ p = y[1];
+ Object(u.useEffect)(
+ function () {
+ n.error && st.warn('[FN] Sankey data error.', { data: n, error: n.error }),
+ n.error ? d({ isError: !0, message: n.error.message }) : p(_());
+ },
+ [n]
+ );
+ var _ = function () {
+ var t = n.series[0],
+ e = t.fields.find(function (t) {
+ return t.name === i.source;
+ }),
+ r = t.fields.find(function (t) {
+ return t.name === i.target;
+ }),
+ o = t.fields.find(function (t) {
+ return t.name === i.value;
+ }),
+ s = null == e ? void 0 : e.values.toArray(),
+ u = null == r ? void 0 : r.values.toArray(),
+ l = null == o ? void 0 : o.values.toArray();
+ if (
+ (function (t, e, n) {
+ var r = !0;
+ if (!(t && e && n)) return d({ isError: !0, message: a }), !1;
+ var o = t.every(function (t) {
+ return 'string' == typeof t;
+ }),
+ i = e.every(function (t) {
+ return 'string' == typeof t;
+ }),
+ s = n.every(function (t) {
+ return 'number' == typeof t;
+ });
+ return o && i && s
+ ? (d({}), r)
+ : (d({
+ isError: !0,
+ message:
+ 'Fields should have the following types: source (string), target (string), value (numeric)',
+ }),
+ !1);
+ })(s, u, l)
+ ) {
+ var f = c.zip(s, u, l);
+ return {
+ nodes: Array.from(new Set(s.concat(u))).map(function (t) {
+ return { name: t };
+ }),
+ links: f.map(function (t) {
+ return { source: t[0], target: t[1], value: +t[2].toFixed(2) };
+ }),
+ };
+ }
+ },
+ v = function (t) {
+ var n = new et(t)
+ .width(r)
+ .height(o)
+ .align(e.align)
+ .edgeColor(e.edgeColor)
+ .colorScheme(e.colorScheme)
+ .displayValues(e.displayValues)
+ .highlightOnHover(e.highlightOnHover)
+ .colorArray(e.colorArray)
+ .data(g);
+ try {
+ n.render();
+ } catch (t) {
+ st.warn('[FN] Sankey render error.', { renderError: t, graph: g }),
+ d({ isError: !0, message: t.message });
+ }
+ };
+ return h.isError
+ ? l.a.createElement(rt, { message: h.message })
+ : l.a.createElement('svg', {
+ viewBox: '0 0 ' + r + ' ' + o,
+ ref: function (t) {
+ c.select(t).selectAll('*').remove(), c.select(t).call(v);
+ },
+ });
+ };
+ function lt() {
+ return function (t) {
+ var e = t.series,
+ n = a(t, ['series']),
+ r = e.map(function (t) {
+ return Object(o.toDataFrame)(
+ i(i({}, t), {
+ fields: t.fields.map(function (t, e, n) {
+ var r,
+ a = ct.includes(t.name),
+ s =
+ t.values instanceof o.ArrayVector ||
+ 'function' == typeof (null === (r = t.values) || void 0 === r ? void 0 : r.toArray),
+ u = Array.isArray(t.values);
+ if (!a || !t.values || (!u && !s)) return t;
+ var l = s ? t.values.toArray() : u ? t.values : null;
+ if (null === l)
+ return (
+ st.warn('[FN] Failed to transform sankey data.', 'Values are not an array.'),
+ i(i({}, t), { values: new o.ArrayVector([]) })
+ );
+ var c = a
+ ? l
+ .map(function (t) {
+ return 'string' == typeof t ? t.split('|') : t;
+ })[0]
+ .map(function (t, e, n) {
+ return Number.isNaN(Number(t)) ? t : Number(t);
+ })
+ : null;
+ try {
+ return i(i({}, t), {
+ type: (
+ null == c
+ ? void 0
+ : c.every(function (t) {
+ return 'number' == typeof t;
+ })
+ )
+ ? o.FieldType.number
+ : t.type,
+ values: c ? new o.ArrayVector(JSON.parse(JSON.stringify(c))) : l,
+ });
+ } catch (e) {
+ return (
+ st.warn('[FN] Failed to transform sankey data.', e instanceof Error ? e.message : String(e)),
+ i(i({}, t), { type: t.type, values: new o.ArrayVector([]) })
+ );
+ }
+ }),
+ })
+ );
+ });
+ return i({ series: r }, n);
+ };
+ }
+ var ct = ['source', 'target', 'value'];
+ n.d(e, 'plugin', function () {
+ return ft;
+ });
+ var ft = new o.PanelPlugin(function (t) {
+ var e = t.data,
+ n = a(t, ['data']),
+ r = Object(u.useMemo)(lt, []),
+ o = Object(u.useMemo)(
+ function () {
+ return r(e);
+ },
+ [r, e]
+ );
+ return l.a.createElement(ut, i({}, i(i({}, n), { data: o })));
+ }).setPanelOptions(function (t) {
+ return t
+ .addSelect({
+ path: 'align',
+ name: 'Align',
+ defaultValue: 'Justify',
+ settings: {
+ options: [
+ { value: 'Justify', label: 'Justify' },
+ { value: 'Left', label: 'Left' },
+ { value: 'Right', label: 'Right' },
+ { value: 'Center', label: 'Center' },
+ ],
+ },
+ })
+ .addTextInput({ path: 'colorArray', name: 'Color Object', defaultValue: '' })
+ .addSelect({
+ path: 'colorScheme',
+ name: 'Color',
+ defaultValue: 'Tableau10',
+ settings: {
+ options: [
+ { value: 'Tableau10', label: 'Tableau10' },
+ { value: 'Category10', label: 'Category10' },
+ { value: 'Accent', label: 'Accent' },
+ { value: 'Dark2', label: 'Dark2' },
+ { value: 'Paired', label: 'Paired' },
+ { value: 'Pastel1', label: 'Pastel1' },
+ { value: 'Pastel2', label: 'Pastel2' },
+ { value: 'Set1', label: 'Set1' },
+ { value: 'Set2', label: 'Set2' },
+ { value: 'Set3', label: 'Set3' },
+ ],
+ },
+ })
+ .addSelect({
+ path: 'edgeColor',
+ name: 'Edge Color',
+ defaultValue: 'path',
+ settings: {
+ options: [
+ { value: 'path', label: 'input-output' },
+ { value: 'input', label: 'input' },
+ { value: 'output', label: 'output' },
+ { value: 'none', label: 'none' },
+ ],
+ },
+ })
+ .addSelect({
+ path: 'displayValues',
+ name: 'Display Values',
+ defaultValue: 'none',
+ settings: {
+ options: [
+ { value: 'total', label: 'Totals' },
+ { value: 'percentage', label: 'Percentages' },
+ { value: 'both', label: 'Both' },
+ { value: 'none', label: 'None' },
+ ],
+ },
+ })
+ .addBooleanSwitch({
+ path: 'highlightOnHover',
+ name: 'Highlight connections on node hover',
+ defaultValue: !1,
+ });
+ });
+ },
+ ]);
+});
+//# sourceMappingURL=module.js.map
diff --git a/public/app/plugins/panel/sankey-panel-0.5.0/module.js.LICENSE.txt b/public/app/plugins/panel/sankey-panel-0.5.0/module.js.LICENSE.txt
new file mode 100644
index 0000000000000..c18ab1d93b2fc
--- /dev/null
+++ b/public/app/plugins/panel/sankey-panel-0.5.0/module.js.LICENSE.txt
@@ -0,0 +1,14 @@
+/*! *****************************************************************************
+Copyright (c) Microsoft Corporation.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+***************************************************************************** */
diff --git a/public/app/plugins/panel/sankey-panel-0.5.0/module.js.map b/public/app/plugins/panel/sankey-panel-0.5.0/module.js.map
new file mode 100644
index 0000000000000..8e5cb8a5eab5a
--- /dev/null
+++ b/public/app/plugins/panel/sankey-panel-0.5.0/module.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///external \"react\"","webpack:///external \"d3\"","webpack:///external \"@grafana/data\"","webpack:///external \"@grafana/ui\"","webpack:///../node_modules/tslib/tslib.es6.js","webpack:///../node_modules/d3-sankey/node_modules/d3-array/src/sum.js","webpack:///../node_modules/d3-sankey/node_modules/d3-array/src/max.js","webpack:///../node_modules/d3-sankey/node_modules/d3-array/src/min.js","webpack:///../node_modules/d3-sankey/src/align.js","webpack:///../node_modules/d3-sankey/src/constant.js","webpack:///../node_modules/d3-sankey/src/sankey.js","webpack:///../node_modules/d3-path/src/path.js","webpack:///../node_modules/d3-shape/src/array.js","webpack:///../node_modules/d3-shape/src/constant.js","webpack:///../node_modules/d3-shape/src/point.js","webpack:///../node_modules/d3-shape/src/link/index.js","webpack:///../node_modules/d3-sankey/src/sankeyLinkHorizontal.js","webpack:///./Sankey.js","webpack:///./Error.tsx","webpack:///./fn-logger.ts","webpack:///./SankeyPanel.tsx","webpack:///./transform-fn-data.ts","webpack:///./module.ts","webpack:///./SankeyPanelFn.tsx"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","__WEBPACK_EXTERNAL_MODULE__0__","__WEBPACK_EXTERNAL_MODULE__1__","__WEBPACK_EXTERNAL_MODULE__2__","__WEBPACK_EXTERNAL_MODULE__3__","__assign","assign","arguments","length","apply","this","__rest","e","indexOf","getOwnPropertySymbols","propertyIsEnumerable","__read","iterator","ar","next","done","push","error","sum","values","valueof","undefined","index","max","min","targetDepth","target","depth","left","node","right","height","justify","sourceLinks","center","targetLinks","constant","x","ascendingSourceBreadth","a","b","ascendingBreadth","source","ascendingTargetBreadth","y0","defaultId","defaultNodes","graph","nodes","defaultLinks","links","find","nodeById","id","Error","computeLinkBreadths","y1","link","width","py","sort","linkSort","x0","x1","dx","dy","align","iterations","sankey","computeNodeLinks","computeNodeValues","computeNodeDepths","computeNodeHeights","computeNodeBreadths","entries","Map","map","fixedValue","Math","current","Set","size","add","columns","kx","Array","floor","layer","column","computeNodeLayers","ky","y","reorderLinks","initializeNodeBreadths","alpha","pow","beta","relaxRightToLeft","relaxLeftToRight","w","v","targetTop","reorderNodeLinks","resolveCollisions","sourceTop","subject","resolveCollisionsBottomToTop","resolveCollisionsTopToBottom","update","nodeId","_","nodeAlign","nodeSort","nodeWidth","nodePadding","extent","pi","PI","tau","tauEpsilon","Path","_x0","_y0","_x1","_y1","path","constructor","moveTo","closePath","lineTo","quadraticCurveTo","bezierCurveTo","x2","y2","arcTo","x21","y21","x01","y01","l01_2","abs","x20","y20","l21_2","l20_2","l21","sqrt","l01","tan","acos","t01","t21","arc","a0","a1","ccw","cos","sin","cw","da","rect","h","toString","slice","linkSource","linkTarget","curve","context","buffer","argv","curveHorizontal","horizontalSource","horizontalTarget","DISPLAY_VALUES","EDGE_COLORS","Sankey","svg","container","_svg","_container","_gBound","_data","_nodes","_links","_width","_height","_boundedWidth","_boundedHeight","_marginTop","_marginRight","_marginBottom","_marginLeft","_background","_edgeColor","_colorScheme","_colorScale","_colorArray","_sankeyAlignType","_sankeyAlign","_sankeyGenerator","_sankeyNodeWith","_sankeyNodePadding","_svgNode","_svgLink","_displayValues","_highlightOnHover","_setBoundDimensions","_setColorScale","_configureSankey","_calculateSankey","d3","d3Sankey","sankeyData","filter","gradient","append","attr","uid","random","_color","currentNode","linkedNodes","linkType","nodeType","forEach","step","selectAll","style","linkedNode","percent","nodesAtDepth","totalAtDepth","nodeValue","_formatThousand","nodePercent","_formatPercent","label","data","join","colorArray","JSON","parse","keys","includes","on","_showLinks","__data__","_showAll","_setLinkGradient","text","_labelNodeValue","_formatValue","_validate","_init","_renderSVG","message","panelStyles","containerStyles","messageStyles","display","justifyContent","alignItems","padding","marginBottom","position","color","textShadow","borderRadius","flexDirection","background","marginLeft","logger","shouldLog","warn","log","console","fnLogger","options","CHART_REQUIRED_FIELDS","requiredFieldsMsg","isError","setError","setGraph","buildGraph","frame","series","sourceAccesor","fields","field","targetAccesor","valueAccesor","sources","toArray","targets","isValid","sourcesString","every","targetsString","valuesNumeric","validate","zip","from","concat","toFixed","chart","edgeColor","colorScheme","displayValues","highlightOnHover","render","renderError","viewBox","ref","remove","transformFnData","other","transformedSeries","__","isSankeyField","SANKEY_FIELD_NAMES","isArrayVector","isArray","parsedValues","split","Number","isNaN","type","number","stringify","err","String","props","transformFn","transformedData","setPanelOptions","builder","addSelect","defaultValue","settings","addTextInput","addBooleanSwitch"],"mappings":";0FACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QA0Df,OArDAF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,IAIjBlC,EAAoBA,EAAoBmC,EAAI,G,gBClFrDhC,EAAOD,QAAUkC,G,cCAjBjC,EAAOD,QAAUmC,G,cCAjBlC,EAAOD,QAAUoC,G,cCAjBnC,EAAOD,QAAUqC,G,8UC6BV,IAAIC,EAAW,WAQlB,OAPAA,EAAW1B,OAAO2B,QAAU,SAAkBnB,GAC1C,IAAK,IAAIa,EAAG/B,EAAI,EAAGyB,EAAIa,UAAUC,OAAQvC,EAAIyB,EAAGzB,IAE5C,IAAK,IAAI8B,KADTC,EAAIO,UAAUtC,GACOU,OAAOkB,UAAUC,eAAe1B,KAAK4B,EAAGD,KAAIZ,EAAEY,GAAKC,EAAED,IAE9E,OAAOZ,IAEKsB,MAAMC,KAAMH,YAGzB,SAASI,EAAOX,EAAGY,GACtB,IAAIzB,EAAI,GACR,IAAK,IAAIY,KAAKC,EAAOrB,OAAOkB,UAAUC,eAAe1B,KAAK4B,EAAGD,IAAMa,EAAEC,QAAQd,GAAK,IAC9EZ,EAAEY,GAAKC,EAAED,IACb,GAAS,MAALC,GAAqD,mBAAjCrB,OAAOmC,sBACtB,KAAI7C,EAAI,EAAb,IAAgB8B,EAAIpB,OAAOmC,sBAAsBd,GAAI/B,EAAI8B,EAAES,OAAQvC,IAC3D2C,EAAEC,QAAQd,EAAE9B,IAAM,GAAKU,OAAOkB,UAAUkB,qBAAqB3C,KAAK4B,EAAGD,EAAE9B,MACvEkB,EAAEY,EAAE9B,IAAM+B,EAAED,EAAE9B,KAE1B,OAAOkB,EA6EJ,SAAS6B,EAAOtC,EAAGgB,GACtB,IAAIrB,EAAsB,mBAAXW,QAAyBN,EAAEM,OAAOiC,UACjD,IAAK5C,EAAG,OAAOK,EACf,IAAmBK,EAAY6B,EAA3B3C,EAAII,EAAED,KAAKM,GAAOwC,EAAK,GAC3B,IACI,WAAc,IAANxB,GAAgBA,KAAM,MAAQX,EAAId,EAAEkD,QAAQC,MAAMF,EAAGG,KAAKtC,EAAEG,OAExE,MAAOoC,GAASV,EAAI,CAAEU,MAAOA,GAC7B,QACI,IACQvC,IAAMA,EAAEqC,OAAS/C,EAAIJ,EAAU,SAAII,EAAED,KAAKH,GAElD,QAAU,GAAI2C,EAAG,MAAMA,EAAEU,OAE7B,OAAOJ,E,2BC5II,SAASK,EAAIC,EAAQC,GAClC,IAAIF,EAAM,EACV,QAAgBG,IAAZD,EACF,IAAK,IAAIvC,KAASsC,GACZtC,GAASA,KACXqC,GAAOrC,OAGN,CACL,IAAIyC,GAAS,EACb,IAAK,IAAIzC,KAASsC,GACZtC,GAASuC,EAAQvC,IAASyC,EAAOH,MACnCD,GAAOrC,GAIb,OAAOqC,EChBM,SAASK,EAAIJ,EAAQC,GAClC,IAAIG,EACJ,QAAgBF,IAAZD,EACF,IAAK,MAAMvC,KAASsC,EACL,MAATtC,IACI0C,EAAM1C,QAAkBwC,IAARE,GAAqB1C,GAASA,KACpD0C,EAAM1C,OAGL,CACL,IAAIyC,GAAS,EACb,IAAK,IAAIzC,KAASsC,EACiC,OAA5CtC,EAAQuC,EAAQvC,IAASyC,EAAOH,MAC7BI,EAAM1C,QAAkBwC,IAARE,GAAqB1C,GAASA,KACpD0C,EAAM1C,GAIZ,OAAO0C,EClBM,SAASC,EAAIL,EAAQC,GAClC,IAAII,EACJ,QAAgBH,IAAZD,EACF,IAAK,MAAMvC,KAASsC,EACL,MAATtC,IACI2C,EAAM3C,QAAkBwC,IAARG,GAAqB3C,GAASA,KACpD2C,EAAM3C,OAGL,CACL,IAAIyC,GAAS,EACb,IAAK,IAAIzC,KAASsC,EACiC,OAA5CtC,EAAQuC,EAAQvC,IAASyC,EAAOH,MAC7BK,EAAM3C,QAAkBwC,IAARG,GAAqB3C,GAASA,KACpD2C,EAAM3C,GAIZ,OAAO2C,EChBT,SAASC,EAAYvD,GACnB,OAAOA,EAAEwD,OAAOC,MAGX,SAASC,EAAKC,GACnB,OAAOA,EAAKF,MAGP,SAASG,EAAMD,EAAMxC,GAC1B,OAAOA,EAAI,EAAIwC,EAAKE,OAGf,SAASC,EAAQH,EAAMxC,GAC5B,OAAOwC,EAAKI,YAAY9B,OAAS0B,EAAKF,MAAQtC,EAAI,EAG7C,SAAS6C,EAAOL,GACrB,OAAOA,EAAKM,YAAYhC,OAAS0B,EAAKF,MAChCE,EAAKI,YAAY9B,OAASqB,EAAIK,EAAKI,YAAaR,GAAe,EAC/D,ECrBO,SAASW,EAASC,GAC/B,OAAO,WACL,OAAOA,GCEX,SAASC,EAAuBC,EAAGC,GACjC,OAAOC,EAAiBF,EAAEG,OAAQF,EAAEE,SAAWH,EAAEjB,MAAQkB,EAAElB,MAG7D,SAASqB,EAAuBJ,EAAGC,GACjC,OAAOC,EAAiBF,EAAEb,OAAQc,EAAEd,SAAWa,EAAEjB,MAAQkB,EAAElB,MAG7D,SAASmB,EAAiBF,EAAGC,GAC3B,OAAOD,EAAEK,GAAKJ,EAAEI,GAGlB,SAAS,EAAM1E,GACb,OAAOA,EAAEW,MAGX,SAASgE,EAAU3E,GACjB,OAAOA,EAAEoD,MAGX,SAASwB,EAAaC,GACpB,OAAOA,EAAMC,MAGf,SAASC,EAAaF,GACpB,OAAOA,EAAMG,MAGf,SAASC,EAAKC,EAAUC,GACtB,MAAMxB,EAAOuB,EAAS3E,IAAI4E,GAC1B,IAAKxB,EAAM,MAAM,IAAIyB,MAAM,YAAcD,GACzC,OAAOxB,EAGT,SAAS0B,GAAoB,MAACP,IAC5B,IAAK,MAAMnB,KAAQmB,EAAO,CACxB,IAAIJ,EAAKf,EAAKe,GACVY,EAAKZ,EACT,IAAK,MAAMa,KAAQ5B,EAAKI,YACtBwB,EAAKb,GAAKA,EAAKa,EAAKC,MAAQ,EAC5Bd,GAAMa,EAAKC,MAEb,IAAK,MAAMD,KAAQ5B,EAAKM,YACtBsB,EAAKD,GAAKA,EAAKC,EAAKC,MAAQ,EAC5BF,GAAMC,EAAKC,OAKF,SAAS,IACtB,IAEYC,EAGRC,EACAC,EANAC,EAAK,EAAGlB,EAAK,EAAGmB,EAAK,EAAGP,EAAK,EAC7BQ,EAAK,GACLC,EAAK,EACLZ,EAAKR,EACLqB,EAAQlC,EAGRgB,EAAQF,EACRI,EAAQD,EACRkB,EAAa,EAEjB,SAASC,IACP,MAAMrB,EAAQ,CAACC,MAAOA,EAAM5C,MAAM,KAAMF,WAAYgD,MAAOA,EAAM9C,MAAM,KAAMF,YAO7E,OANAmE,EAAiBtB,GACjBuB,EAAkBvB,GAClBwB,EAAkBxB,GAClByB,EAAmBzB,GACnB0B,EAAoB1B,GACpBQ,EAAoBR,GACbA,EAoDT,SAASsB,GAAiB,MAACrB,EAAK,MAAEE,IAChC,IAAK,MAAOtF,EAAGiE,KAASmB,EAAM0B,UAC5B7C,EAAKP,MAAQ1D,EACbiE,EAAKI,YAAc,GACnBJ,EAAKM,YAAc,GAErB,MAAMiB,EAAW,IAAIuB,IAAI3B,EAAM4B,IAAI,CAAC1G,EAAGN,IAAM,CAACyF,EAAGnF,EAAGN,EAAGoF,GAAQ9E,KAC/D,IAAK,MAAON,EAAG6F,KAASP,EAAMwB,UAAW,CACvCjB,EAAKnC,MAAQ1D,EACb,IAAI,OAAC8E,EAAM,OAAEhB,GAAU+B,EACD,iBAAXf,IAAqBA,EAASe,EAAKf,OAASS,EAAKC,EAAUV,IAChD,iBAAXhB,IAAqBA,EAAS+B,EAAK/B,OAASyB,EAAKC,EAAU1B,IACtEgB,EAAOT,YAAYjB,KAAKyC,GACxB/B,EAAOS,YAAYnB,KAAKyC,GAE1B,GAAgB,MAAZI,EACF,IAAK,MAAM,YAAC5B,EAAW,YAAEE,KAAgBa,EACvCf,EAAY2B,KAAKC,GACjB1B,EAAYyB,KAAKC,GAKvB,SAASS,GAAkB,MAACtB,IAC1B,IAAK,MAAMnB,KAAQmB,EACjBnB,EAAKhD,WAA4BwC,IAApBQ,EAAKgD,WACZC,KAAKvD,IAAIL,EAAIW,EAAKI,YAAa,GAAQf,EAAIW,EAAKM,YAAa,IAC7DN,EAAKgD,WAIf,SAASN,GAAkB,MAACvB,IAC1B,MAAM3D,EAAI2D,EAAM7C,OAChB,IAAI4E,EAAU,IAAIC,IAAIhC,GAClBlC,EAAO,IAAIkE,IACX3C,EAAI,EACR,KAAO0C,EAAQE,MAAM,CACnB,IAAK,MAAMpD,KAAQkD,EAAS,CAC1BlD,EAAKF,MAAQU,EACb,IAAK,MAAM,OAACX,KAAWG,EAAKI,YAC1BnB,EAAKoE,IAAIxD,GAGb,KAAMW,EAAIhD,EAAG,MAAM,IAAIiE,MAAM,iBAC7ByB,EAAUjE,EACVA,EAAO,IAAIkE,KAIf,SAASR,GAAmB,MAACxB,IAC3B,MAAM3D,EAAI2D,EAAM7C,OAChB,IAAI4E,EAAU,IAAIC,IAAIhC,GAClBlC,EAAO,IAAIkE,IACX3C,EAAI,EACR,KAAO0C,EAAQE,MAAM,CACnB,IAAK,MAAMpD,KAAQkD,EAAS,CAC1BlD,EAAKE,OAASM,EACd,IAAK,MAAM,OAACK,KAAWb,EAAKM,YAC1BrB,EAAKoE,IAAIxC,GAGb,KAAML,EAAIhD,EAAG,MAAM,IAAIiE,MAAM,iBAC7ByB,EAAUjE,EACVA,EAAO,IAAIkE,KA4Cf,SAASP,EAAoB1B,GAC3B,MAAMoC,EAzCR,UAA2B,MAACnC,IAC1B,MAAMX,EAAId,EAAIyB,EAAO9E,GAAKA,EAAEyD,OAAS,EAC/ByD,GAAMrB,EAAKD,EAAKE,IAAO3B,EAAI,GAC3B8C,EAAU,IAAIE,MAAMhD,GAC1B,IAAK,MAAMR,KAAQmB,EAAO,CACxB,MAAMpF,EAAIkH,KAAKvD,IAAI,EAAGuD,KAAKtD,IAAIa,EAAI,EAAGyC,KAAKQ,MAAMpB,EAAMnG,KAAK,KAAM8D,EAAMQ,MACxER,EAAK0D,MAAQ3H,EACbiE,EAAKiC,GAAKA,EAAKlG,EAAIwH,EACnBvD,EAAKkC,GAAKlC,EAAKiC,GAAKE,EAChBmB,EAAQvH,GAAIuH,EAAQvH,GAAGoD,KAAKa,GAC3BsD,EAAQvH,GAAK,CAACiE,GAErB,GAAI+B,EAAM,IAAK,MAAM4B,KAAUL,EAC7BK,EAAO5B,KAAKA,GAEd,OAAOuB,EA0BSM,CAAkB1C,GAClCY,EAAKmB,KAAKtD,IAAIyC,GAAKT,EAAKZ,IAAOrB,EAAI4D,EAASlH,GAAKA,EAAEkC,QAAU,IAxB/D,SAAgCgF,GAC9B,MAAMO,EAAKlE,EAAI2D,EAASlH,IAAMuF,EAAKZ,GAAM3E,EAAEkC,OAAS,GAAKwD,GAAMzC,EAAIjD,EAAG,IACtE,IAAK,MAAM+E,KAASmC,EAAS,CAC3B,IAAIQ,EAAI/C,EACR,IAAK,MAAMf,KAAQmB,EAAO,CACxBnB,EAAKe,GAAK+C,EACV9D,EAAK2B,GAAKmC,EAAI9D,EAAKhD,MAAQ6G,EAC3BC,EAAI9D,EAAK2B,GAAKG,EACd,IAAK,MAAMF,KAAQ5B,EAAKI,YACtBwB,EAAKC,MAAQD,EAAK5E,MAAQ6G,EAG9BC,GAAKnC,EAAKmC,EAAIhC,IAAOX,EAAM7C,OAAS,GACpC,IAAK,IAAIvC,EAAI,EAAGA,EAAIoF,EAAM7C,SAAUvC,EAAG,CACrC,MAAMiE,EAAOmB,EAAMpF,GACnBiE,EAAKe,IAAM+C,GAAK/H,EAAI,GACpBiE,EAAK2B,IAAMmC,GAAK/H,EAAI,GAEtBgI,EAAa5C,IAOf6C,CAAuBV,GACvB,IAAK,IAAIvH,EAAI,EAAGA,EAAIuG,IAAcvG,EAAG,CACnC,MAAMkI,EAAQhB,KAAKiB,IAAI,IAAMnI,GACvBoI,EAAOlB,KAAKvD,IAAI,EAAIuE,GAAQlI,EAAI,GAAKuG,GAC3C8B,EAAiBd,EAASW,EAAOE,GACjCE,EAAiBf,EAASW,EAAOE,IAKrC,SAASE,EAAiBf,EAASW,EAAOE,GACxC,IAAK,IAAIpI,EAAI,EAAGyB,EAAI8F,EAAQhF,OAAQvC,EAAIyB,IAAKzB,EAAG,CAC9C,MAAM4H,EAASL,EAAQvH,GACvB,IAAK,MAAM8D,KAAU8D,EAAQ,CAC3B,IAAIG,EAAI,EACJQ,EAAI,EACR,IAAK,MAAM,OAACzD,EAAM,MAAE7D,KAAU6C,EAAOS,YAAa,CAChD,IAAIiE,EAAIvH,GAAS6C,EAAO6D,MAAQ7C,EAAO6C,OACvCI,GAAKU,EAAU3D,EAAQhB,GAAU0E,EACjCD,GAAKC,EAEP,KAAMD,EAAI,GAAI,SACd,IAAIlC,GAAM0B,EAAIQ,EAAIzE,EAAOkB,IAAMkD,EAC/BpE,EAAOkB,IAAMqB,EACbvC,EAAO8B,IAAMS,EACbqC,EAAiB5E,QAENL,IAATuC,GAAoB4B,EAAO5B,KAAKnB,GACpC8D,EAAkBf,EAAQQ,IAK9B,SAASC,EAAiBd,EAASW,EAAOE,GACxC,IAAK,IAAwBpI,EAAhBuH,EAAQhF,OAAgB,EAAGvC,GAAK,IAAKA,EAAG,CACnD,MAAM4H,EAASL,EAAQvH,GACvB,IAAK,MAAM8E,KAAU8C,EAAQ,CAC3B,IAAIG,EAAI,EACJQ,EAAI,EACR,IAAK,MAAM,OAACzE,EAAM,MAAE7C,KAAU6D,EAAOT,YAAa,CAChD,IAAImE,EAAIvH,GAAS6C,EAAO6D,MAAQ7C,EAAO6C,OACvCI,GAAKa,EAAU9D,EAAQhB,GAAU0E,EACjCD,GAAKC,EAEP,KAAMD,EAAI,GAAI,SACd,IAAIlC,GAAM0B,EAAIQ,EAAIzD,EAAOE,IAAMkD,EAC/BpD,EAAOE,IAAMqB,EACbvB,EAAOc,IAAMS,EACbqC,EAAiB5D,QAENrB,IAATuC,GAAoB4B,EAAO5B,KAAKnB,GACpC8D,EAAkBf,EAAQQ,IAI9B,SAASO,EAAkBvD,EAAO8C,GAChC,MAAMlI,EAAIoF,EAAM7C,QAAU,EACpBsG,EAAUzD,EAAMpF,GACtB8I,EAA6B1D,EAAOyD,EAAQ7D,GAAKe,EAAI/F,EAAI,EAAGkI,GAC5Da,EAA6B3D,EAAOyD,EAAQjD,GAAKG,EAAI/F,EAAI,EAAGkI,GAC5DY,EAA6B1D,EAAOQ,EAAIR,EAAM7C,OAAS,EAAG2F,GAC1Da,EAA6B3D,EAAOJ,EAAI,EAAGkD,GAI7C,SAASa,EAA6B3D,EAAO2C,EAAG/H,EAAGkI,GACjD,KAAOlI,EAAIoF,EAAM7C,SAAUvC,EAAG,CAC5B,MAAMiE,EAAOmB,EAAMpF,GACbqG,GAAM0B,EAAI9D,EAAKe,IAAMkD,EACvB7B,EAAK,OAAMpC,EAAKe,IAAMqB,EAAIpC,EAAK2B,IAAMS,GACzC0B,EAAI9D,EAAK2B,GAAKG,GAKlB,SAAS+C,EAA6B1D,EAAO2C,EAAG/H,EAAGkI,GACjD,KAAOlI,GAAK,IAAKA,EAAG,CAClB,MAAMiE,EAAOmB,EAAMpF,GACbqG,GAAMpC,EAAK2B,GAAKmC,GAAKG,EACvB7B,EAAK,OAAMpC,EAAKe,IAAMqB,EAAIpC,EAAK2B,IAAMS,GACzC0B,EAAI9D,EAAKe,GAAKe,GAIlB,SAAS2C,GAAiB,YAACrE,EAAW,YAAEE,IACtC,QAAiBd,IAAbwC,EAAwB,CAC1B,IAAK,MAAOnB,QAAQ,YAACT,MAAiBE,EACpCF,EAAY2B,KAAKjB,GAEnB,IAAK,MAAOjB,QAAQ,YAACS,MAAiBF,EACpCE,EAAYyB,KAAKtB,IAKvB,SAASsD,EAAa5C,GACpB,QAAiB3B,IAAbwC,EACF,IAAK,MAAM,YAAC5B,EAAW,YAAEE,KAAgBa,EACvCf,EAAY2B,KAAKjB,GACjBR,EAAYyB,KAAKtB,GAMvB,SAAS+D,EAAU3D,EAAQhB,GACzB,IAAIiE,EAAIjD,EAAOE,IAAMF,EAAOT,YAAY9B,OAAS,GAAKwD,EAAK,EAC3D,IAAK,MAAOjC,OAAQG,EAAI,MAAE6B,KAAUhB,EAAOT,YAAa,CACtD,GAAIJ,IAASH,EAAQ,MACrBiE,GAAKjC,EAAQC,EAEf,IAAK,MAAOjB,OAAQb,EAAI,MAAE6B,KAAUhC,EAAOS,YAAa,CACtD,GAAIN,IAASa,EAAQ,MACrBiD,GAAKjC,EAEP,OAAOiC,EAIT,SAASa,EAAU9D,EAAQhB,GACzB,IAAIiE,EAAIjE,EAAOkB,IAAMlB,EAAOS,YAAYhC,OAAS,GAAKwD,EAAK,EAC3D,IAAK,MAAOjB,OAAQb,EAAI,MAAE6B,KAAUhC,EAAOS,YAAa,CACtD,GAAIN,IAASa,EAAQ,MACrBiD,GAAKjC,EAAQC,EAEf,IAAK,MAAOjC,OAAQG,EAAI,MAAE6B,KAAUhB,EAAOT,YAAa,CACtD,GAAIJ,IAASH,EAAQ,MACrBiE,GAAKjC,EAEP,OAAOiC,EAGT,OAnSAvB,EAAOwC,OAAS,SAAS7D,GAEvB,OADAQ,EAAoBR,GACbA,GAGTqB,EAAOyC,OAAS,SAASC,GACvB,OAAO5G,UAAUC,QAAUkD,EAAkB,mBAANyD,EAAmBA,EAAI1E,EAAS0E,GAAI1C,GAAUf,GAGvFe,EAAO2C,UAAY,SAASD,GAC1B,OAAO5G,UAAUC,QAAU+D,EAAqB,mBAAN4C,EAAmBA,EAAI1E,EAAS0E,GAAI1C,GAAUF,GAG1FE,EAAO4C,SAAW,SAASF,GACzB,OAAO5G,UAAUC,QAAUyD,EAAOkD,EAAG1C,GAAUR,GAGjDQ,EAAO6C,UAAY,SAASH,GAC1B,OAAO5G,UAAUC,QAAU6D,GAAM8C,EAAG1C,GAAUJ,GAGhDI,EAAO8C,YAAc,SAASJ,GAC5B,OAAO5G,UAAUC,QAAU8D,EAAKN,GAAMmD,EAAG1C,GAAUH,GAGrDG,EAAOpB,MAAQ,SAAS8D,GACtB,OAAO5G,UAAUC,QAAU6C,EAAqB,mBAAN8D,EAAmBA,EAAI1E,EAAS0E,GAAI1C,GAAUpB,GAG1FoB,EAAOlB,MAAQ,SAAS4D,GACtB,OAAO5G,UAAUC,QAAU+C,EAAqB,mBAAN4D,EAAmBA,EAAI1E,EAAS0E,GAAI1C,GAAUlB,GAG1FkB,EAAOP,SAAW,SAASiD,GACzB,OAAO5G,UAAUC,QAAU0D,EAAWiD,EAAG1C,GAAUP,GAGrDO,EAAOa,KAAO,SAAS6B,GACrB,OAAO5G,UAAUC,QAAU2D,EAAKlB,EAAK,EAAGmB,GAAM+C,EAAE,GAAItD,GAAMsD,EAAE,GAAI1C,GAAU,CAACL,EAAKD,EAAIN,EAAKZ,IAG3FwB,EAAO+C,OAAS,SAASL,GACvB,OAAO5G,UAAUC,QAAU2D,GAAMgD,EAAE,GAAG,GAAI/C,GAAM+C,EAAE,GAAG,GAAIlE,GAAMkE,EAAE,GAAG,GAAItD,GAAMsD,EAAE,GAAG,GAAI1C,GAAU,CAAC,CAACN,EAAIlB,GAAK,CAACmB,EAAIP,KAGnHY,EAAOD,WAAa,SAAS2C,GAC3B,OAAO5G,UAAUC,QAAUgE,GAAc2C,EAAG1C,GAAUD,GAqPjDC,EC/WT,IAAIgD,EAAKtC,KAAKuC,GACVC,EAAM,EAAIF,EAEVG,EAAaD,EADH,KAGd,SAASE,IACPnH,KAAKoH,IAAMpH,KAAKqH,IAChBrH,KAAKsH,IAAMtH,KAAKuH,IAAM,KACtBvH,KAAKyG,EAAI,GAGX,SAASe,IACP,OAAO,IAAIL,EAGbA,EAAKhI,UAAYqI,EAAKrI,UAAY,CAChCsI,YAAaN,EACbO,OAAQ,SAAS1F,EAAGsD,GAClBtF,KAAKyG,GAAK,KAAOzG,KAAKoH,IAAMpH,KAAKsH,KAAOtF,GAAK,KAAOhC,KAAKqH,IAAMrH,KAAKuH,KAAOjC,IAE7EqC,UAAW,WACQ,OAAb3H,KAAKsH,MACPtH,KAAKsH,IAAMtH,KAAKoH,IAAKpH,KAAKuH,IAAMvH,KAAKqH,IACrCrH,KAAKyG,GAAK,MAGdmB,OAAQ,SAAS5F,EAAGsD,GAClBtF,KAAKyG,GAAK,KAAOzG,KAAKsH,KAAOtF,GAAK,KAAOhC,KAAKuH,KAAOjC,IAEvDuC,iBAAkB,SAASnE,EAAIP,EAAInB,EAAGsD,GACpCtF,KAAKyG,GAAK,MAAQ/C,EAAM,MAAQP,EAAM,KAAOnD,KAAKsH,KAAOtF,GAAK,KAAOhC,KAAKuH,KAAOjC,IAEnFwC,cAAe,SAASpE,EAAIP,EAAI4E,EAAIC,EAAIhG,EAAGsD,GACzCtF,KAAKyG,GAAK,MAAQ/C,EAAM,MAAQP,EAAM,MAAQ4E,EAAM,MAAQC,EAAM,KAAOhI,KAAKsH,KAAOtF,GAAK,KAAOhC,KAAKuH,KAAOjC,IAE/G2C,MAAO,SAASvE,EAAIP,EAAI4E,EAAIC,EAAI3J,GAC9BqF,GAAMA,EAAIP,GAAMA,EAAI4E,GAAMA,EAAIC,GAAMA,EAAI3J,GAAKA,EAC7C,IAAIoF,EAAKzD,KAAKsH,IACV/E,EAAKvC,KAAKuH,IACVW,EAAMH,EAAKrE,EACXyE,EAAMH,EAAK7E,EACXiF,EAAM3E,EAAKC,EACX2E,EAAM9F,EAAKY,EACXmF,EAAQF,EAAMA,EAAMC,EAAMA,EAG9B,GAAIhK,EAAI,EAAG,MAAM,IAAI4E,MAAM,oBAAsB5E,GAGjD,GAAiB,OAAb2B,KAAKsH,IACPtH,KAAKyG,GAAK,KAAOzG,KAAKsH,IAAM5D,GAAM,KAAO1D,KAAKuH,IAAMpE,QAIjD,GAAMmF,EApDD,KAyDL,GAAM7D,KAAK8D,IAAIF,EAAMH,EAAMC,EAAMC,GAzD5B,MAyDgD/J,EAKrD,CACH,IAAImK,EAAMT,EAAKtE,EACXgF,EAAMT,EAAKzF,EACXmG,EAAQR,EAAMA,EAAMC,EAAMA,EAC1BQ,EAAQH,EAAMA,EAAMC,EAAMA,EAC1BG,EAAMnE,KAAKoE,KAAKH,GAChBI,EAAMrE,KAAKoE,KAAKP,GAChB9K,EAAIa,EAAIoG,KAAKsE,KAAKhC,EAAKtC,KAAKuE,MAAMN,EAAQJ,EAAQK,IAAU,EAAIC,EAAME,KAAS,GAC/EG,EAAMzL,EAAIsL,EACVI,EAAM1L,EAAIoL,EAGVnE,KAAK8D,IAAIU,EAAM,GA1EX,OA2ENjJ,KAAKyG,GAAK,KAAO/C,EAAKuF,EAAMb,GAAO,KAAOjF,EAAK8F,EAAMZ,IAGvDrI,KAAKyG,GAAK,IAAMpI,EAAI,IAAMA,EAAI,WAAagK,EAAMG,EAAMJ,EAAMK,GAAQ,KAAOzI,KAAKsH,IAAM5D,EAAKwF,EAAMhB,GAAO,KAAOlI,KAAKuH,IAAMpE,EAAK+F,EAAMf,QApBtInI,KAAKyG,GAAK,KAAOzG,KAAKsH,IAAM5D,GAAM,KAAO1D,KAAKuH,IAAMpE,UAuBxDgG,IAAK,SAASnH,EAAGsD,EAAGjH,EAAG+K,EAAIC,EAAIC,GAC7BtH,GAAKA,EAAGsD,GAAKA,EAAWgE,IAAQA,EAChC,IAAI3F,GADYtF,GAAKA,GACRoG,KAAK8E,IAAIH,GAClBxF,EAAKvF,EAAIoG,KAAK+E,IAAIJ,GAClB3F,EAAKzB,EAAI2B,EACTpB,EAAK+C,EAAI1B,EACT6F,EAAK,EAAIH,EACTI,EAAKJ,EAAMF,EAAKC,EAAKA,EAAKD,EAG9B,GAAI/K,EAAI,EAAG,MAAM,IAAI4E,MAAM,oBAAsB5E,GAGhC,OAAb2B,KAAKsH,IACPtH,KAAKyG,GAAK,IAAMhD,EAAK,IAAMlB,GAIpBkC,KAAK8D,IAAIvI,KAAKsH,IAAM7D,GAnGnB,MAmGoCgB,KAAK8D,IAAIvI,KAAKuH,IAAMhF,GAnGxD,QAoGRvC,KAAKyG,GAAK,IAAMhD,EAAK,IAAMlB,GAIxBlE,IAGDqL,EAAK,IAAGA,EAAKA,EAAKzC,EAAMA,GAGxByC,EAAKxC,EACPlH,KAAKyG,GAAK,IAAMpI,EAAI,IAAMA,EAAI,QAAUoL,EAAK,KAAOzH,EAAI2B,GAAM,KAAO2B,EAAI1B,GAAM,IAAMvF,EAAI,IAAMA,EAAI,QAAUoL,EAAK,KAAOzJ,KAAKsH,IAAM7D,GAAM,KAAOzD,KAAKuH,IAAMhF,GAIrJmH,EAnHC,OAoHR1J,KAAKyG,GAAK,IAAMpI,EAAI,IAAMA,EAAI,SAAWqL,GAAM3C,GAAO,IAAM0C,EAAK,KAAOzJ,KAAKsH,IAAMtF,EAAI3D,EAAIoG,KAAK8E,IAAIF,IAAO,KAAOrJ,KAAKuH,IAAMjC,EAAIjH,EAAIoG,KAAK+E,IAAIH,OAGlJM,KAAM,SAAS3H,EAAGsD,EAAGQ,EAAG8D,GACtB5J,KAAKyG,GAAK,KAAOzG,KAAKoH,IAAMpH,KAAKsH,KAAOtF,GAAK,KAAOhC,KAAKqH,IAAMrH,KAAKuH,KAAOjC,GAAK,MAAQQ,EAAK,MAAQ8D,EAAK,KAAQ9D,EAAK,KAEzH+D,SAAU,WACR,OAAO7J,KAAKyG,IAID,QCjIJqD,EAAQ9E,MAAM7F,UAAU2K,MCApB,cACb,OAAO,WACL,OAAO9H,ICFJ,SAAS,EAAE3C,GAChB,OAAOA,EAAE,GAGJ,SAAS,EAAEA,GAChB,OAAOA,EAAE,GCCX,SAAS0K,EAAWlM,GAClB,OAAOA,EAAEwE,OAGX,SAAS2H,EAAWnM,GAClB,OAAOA,EAAEwD,OAGX,SAAS,EAAK4I,GACZ,IAAI5H,EAAS0H,EACT1I,EAAS2I,EACThI,EAAI,EACJsD,EAAI,EACJ4E,EAAU,KAEd,SAAS9G,IACP,IAAI+G,EAAQC,EAAON,EAAMpM,KAAKmC,WAAYP,EAAI+C,EAAOtC,MAAMC,KAAMoK,GAAO3L,EAAI4C,EAAOtB,MAAMC,KAAMoK,GAG/F,GAFKF,IAASA,EAAUC,EAAS,KACjCF,EAAMC,GAAUlI,EAAEjC,MAAMC,MAAOoK,EAAK,GAAK9K,EAAG8K,KAAS9E,EAAEvF,MAAMC,KAAMoK,IAAQpI,EAAEjC,MAAMC,MAAOoK,EAAK,GAAK3L,EAAG2L,KAAS9E,EAAEvF,MAAMC,KAAMoK,IAC1HD,EAAQ,OAAOD,EAAU,KAAMC,EAAS,IAAM,KAuBpD,OApBA/G,EAAKf,OAAS,SAASoE,GACrB,OAAO5G,UAAUC,QAAUuC,EAASoE,EAAGrD,GAAQf,GAGjDe,EAAK/B,OAAS,SAASoF,GACrB,OAAO5G,UAAUC,QAAUuB,EAASoF,EAAGrD,GAAQ/B,GAGjD+B,EAAKpB,EAAI,SAASyE,GAChB,OAAO5G,UAAUC,QAAUkC,EAAiB,mBAANyE,EAAmBA,EAAI,GAAUA,GAAIrD,GAAQpB,GAGrFoB,EAAKkC,EAAI,SAASmB,GAChB,OAAO5G,UAAUC,QAAUwF,EAAiB,mBAANmB,EAAmBA,EAAI,GAAUA,GAAIrD,GAAQkC,GAGrFlC,EAAK8G,QAAU,SAASzD,GACtB,OAAO5G,UAAUC,QAAWoK,EAAe,MAALzD,EAAY,KAAOA,EAAIrD,GAAQ8G,GAGhE9G,EAGT,SAASiH,EAAgBH,EAASzG,EAAIlB,EAAImB,EAAIP,GAC5C+G,EAAQxC,OAAOjE,EAAIlB,GACnB2H,EAAQpC,cAAcrE,GAAMA,EAAKC,GAAM,EAAGnB,EAAIkB,EAAIN,EAAIO,EAAIP,GCnD5D,SAASmH,EAAiBzM,GACxB,MAAO,CAACA,EAAEwE,OAAOqB,GAAI7F,EAAE0E,IAGzB,SAASgI,EAAiB1M,GACxB,MAAO,CAACA,EAAEwD,OAAOoC,GAAI5F,EAAEsF,IAGV,iBACb,OD4DO,EAAKkH,GC3DPhI,OAAOiI,GACPjJ,OAAOkJ,I,sKCVd,IAAMC,EAA0B,QAA1BA,EAA+C,aAA/CA,EAAmE,OACnEC,EAAsB,OAAtBA,EAAoC,OAApCA,EAAmD,QAAnDA,GAAoE,SAE7DC,GAAb,WACE,WAAYC,EAAKC,I,4FAAW,SAC1B5K,KAAK6K,KAAOF,EACZ3K,KAAK8K,WAAaF,GAAaD,EAC/B3K,KAAK+K,QAAU,KAEf/K,KAAKgL,MAAQ,KACbhL,KAAKiL,OAAS,KACdjL,KAAKkL,OAAS,KAEdlL,KAAKmL,OAAS,EACdnL,KAAKoL,QAAU,EACfpL,KAAKqL,cAAgB,EACrBrL,KAAKsL,eAAiB,EAEtBtL,KAAKuL,WAAa,GAClBvL,KAAKwL,aAAe,GACpBxL,KAAKyL,cAAgB,GACrBzL,KAAK0L,YAAc,GAEnB1L,KAAK2L,YAAc,mBACnB3L,KAAK4L,WAAa,OAClB5L,KAAK6L,aAAe,YACpB7L,KAAK8L,YAAc,KACnB9L,KAAK+L,YAAc,GAEnB/L,KAAKgM,iBAAmB,UACxBhM,KAAKiM,aAAe,KACpBjM,KAAKkM,iBAAmB,KACxBlM,KAAKmM,gBAAkB,IACvBnM,KAAKoM,mBAAqB,GAE1BpM,KAAKqM,SAAW,KAChBrM,KAAKsM,SAAW,KAEhBtM,KAAKuM,eAAiB,OACtBvM,KAAKwM,mBAAoB,E,UApC7B,O,EAAA,G,EAAA,oBAwCE,WACExM,KAAKyM,sBACLzM,KAAK0M,iBACL1M,KAAK2M,mBACL3M,KAAK4M,qBA5CT,iCAiDE,WACE5M,KAAKqL,cAAgBrL,KAAKmL,OAASnL,KAAK0L,YAAc1L,KAAKwL,aAC3DxL,KAAKsL,eAAiBtL,KAAKoL,QAAUpL,KAAKuL,WAAavL,KAAKyL,gBAnDhE,4BAwDE,WACEzL,KAAK8L,YAAce,eAAgBA,EAAG,SAAD,OAAU7M,KAAK6L,kBAzDxD,oBA4DE,SAAOrK,GACL,OAAOxB,KAAK8L,YAAYtK,EAAK1D,QA7DjC,8BAkEE,WACEkC,KAAKiM,aAAea,EAAS,SAAD,OAAU9M,KAAKgM,mBAE3ChM,KAAKkM,iBAAmBY,IAErBtG,QAAO,SAAA3I,GAAC,OAAIA,EAAEC,QACd4I,UAAU1G,KAAKiM,cACfrF,UAAU5G,KAAKmM,iBACftF,YAAY7G,KAAKoM,oBACjBtF,OAAO,CACN,CAAC,EAAG,GACJ,CAAC9G,KAAKqL,cAAerL,KAAKsL,oBA7ElC,8BAiFE,WACE,IAAMyB,EAAa/M,KAAKkM,iBAAiB,CACvCvJ,MAAO3C,KAAKgL,MAAMrI,MAAM4B,KAAI,SAAA1G,GAAC,OAAII,OAAO2B,OAAO,GAAI/B,MACnDgF,MAAO7C,KAAKgL,MAAMnI,MAAM0B,KAAI,SAAA1G,GAAC,OAAII,OAAO2B,OAAO,GAAI/B,QAGrDmC,KAAKiL,OAAS8B,EAAWpK,MAAMqK,QAAO,SAAAnP,GAAC,OAAgB,IAAZA,EAAEW,SAC7CwB,KAAKkL,OAAS6B,EAAWlK,MAAMmK,QAAO,SAAAnP,GAAC,OAAgB,IAAZA,EAAEW,WAxFjD,uBA6FE,WACE,OAAOwB,KAAKgL,OACZhL,KAAKgL,MAAMrI,OACX3C,KAAKgL,MAAMnI,OACX7C,KAAKgL,MAAMrI,MAAM7C,OAAS,GAC1BE,KAAKgL,MAAMnI,MAAM/C,OAAS,IAlG9B,8BAuGE,WAAmB,WACXmN,EAAWjN,KAAKsM,SACrBY,OAAO,kBACLC,KAAK,MAAM,SAAAtP,GAAC,OAAKA,EAAEuP,IAAF,eAAgBvP,EAAEoD,MAAlB,YAA2BwD,KAAK4I,aACjDF,KAAK,gBAAiB,kBACtBA,KAAK,MAAM,SAAAtP,GAAC,OAAIA,EAAEwE,OAAOqB,MACzByJ,KAAK,MAAM,SAAAtP,GAAC,OAAIA,EAAEwD,OAAOoC,MAE5BwJ,EACGC,OAAO,QACPC,KAAK,SAAU,MACfA,KAAK,cAAc,SAAAtP,GAAC,OAAI,EAAKyP,OAAOzP,EAAEwE,WAEzC4K,EACGC,OAAO,QACPC,KAAK,SAAU,QACfA,KAAK,cAAc,SAAAtP,GAAC,OAAI,EAAKyP,OAAOzP,EAAEwD,aAvH7C,4BA0HE,SAAexD,GACX,OAAQmC,KAAK4L,YACX,KAAKnB,EACH,MAAO,OACT,KAAKA,EACH,qBAAe5M,EAAEuP,IAAjB,KACF,KAAK3C,EACH,OAAOzK,KAAKsN,OAAOzP,EAAEwE,QACvB,KAAKoI,GACH,OAAOzK,KAAKsN,OAAOzP,EAAEwD,QACvB,QACE,UArIV,wBA0IE,SAAWkM,GACT,IAAMC,EAAc,GAEL,CACb,CACEC,SAAU,cACVC,SAAU,UAEZ,CACED,SAAU,cACVC,SAAU,WAILC,SAAQ,SAAAC,GACfL,EAAYK,EAAKH,UAAUE,SAAQ,SAAAnQ,GACjCgQ,EAAY7M,KAAKnD,EAAEoQ,EAAKF,iBAK5B1N,KAAK+K,QACF8C,UAAU,gBACVC,MAAM,WAAW,SAAAtM,GAAI,OACpB+L,EAAYzP,OAAS0D,EAAK1D,MAC1B0P,EAAY1K,MAAK,SAAAiL,GAAU,OAAIA,EAAWjQ,OAAS0D,EAAK1D,QACxD,IAAM,SAIVkC,KAAK+K,QACF8C,UAAU,gBACVC,MAAM,WAAW,SAAA1K,GAAI,OACpBA,GACEA,EAAKf,OAAOvE,OAASyP,EAAYzP,MACjCsF,EAAK/B,OAAOvD,OAASyP,EAAYzP,KAE7B,MAAN,SA/KR,sBAmLE,WACEkC,KAAK+K,QAAQ8C,UAAU,gBAAgBC,MAAM,UAAW,KACxD9N,KAAK+K,QAAQ8C,UAAU,gBAAgBC,MAAM,UAAW,OArL5D,0BAyLE,SAAatP,GAAS,OAAOqO,SAAU,OAAVA,CAAkBrO,KAzLjD,4BA0LE,SAAewP,GAAY,OAAOnB,SAAU,OAAVA,CAAkBmB,KA1LtD,6BA2LE,SAAgBxP,GAAS,OAAOqO,SAAU,OAAVA,CAAkBrO,KA3LpD,6BA6LE,SAAgB+O,GACd,IAAMU,EAAejO,KAAKiL,OAAO+B,QAAO,SAAAxL,GAAI,OAAIA,EAAKF,QAAUiM,EAAYjM,SACrE4M,EAAerB,MAAOoB,GAAc,SAAAzM,GAAI,OAAIA,EAAKhD,SACjD2P,EAAYnO,KAAKoO,gBAAgBb,EAAY/O,OAC7C6P,EAAcrO,KAAKsO,eAAef,EAAY/O,MAAQ0P,GAExDK,EAAQ,GACZ,OAAQvO,KAAKuM,gBACX,KAAK/B,EACH+D,EAAQ,GAAH,OAAMJ,GACX,MACF,KAAK3D,EACH+D,EAAQ,GAAH,OAAMF,GACX,MACF,KAAK7D,EACH+D,EAAQ,GAAH,OAAMF,EAAN,cAAuBF,GAKhC,OAAOI,IAjNX,wBAsNE,WAAa,WAEXvO,KAAK8K,WAAWgD,MAAM,mBAAoB9N,KAAK2L,aAG/C3L,KAAK+K,QAAU/K,KAAK8K,WAAWoC,OAAO,KACjCC,KAAK,YADK,oBACqBnN,KAAK0L,YAD1B,aAC0C1L,KAAKuL,WAD/C,MAIfvL,KAAKqM,SAAWrM,KAAK+K,QAClBmC,OAAO,KACLC,KAAK,SAAU,QACjBU,UAAU,gBACVW,KAAKxO,KAAKiL,QAAQ,SAAAzJ,GAAI,OAAIA,EAAK1D,QAC/B2Q,KAAK,QACHtB,KAAK,QAAS,eACdA,KAAK,MAAM,SAAAtP,GAAC,OAAIA,EAAEC,QAClBqP,KAAK,KAAK,SAAAtP,GAAC,OAAIA,EAAE4F,MACjB0J,KAAK,KAAK,SAAAtP,GAAC,OAAIA,EAAE0E,MACjB4K,KAAK,KAAM,GACXA,KAAK,KAAM,GACXA,KAAK,UAAU,SAAAtP,GAAC,OAAIA,EAAEsF,GAAKtF,EAAE0E,MAC7B4K,KAAK,SAAS,SAAAtP,GAAC,OAAIA,EAAE6F,GAAK7F,EAAE4F,MAC5B0J,KAAK,UAAU,SAAAtP,GACd,IAAM6Q,EAAaC,KAAKC,MAAM,EAAK7C,aACnC,OAAI9N,OAAO4Q,KAAKH,GAAYI,SAASjR,EAAEC,MAC9B4Q,EAAW7Q,EAAEC,MAEf,4BAERqP,KAAK,QAAQ,SAAAtP,GACZ,IAAM6Q,EAAaC,KAAKC,MAAM,EAAK7C,aACnC,OAAI9N,OAAO4Q,KAAKH,GAAYI,SAASjR,EAAEC,MAC9B4Q,EAAW7Q,EAAEC,MAEf,4BAERiR,GAAG,aAAa,SAAAlR,GAAC,aAAI,EAAK2O,mBAAqB,EAAKwC,WAAL,UAAgBnR,EAAEwD,cAAlB,aAAgB,EAAU4N,aACzEF,GAAG,YAAY,SAAAtI,GAAC,OAAI,EAAK+F,mBAAqB,EAAK0C,cAGxDlP,KAAKsM,SAAWtM,KAAK+K,QAClBmC,OAAO,KACLC,KAAK,OAAQ,QACbA,KAAK,iBAAkB,IACzBU,UAAU,KACVW,KAAKxO,KAAKkL,QAAQ,SAAA9H,GAAI,gBAAOA,EAAKf,OAAOvE,KAAnB,YAA2BsF,EAAK/B,OAAOvD,SAC7D2Q,KAAK,KACHX,MAAM,iBAAkB,YAEL,SAApB9N,KAAK4L,YAAuB5L,KAAKmP,mBAErCnP,KAAKsM,SACFY,OAAO,QACLC,KAAK,QAAS,eACdA,KAAK,IAAKL,KACVK,KAAK,SAAU,0BACfA,KAAK,gBAAgB,SAAAtP,GAAC,OAAI4G,KAAKvD,IAAI,EAAGrD,EAAEwF,UAG7CrD,KAAK+K,QACFmC,OAAO,KACLC,KAAK,cAAe,cACpBA,KAAK,YAAa,IACpBU,UAAU,QACVW,KAAKxO,KAAKiL,QACVwD,KAAK,QACHtB,KAAK,KAAK,SAAAtP,GAAC,OAAIA,EAAE4F,GAAK,KACtB0J,KAAK,KAAK,SAAAtP,GAAC,OAAKA,EAAEsF,GAAKtF,EAAE0E,IAAM,KAC/B4K,KAAK,KAAM,UACXiC,MAAK,SAAAvR,GAAC,OAAIA,EAAEC,QAEfkC,KAAK+K,QACFmC,OAAO,KACLC,KAAK,cAAe,cACpBA,KAAK,YAAa,IACpBU,UAAU,QACVW,KAAKxO,KAAKiL,QACVwD,KAAK,QACLtB,KAAK,KAAK,SAAAtP,GAAC,OAAIA,EAAE4F,GAAK,KACpB0J,KAAK,YAAa,IAClBA,KAAK,cAAe,OACpBA,KAAK,KAAK,SAAAtP,GAAC,OAAMA,EAAEsF,GAAKtF,EAAE0E,IAAM,EAAK,MACrC4K,KAAK,KAAM,UACXiC,MAAK,SAAAvR,GAAC,OAAI,EAAKwR,gBAAgBxR,MAEtCmC,KAAKqM,SACFa,OAAO,SACLkC,MAAK,SAAAvR,GAAC,gBAAOA,EAAEC,KAAT,aAAkB,EAAKwR,aAAazR,EAAEW,WAEjDwB,KAAKsM,SACFY,OAAO,SACLkC,MAAK,SAAAvR,GAAC,gBAAOA,EAAEwE,OAAOvE,KAAhB,cAA0BD,EAAEwD,OAAOvD,KAAnC,aAA4C,EAAKwR,aAAazR,EAAEW,aAlT/E,kBA0TE,SAAKiI,GACH,OAAO5G,UAAUC,QAAUE,KAAKgL,MAAQvE,EAAGzG,MAAQA,KAAKgL,QA3T5D,mBA8TE,SAAMvE,GACJ,OAAO5G,UAAUC,QAAUE,KAAKmL,QAAU1E,EAAGzG,MAAQA,KAAKmL,SA/T9D,oBAkUE,SAAO1E,GACL,OAAO5G,UAAUC,QAAUE,KAAKoL,SAAW3E,EAAGzG,MAAQA,KAAKoL,UAnU/D,mBAsUE,SAAM3E,GACJ,OAAO5G,UAAUC,QAAUE,KAAKgM,iBAAmBvF,EAAGzG,MAAQA,KAAKgM,mBAvUvE,yBA0UE,SAAYvF,GACV,OAAO5G,UAAUC,QAAUE,KAAK6L,aAAepF,EAAGzG,MAAQA,KAAK6L,eA3UnE,wBA8UE,SAAWpF,GACT,OAAO5G,UAAUC,QAAUE,KAAK+L,YAActF,EAAGzG,MAAQA,KAAK+L,cA/UlE,uBAkVE,SAAUtF,GACR,OAAO5G,UAAUC,QAAUE,KAAK4L,WAAanF,EAAGzG,MAAQA,KAAK4L,aAnVjE,2BAsVE,SAAcnF,GACZ,OAAO5G,UAAUC,QAAUE,KAAKuM,eAAiB9F,EAAGzG,MAAQA,KAAKuM,iBAvVrE,8BA0VE,SAAiB9F,GACf,OAAO5G,UAAUC,QAAUE,KAAKwM,kBAAoB/F,EAAGzG,MAAQA,KAAKwM,oBA3VxE,oBA8VE,WAQE,OAPKxM,KAAKuP,cAIRvP,KAAKwP,QACLxP,KAAKyP,cAEAzP,U,2BAtWX,K,QCFa,GAAe,SAAC,G,IAAE0P,EAAO,UAAO,OAC3C,uBAAG5B,MAAO6B,IACR,yBAAK7B,MAAO8B,IACV,kBAAC,QAAI,CAAC9R,KAAK,yBACX,yBAAKgQ,MAAO+B,IAAgBH,MAK5BC,GAAc,CAClBjO,OAAQ,OACRoO,QAAS,OACTC,eAAgB,SAChBC,WAAY,UAGRJ,GAAkB,CACtBK,QAAS,YACTC,aAAc,MACdC,SAAU,WACVC,MAAO,qBACPC,WAAY,+BACZC,aAAc,MACdR,QAAS,OACTS,cAAe,MACfP,WAAY,SACZQ,WAAY,8DAGRX,GAAgB,CACpBY,WAAY,IChCDC,GAEb,SAAkBC,QAAA,IAAAA,OAJC,GAKjB,IAAKA,EACH,MAAO,CACLC,KAAM,W,IAAC,uDACPhQ,MAAO,W,IAAC,uDACRiQ,IAAK,W,IAAC,wDAIV,MAAO,CACLD,KAAME,QAAQF,KACdhQ,MAAOkQ,QAAQlQ,MACfiQ,IAAKC,QAAQD,KAdKE,GCSf,IAAM,GAA+B,SAAC,G,IAAEC,EAAO,UAAExC,EAAI,OAAEnL,EAAK,QAAE3B,EAAM,SAEnEuP,EAAwB,CAAE5O,OAAQ,SAAUhB,OAAQ,SAAU7C,MAAO,SAGrE0S,EAAoB,gCAAgCjT,OAAO4Q,KAAKoC,GAAuBxC,KAAK,MAI5F,IAAsB,mBAAS,CAAE0C,SAAS,EAAOzB,QAAS,KAAK,GAA7D9O,EAAK,KAAEwQ,EAAQ,KACjB,IAAsB,mBAAS,CAAEzO,MAAO,GAAIE,MAAO,KAAK,GAAtDH,EAAK,KAAE2O,EAAQ,KAEvB,qBAAU,WACJ7C,EAAK5N,OACP8P,GAAOE,KAAK,0BAA0B,CAACpC,KAAI,EAAE5N,MAAO4N,EAAK5N,QAG3D4N,EAAK5N,MAEHwQ,EAAS,CAACD,SAAS,EAAMzB,QAASlB,EAAK5N,MAAM8O,UAE7C2B,EAASC,OACV,CAAC9C,IAGJ,IAwBM8C,EAAa,WACjB,IAAMC,EAAQ/C,EAAKgD,OAAO,GAEpBC,EAAgBF,EAAMG,OAAO5O,MAAK,SAAA6O,GAAS,OAAAA,EAAM7T,OAASmT,EAAf,UAC3CW,EAAgBL,EAAMG,OAAO5O,MAAK,SAAA6O,GAAS,OAAAA,EAAM7T,OAASmT,EAAf,UAC3CY,EAAeN,EAAMG,OAAO5O,MAAK,SAAA6O,GAAS,OAAAA,EAAM7T,OAASmT,EAAf,SAE1Ca,EAAUL,aAAa,EAAbA,EAAe3Q,OAAOiR,UAChCC,EAAUJ,aAAa,EAAbA,EAAe9Q,OAAOiR,UAChCjR,EAAS+Q,aAAY,EAAZA,EAAc/Q,OAAOiR,UAGpC,GApCe,SAACD,EAASE,EAASlR,GAClC,IAAImR,GAAU,EAGd,KAAMH,GAAWE,GAAWlR,GAE1B,OADAsQ,EAAS,CAAED,SAAS,EAAMzB,QAASwB,KAClB,EAInB,IAAMgB,EAAgBJ,EAAQK,OAAM,SAAAtU,GAAK,uBAAOA,KAC1CuU,EAAgBJ,EAAQG,OAAM,SAAAtU,GAAK,uBAAOA,KAC1CwU,EAAgBvR,EAAOqR,OAAM,SAAAtU,GAAK,uBAAOA,KAE/C,OAAMqU,GAAiBE,GAAiBC,GAKxCjB,EAAS,IAEFa,IANLb,EAAS,CAAED,SAAS,EAAMzB,QAlCT,+FAmCA,GAmBH4C,CAASR,EAASE,EAASlR,GAC3C,CAEA,IAAMyR,EAAM,MAAOT,EAASE,EAASlR,GAMrC,MAFc,CAAE6B,MAFFqC,MAAMwN,KAAK,IAAI7N,IAAImN,EAAQW,OAAOT,KAAWzN,KAAI,SAAA/C,GAAQ,MAAC,CAAE1D,KAAH,MAEhD+E,MADT0P,EAAIhO,KAAI,SAAA1G,GAAK,MAAC,CAAEwE,OAAQxE,EAAE,GAAIwD,OAAQxD,EAAE,GAAIW,OAAQX,EAAE,GAAG6U,QAA5C,UAOvBC,EAAQ,SAAAhI,GACZ,IAAM5G,EAAS,IAAI,GAAO4G,GACvBtH,MAAMA,GACN3B,OAAOA,GACPmC,MAAMmN,EAAQnN,OACd+O,UAAU5B,EAAQ4B,WAClBC,YAAY7B,EAAQ6B,aACpBC,cAAc9B,EAAQ8B,eACtBC,iBAAiB/B,EAAQ+B,kBACzBrE,WAAWsC,EAAQtC,YACnBF,KAAK9L,GAER,IACEqB,EAAOiP,SACP,MAAOC,GACPvC,GAAOE,KAAK,4BAA4B,CAACqC,YAAW,EAAEvQ,MAAK,IAE3D0O,EAAS,CAACD,SAAS,EAAMzB,QAASuD,EAAYvD,YAIlD,OAAQ9O,EAAMuQ,QACZ,kBAAC,GAAY,CAACzB,QAAS9O,EAAM8O,UAE7B,yBACEwD,QAAS,OAAO7P,EAAK,IAAI3B,EACzByR,IAAK,SAAA3R,GACH,SAAUA,GACPqM,UAAU,KACVuF,SACH,SAAU5R,GAAM9D,KAAKiV,OC5GvB,SAAUU,KACd,OAAO,SAAC,GAAE,IAAA7B,EAAM,SAAK8B,EAAK,IAAlB,YACAC,EAAoB/B,EAAOjN,KAAI,SAACiK,GACpC,OAAO,sBAAY,EAAD,KAAMA,GAAI,CAAEkD,OAAQlD,EAAKkD,OAAOnN,KAc/C,SAACoN,EAAiBlL,EAAW+M,G,MAC5BC,EAAgBC,GAAmB5E,SAAS6C,EAAM7T,MAElD6V,EAAgBhC,EAAM7Q,kBAAkB,eAAgD,mBAAd,QAAnB,EAAO6Q,EAAM7Q,cAAM,eAAEiR,SAC5E6B,EAAU5O,MAAM4O,QAAQjC,EAAM7Q,QAEpC,IAAK2S,IAAkB9B,EAAM7Q,SAAY8S,IAAYD,EACnD,OAAOhC,EAGT,IAAM7Q,EAAS6S,EAAgBhC,EAAM7Q,OAAOiR,UAAY6B,EAAUjC,EAAM7Q,OAAS,KAEjF,GAAe,OAAXA,EAGF,OAFA4P,GAAOE,KAAK,wCAAyC,4BAErD,OACKe,GAAK,CACR7Q,OAAQ,IAAI,cAAY,MAI5B,IAAM+S,EAAeJ,EAAkB3S,EAAeyD,KA2BjD,SAAC/F,GAAa,MAAkB,iBAAVA,EAAqBA,EAAMsV,MAAM,KAAzC,KA3BqD,GAAiBvP,KAsBpF,SAAC/F,EAAUiI,EAAW+M,GAAY,OAACO,OAAOC,MAAMD,OAAOvV,IAAUA,EAAQuV,OAAvC,MAtBuE,KAE9G,IACE,cACKpC,GAAK,CACRsC,MAAMJ,aAAY,EAAZA,EAAc1B,OA2BnB,SAAC3T,GAAa,uBAAOA,MA3BkB,YAAU0V,OAASvC,EAAMsC,KACjEnT,OAAQ+S,EAAe,IAAI,cAAYlF,KAAKC,MAAMD,KAAKwF,UAAUN,KAAkB/S,IAErF,MAAOsT,GAGP,OAFA1D,GAAOE,KAAK,wCAAyCwD,aAAenR,MAAQmR,EAAI1E,QAAU2E,OAAOD,IAEjG,OACKzC,GAAK,CACRsC,KAAMtC,EAAMsC,KACZnT,OAAQ,IAAI,cAAY,gBA9C5B,UACE0Q,OAAQ+B,GACLD,IAKT,IAAMI,GAAqB,CAAC,SAAU,SAAU,SCnBhD,wCAIO,IAAM,GAAS,IAAI,eCI2B,SAAC,GAAE,IAAAlF,EAAI,OAAK8F,EAAK,IAAhB,UAC9CC,EAAc,kBAAQlB,GAAiB,IAEvCmB,EAAkB,mBAAQ,WAAM,OAAAD,EAAA,KAAmB,CAACA,EAAa/F,IAEvE,OAAO,kBAAC,GAAW,YAAU8F,GAAK,CAAE9F,KAAMgG,SDTwBC,iBAAgB,SAACC,GACnF,OAAOA,EACJC,UAAU,CACTnN,KAAM,QACN1J,KAAM,QACN8W,aAAc,UACdC,SAAU,CACR7D,QAAS,CACP,CACExS,MAAO,UACP+P,MAAO,WAET,CACE/P,MAAO,OACP+P,MAAO,QAET,CACE/P,MAAO,QACP+P,MAAO,SAET,CACE/P,MAAO,SACP+P,MAAO,cAKduG,aAAa,CACZtN,KAAM,aACN1J,KAAM,eACN8W,aAAc,KAEfD,UAAU,CACTnN,KAAM,cACN1J,KAAM,QACN8W,aAAc,YACdC,SAAU,CACR7D,QAAS,CACP,CACExS,MAAO,YACP+P,MAAO,aAET,CACE/P,MAAO,aACP+P,MAAO,cAET,CACE/P,MAAO,SACP+P,MAAO,UAET,CACE/P,MAAO,QACP+P,MAAO,SAET,CACE/P,MAAO,SACP+P,MAAO,UAET,CACE/P,MAAO,UACP+P,MAAO,WAET,CACE/P,MAAO,UACP+P,MAAO,WAET,CACE/P,MAAO,OACP+P,MAAO,QAET,CACE/P,MAAO,OACP+P,MAAO,QAET,CACE/P,MAAO,OACP+P,MAAO,YAKdoG,UAAU,CACTnN,KAAM,YACN1J,KAAM,aACN8W,aAAc,OACdC,SAAU,CACR7D,QAAS,CACP,CACExS,MAAO,OACP+P,MAAO,gBAET,CACE/P,MAAO,QACP+P,MAAO,SAET,CACE/P,MAAO,SACP+P,MAAO,UAET,CACE/P,MAAO,OACP+P,MAAO,YAKdoG,UAAU,CACTnN,KAAM,gBACN1J,KAAM,iBACN8W,aAAc,OACdC,SAAU,CACR7D,QAAS,CACP,CACExS,MAAO,QACP+P,MAAO,UAET,CACE/P,MAAO,aACP+P,MAAO,eAET,CACE/P,MAAO,OACP+P,MAAO,QAET,CACE/P,MAAO,OACP+P,MAAO,YAKdwG,iBAAiB,CAChBvN,KAAM,mBACN1J,KAAM,sCACN8W,cAAc","file":"module.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 5);\n","module.exports = __WEBPACK_EXTERNAL_MODULE__0__;","module.exports = __WEBPACK_EXTERNAL_MODULE__1__;","module.exports = __WEBPACK_EXTERNAL_MODULE__2__;","module.exports = __WEBPACK_EXTERNAL_MODULE__3__;","/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport function __createBinding(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}\r\n\r\nexport function __exportStar(m, exports) {\r\n for (var p in m) if (p !== \"default\" && !exports.hasOwnProperty(p)) exports[p] = m[p];\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n};\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n result.default = mod;\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, privateMap) {\r\n if (!privateMap.has(receiver)) {\r\n throw new TypeError(\"attempted to get private field on non-instance\");\r\n }\r\n return privateMap.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, privateMap, value) {\r\n if (!privateMap.has(receiver)) {\r\n throw new TypeError(\"attempted to set private field on non-instance\");\r\n }\r\n privateMap.set(receiver, value);\r\n return value;\r\n}\r\n","export default function sum(values, valueof) {\n let sum = 0;\n if (valueof === undefined) {\n for (let value of values) {\n if (value = +value) {\n sum += value;\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if (value = +valueof(value, ++index, values)) {\n sum += value;\n }\n }\n }\n return sum;\n}\n","export default function max(values, valueof) {\n let max;\n if (valueof === undefined) {\n for (const value of values) {\n if (value != null\n && (max < value || (max === undefined && value >= value))) {\n max = value;\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if ((value = valueof(value, ++index, values)) != null\n && (max < value || (max === undefined && value >= value))) {\n max = value;\n }\n }\n }\n return max;\n}\n","export default function min(values, valueof) {\n let min;\n if (valueof === undefined) {\n for (const value of values) {\n if (value != null\n && (min > value || (min === undefined && value >= value))) {\n min = value;\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if ((value = valueof(value, ++index, values)) != null\n && (min > value || (min === undefined && value >= value))) {\n min = value;\n }\n }\n }\n return min;\n}\n","import {min} from \"d3-array\";\n\nfunction targetDepth(d) {\n return d.target.depth;\n}\n\nexport function left(node) {\n return node.depth;\n}\n\nexport function right(node, n) {\n return n - 1 - node.height;\n}\n\nexport function justify(node, n) {\n return node.sourceLinks.length ? node.depth : n - 1;\n}\n\nexport function center(node) {\n return node.targetLinks.length ? node.depth\n : node.sourceLinks.length ? min(node.sourceLinks, targetDepth) - 1\n : 0;\n}\n","export default function constant(x) {\n return function() {\n return x;\n };\n}\n","import {max, min, sum} from \"d3-array\";\nimport {justify} from \"./align.js\";\nimport constant from \"./constant.js\";\n\nfunction ascendingSourceBreadth(a, b) {\n return ascendingBreadth(a.source, b.source) || a.index - b.index;\n}\n\nfunction ascendingTargetBreadth(a, b) {\n return ascendingBreadth(a.target, b.target) || a.index - b.index;\n}\n\nfunction ascendingBreadth(a, b) {\n return a.y0 - b.y0;\n}\n\nfunction value(d) {\n return d.value;\n}\n\nfunction defaultId(d) {\n return d.index;\n}\n\nfunction defaultNodes(graph) {\n return graph.nodes;\n}\n\nfunction defaultLinks(graph) {\n return graph.links;\n}\n\nfunction find(nodeById, id) {\n const node = nodeById.get(id);\n if (!node) throw new Error(\"missing: \" + id);\n return node;\n}\n\nfunction computeLinkBreadths({nodes}) {\n for (const node of nodes) {\n let y0 = node.y0;\n let y1 = y0;\n for (const link of node.sourceLinks) {\n link.y0 = y0 + link.width / 2;\n y0 += link.width;\n }\n for (const link of node.targetLinks) {\n link.y1 = y1 + link.width / 2;\n y1 += link.width;\n }\n }\n}\n\nexport default function Sankey() {\n let x0 = 0, y0 = 0, x1 = 1, y1 = 1; // extent\n let dx = 24; // nodeWidth\n let dy = 8, py; // nodePadding\n let id = defaultId;\n let align = justify;\n let sort;\n let linkSort;\n let nodes = defaultNodes;\n let links = defaultLinks;\n let iterations = 6;\n\n function sankey() {\n const graph = {nodes: nodes.apply(null, arguments), links: links.apply(null, arguments)};\n computeNodeLinks(graph);\n computeNodeValues(graph);\n computeNodeDepths(graph);\n computeNodeHeights(graph);\n computeNodeBreadths(graph);\n computeLinkBreadths(graph);\n return graph;\n }\n\n sankey.update = function(graph) {\n computeLinkBreadths(graph);\n return graph;\n };\n\n sankey.nodeId = function(_) {\n return arguments.length ? (id = typeof _ === \"function\" ? _ : constant(_), sankey) : id;\n };\n\n sankey.nodeAlign = function(_) {\n return arguments.length ? (align = typeof _ === \"function\" ? _ : constant(_), sankey) : align;\n };\n\n sankey.nodeSort = function(_) {\n return arguments.length ? (sort = _, sankey) : sort;\n };\n\n sankey.nodeWidth = function(_) {\n return arguments.length ? (dx = +_, sankey) : dx;\n };\n\n sankey.nodePadding = function(_) {\n return arguments.length ? (dy = py = +_, sankey) : dy;\n };\n\n sankey.nodes = function(_) {\n return arguments.length ? (nodes = typeof _ === \"function\" ? _ : constant(_), sankey) : nodes;\n };\n\n sankey.links = function(_) {\n return arguments.length ? (links = typeof _ === \"function\" ? _ : constant(_), sankey) : links;\n };\n\n sankey.linkSort = function(_) {\n return arguments.length ? (linkSort = _, sankey) : linkSort;\n };\n\n sankey.size = function(_) {\n return arguments.length ? (x0 = y0 = 0, x1 = +_[0], y1 = +_[1], sankey) : [x1 - x0, y1 - y0];\n };\n\n sankey.extent = function(_) {\n return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], sankey) : [[x0, y0], [x1, y1]];\n };\n\n sankey.iterations = function(_) {\n return arguments.length ? (iterations = +_, sankey) : iterations;\n };\n\n function computeNodeLinks({nodes, links}) {\n for (const [i, node] of nodes.entries()) {\n node.index = i;\n node.sourceLinks = [];\n node.targetLinks = [];\n }\n const nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d]));\n for (const [i, link] of links.entries()) {\n link.index = i;\n let {source, target} = link;\n if (typeof source !== \"object\") source = link.source = find(nodeById, source);\n if (typeof target !== \"object\") target = link.target = find(nodeById, target);\n source.sourceLinks.push(link);\n target.targetLinks.push(link);\n }\n if (linkSort != null) {\n for (const {sourceLinks, targetLinks} of nodes) {\n sourceLinks.sort(linkSort);\n targetLinks.sort(linkSort);\n }\n }\n }\n\n function computeNodeValues({nodes}) {\n for (const node of nodes) {\n node.value = node.fixedValue === undefined\n ? Math.max(sum(node.sourceLinks, value), sum(node.targetLinks, value))\n : node.fixedValue;\n }\n }\n\n function computeNodeDepths({nodes}) {\n const n = nodes.length;\n let current = new Set(nodes);\n let next = new Set;\n let x = 0;\n while (current.size) {\n for (const node of current) {\n node.depth = x;\n for (const {target} of node.sourceLinks) {\n next.add(target);\n }\n }\n if (++x > n) throw new Error(\"circular link\");\n current = next;\n next = new Set;\n }\n }\n\n function computeNodeHeights({nodes}) {\n const n = nodes.length;\n let current = new Set(nodes);\n let next = new Set;\n let x = 0;\n while (current.size) {\n for (const node of current) {\n node.height = x;\n for (const {source} of node.targetLinks) {\n next.add(source);\n }\n }\n if (++x > n) throw new Error(\"circular link\");\n current = next;\n next = new Set;\n }\n }\n\n function computeNodeLayers({nodes}) {\n const x = max(nodes, d => d.depth) + 1;\n const kx = (x1 - x0 - dx) / (x - 1);\n const columns = new Array(x);\n for (const node of nodes) {\n const i = Math.max(0, Math.min(x - 1, Math.floor(align.call(null, node, x))));\n node.layer = i;\n node.x0 = x0 + i * kx;\n node.x1 = node.x0 + dx;\n if (columns[i]) columns[i].push(node);\n else columns[i] = [node];\n }\n if (sort) for (const column of columns) {\n column.sort(sort);\n }\n return columns;\n }\n\n function initializeNodeBreadths(columns) {\n const ky = min(columns, c => (y1 - y0 - (c.length - 1) * py) / sum(c, value));\n for (const nodes of columns) {\n let y = y0;\n for (const node of nodes) {\n node.y0 = y;\n node.y1 = y + node.value * ky;\n y = node.y1 + py;\n for (const link of node.sourceLinks) {\n link.width = link.value * ky;\n }\n }\n y = (y1 - y + py) / (nodes.length + 1);\n for (let i = 0; i < nodes.length; ++i) {\n const node = nodes[i];\n node.y0 += y * (i + 1);\n node.y1 += y * (i + 1);\n }\n reorderLinks(nodes);\n }\n }\n\n function computeNodeBreadths(graph) {\n const columns = computeNodeLayers(graph);\n py = Math.min(dy, (y1 - y0) / (max(columns, c => c.length) - 1));\n initializeNodeBreadths(columns);\n for (let i = 0; i < iterations; ++i) {\n const alpha = Math.pow(0.99, i);\n const beta = Math.max(1 - alpha, (i + 1) / iterations);\n relaxRightToLeft(columns, alpha, beta);\n relaxLeftToRight(columns, alpha, beta);\n }\n }\n\n // Reposition each node based on its incoming (target) links.\n function relaxLeftToRight(columns, alpha, beta) {\n for (let i = 1, n = columns.length; i < n; ++i) {\n const column = columns[i];\n for (const target of column) {\n let y = 0;\n let w = 0;\n for (const {source, value} of target.targetLinks) {\n let v = value * (target.layer - source.layer);\n y += targetTop(source, target) * v;\n w += v;\n }\n if (!(w > 0)) continue;\n let dy = (y / w - target.y0) * alpha;\n target.y0 += dy;\n target.y1 += dy;\n reorderNodeLinks(target);\n }\n if (sort === undefined) column.sort(ascendingBreadth);\n resolveCollisions(column, beta);\n }\n }\n\n // Reposition each node based on its outgoing (source) links.\n function relaxRightToLeft(columns, alpha, beta) {\n for (let n = columns.length, i = n - 2; i >= 0; --i) {\n const column = columns[i];\n for (const source of column) {\n let y = 0;\n let w = 0;\n for (const {target, value} of source.sourceLinks) {\n let v = value * (target.layer - source.layer);\n y += sourceTop(source, target) * v;\n w += v;\n }\n if (!(w > 0)) continue;\n let dy = (y / w - source.y0) * alpha;\n source.y0 += dy;\n source.y1 += dy;\n reorderNodeLinks(source);\n }\n if (sort === undefined) column.sort(ascendingBreadth);\n resolveCollisions(column, beta);\n }\n }\n\n function resolveCollisions(nodes, alpha) {\n const i = nodes.length >> 1;\n const subject = nodes[i];\n resolveCollisionsBottomToTop(nodes, subject.y0 - py, i - 1, alpha);\n resolveCollisionsTopToBottom(nodes, subject.y1 + py, i + 1, alpha);\n resolveCollisionsBottomToTop(nodes, y1, nodes.length - 1, alpha);\n resolveCollisionsTopToBottom(nodes, y0, 0, alpha);\n }\n\n // Push any overlapping nodes down.\n function resolveCollisionsTopToBottom(nodes, y, i, alpha) {\n for (; i < nodes.length; ++i) {\n const node = nodes[i];\n const dy = (y - node.y0) * alpha;\n if (dy > 1e-6) node.y0 += dy, node.y1 += dy;\n y = node.y1 + py;\n }\n }\n\n // Push any overlapping nodes up.\n function resolveCollisionsBottomToTop(nodes, y, i, alpha) {\n for (; i >= 0; --i) {\n const node = nodes[i];\n const dy = (node.y1 - y) * alpha;\n if (dy > 1e-6) node.y0 -= dy, node.y1 -= dy;\n y = node.y0 - py;\n }\n }\n\n function reorderNodeLinks({sourceLinks, targetLinks}) {\n if (linkSort === undefined) {\n for (const {source: {sourceLinks}} of targetLinks) {\n sourceLinks.sort(ascendingTargetBreadth);\n }\n for (const {target: {targetLinks}} of sourceLinks) {\n targetLinks.sort(ascendingSourceBreadth);\n }\n }\n }\n\n function reorderLinks(nodes) {\n if (linkSort === undefined) {\n for (const {sourceLinks, targetLinks} of nodes) {\n sourceLinks.sort(ascendingTargetBreadth);\n targetLinks.sort(ascendingSourceBreadth);\n }\n }\n }\n\n // Returns the target.y0 that would produce an ideal link from source to target.\n function targetTop(source, target) {\n let y = source.y0 - (source.sourceLinks.length - 1) * py / 2;\n for (const {target: node, width} of source.sourceLinks) {\n if (node === target) break;\n y += width + py;\n }\n for (const {source: node, width} of target.targetLinks) {\n if (node === source) break;\n y -= width;\n }\n return y;\n }\n\n // Returns the source.y0 that would produce an ideal link from source to target.\n function sourceTop(source, target) {\n let y = target.y0 - (target.targetLinks.length - 1) * py / 2;\n for (const {source: node, width} of target.targetLinks) {\n if (node === source) break;\n y += width + py;\n }\n for (const {target: node, width} of source.sourceLinks) {\n if (node === target) break;\n y -= width;\n }\n return y;\n }\n\n return sankey;\n}\n","var pi = Math.PI,\n tau = 2 * pi,\n epsilon = 1e-6,\n tauEpsilon = tau - epsilon;\n\nfunction Path() {\n this._x0 = this._y0 = // start of current subpath\n this._x1 = this._y1 = null; // end of current subpath\n this._ = \"\";\n}\n\nfunction path() {\n return new Path;\n}\n\nPath.prototype = path.prototype = {\n constructor: Path,\n moveTo: function(x, y) {\n this._ += \"M\" + (this._x0 = this._x1 = +x) + \",\" + (this._y0 = this._y1 = +y);\n },\n closePath: function() {\n if (this._x1 !== null) {\n this._x1 = this._x0, this._y1 = this._y0;\n this._ += \"Z\";\n }\n },\n lineTo: function(x, y) {\n this._ += \"L\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n quadraticCurveTo: function(x1, y1, x, y) {\n this._ += \"Q\" + (+x1) + \",\" + (+y1) + \",\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) {\n this._ += \"C\" + (+x1) + \",\" + (+y1) + \",\" + (+x2) + \",\" + (+y2) + \",\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n arcTo: function(x1, y1, x2, y2, r) {\n x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;\n var x0 = this._x1,\n y0 = this._y1,\n x21 = x2 - x1,\n y21 = y2 - y1,\n x01 = x0 - x1,\n y01 = y0 - y1,\n l01_2 = x01 * x01 + y01 * y01;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(\"negative radius: \" + r);\n\n // Is this path empty? Move to (x1,y1).\n if (this._x1 === null) {\n this._ += \"M\" + (this._x1 = x1) + \",\" + (this._y1 = y1);\n }\n\n // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.\n else if (!(l01_2 > epsilon));\n\n // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?\n // Equivalently, is (x1,y1) coincident with (x2,y2)?\n // Or, is the radius zero? Line to (x1,y1).\n else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {\n this._ += \"L\" + (this._x1 = x1) + \",\" + (this._y1 = y1);\n }\n\n // Otherwise, draw an arc!\n else {\n var x20 = x2 - x0,\n y20 = y2 - y0,\n l21_2 = x21 * x21 + y21 * y21,\n l20_2 = x20 * x20 + y20 * y20,\n l21 = Math.sqrt(l21_2),\n l01 = Math.sqrt(l01_2),\n l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),\n t01 = l / l01,\n t21 = l / l21;\n\n // If the start tangent is not coincident with (x0,y0), line to.\n if (Math.abs(t01 - 1) > epsilon) {\n this._ += \"L\" + (x1 + t01 * x01) + \",\" + (y1 + t01 * y01);\n }\n\n this._ += \"A\" + r + \",\" + r + \",0,0,\" + (+(y01 * x20 > x01 * y20)) + \",\" + (this._x1 = x1 + t21 * x21) + \",\" + (this._y1 = y1 + t21 * y21);\n }\n },\n arc: function(x, y, r, a0, a1, ccw) {\n x = +x, y = +y, r = +r, ccw = !!ccw;\n var dx = r * Math.cos(a0),\n dy = r * Math.sin(a0),\n x0 = x + dx,\n y0 = y + dy,\n cw = 1 ^ ccw,\n da = ccw ? a0 - a1 : a1 - a0;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(\"negative radius: \" + r);\n\n // Is this path empty? Move to (x0,y0).\n if (this._x1 === null) {\n this._ += \"M\" + x0 + \",\" + y0;\n }\n\n // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).\n else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {\n this._ += \"L\" + x0 + \",\" + y0;\n }\n\n // Is this arc empty? We’re done.\n if (!r) return;\n\n // Does the angle go the wrong way? Flip the direction.\n if (da < 0) da = da % tau + tau;\n\n // Is this a complete circle? Draw two arcs to complete the circle.\n if (da > tauEpsilon) {\n this._ += \"A\" + r + \",\" + r + \",0,1,\" + cw + \",\" + (x - dx) + \",\" + (y - dy) + \"A\" + r + \",\" + r + \",0,1,\" + cw + \",\" + (this._x1 = x0) + \",\" + (this._y1 = y0);\n }\n\n // Is this arc non-empty? Draw an arc!\n else if (da > epsilon) {\n this._ += \"A\" + r + \",\" + r + \",0,\" + (+(da >= pi)) + \",\" + cw + \",\" + (this._x1 = x + r * Math.cos(a1)) + \",\" + (this._y1 = y + r * Math.sin(a1));\n }\n },\n rect: function(x, y, w, h) {\n this._ += \"M\" + (this._x0 = this._x1 = +x) + \",\" + (this._y0 = this._y1 = +y) + \"h\" + (+w) + \"v\" + (+h) + \"h\" + (-w) + \"Z\";\n },\n toString: function() {\n return this._;\n }\n};\n\nexport default path;\n","export var slice = Array.prototype.slice;\n","export default function(x) {\n return function constant() {\n return x;\n };\n}\n","export function x(p) {\n return p[0];\n}\n\nexport function y(p) {\n return p[1];\n}\n","import {path} from \"d3-path\";\nimport {slice} from \"../array.js\";\nimport constant from \"../constant.js\";\nimport {x as pointX, y as pointY} from \"../point.js\";\nimport pointRadial from \"../pointRadial.js\";\n\nfunction linkSource(d) {\n return d.source;\n}\n\nfunction linkTarget(d) {\n return d.target;\n}\n\nfunction link(curve) {\n var source = linkSource,\n target = linkTarget,\n x = pointX,\n y = pointY,\n context = null;\n\n function link() {\n var buffer, argv = slice.call(arguments), s = source.apply(this, argv), t = target.apply(this, argv);\n if (!context) context = buffer = path();\n curve(context, +x.apply(this, (argv[0] = s, argv)), +y.apply(this, argv), +x.apply(this, (argv[0] = t, argv)), +y.apply(this, argv));\n if (buffer) return context = null, buffer + \"\" || null;\n }\n\n link.source = function(_) {\n return arguments.length ? (source = _, link) : source;\n };\n\n link.target = function(_) {\n return arguments.length ? (target = _, link) : target;\n };\n\n link.x = function(_) {\n return arguments.length ? (x = typeof _ === \"function\" ? _ : constant(+_), link) : x;\n };\n\n link.y = function(_) {\n return arguments.length ? (y = typeof _ === \"function\" ? _ : constant(+_), link) : y;\n };\n\n link.context = function(_) {\n return arguments.length ? ((context = _ == null ? null : _), link) : context;\n };\n\n return link;\n}\n\nfunction curveHorizontal(context, x0, y0, x1, y1) {\n context.moveTo(x0, y0);\n context.bezierCurveTo(x0 = (x0 + x1) / 2, y0, x0, y1, x1, y1);\n}\n\nfunction curveVertical(context, x0, y0, x1, y1) {\n context.moveTo(x0, y0);\n context.bezierCurveTo(x0, y0 = (y0 + y1) / 2, x1, y0, x1, y1);\n}\n\nfunction curveRadial(context, x0, y0, x1, y1) {\n var p0 = pointRadial(x0, y0),\n p1 = pointRadial(x0, y0 = (y0 + y1) / 2),\n p2 = pointRadial(x1, y0),\n p3 = pointRadial(x1, y1);\n context.moveTo(p0[0], p0[1]);\n context.bezierCurveTo(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);\n}\n\nexport function linkHorizontal() {\n return link(curveHorizontal);\n}\n\nexport function linkVertical() {\n return link(curveVertical);\n}\n\nexport function linkRadial() {\n var l = link(curveRadial);\n l.angle = l.x, delete l.x;\n l.radius = l.y, delete l.y;\n return l;\n}\n","import {linkHorizontal} from \"d3-shape\";\n\nfunction horizontalSource(d) {\n return [d.source.x1, d.y0];\n}\n\nfunction horizontalTarget(d) {\n return [d.target.x0, d.y1];\n}\n\nexport default function() {\n return linkHorizontal()\n .source(horizontalSource)\n .target(horizontalTarget);\n}\n","import * as d3 from 'd3';\nimport * as d3Sankey from 'd3-sankey';\n\nconst DISPLAY_VALUES = { total: 'total', percentage: 'percentage', both: 'both', none: 'none' };\nconst EDGE_COLORS = { none: 'none', path: 'path', input: 'input', output: 'output'};\n\nexport class Sankey {\n constructor(svg, container) {\n this._svg = svg;\n this._container = container || svg;\n this._gBound = null;\n\n this._data = null;\n this._nodes = null;\n this._links = null;\n\n this._width = 0;\n this._height = 0;\n this._boundedWidth = 0;\n this._boundedHeight = 0;\n\n this._marginTop = 20;\n this._marginRight = 20;\n this._marginBottom = 20;\n this._marginLeft = 20;\n\n this._background = 'rgba(0, 0, 0, 0)';\n this._edgeColor = 'path';\n this._colorScheme = 'Tableau10';\n this._colorScale = null;\n this._colorArray = '';\n\n this._sankeyAlignType = 'Justify';\n this._sankeyAlign = null;\n this._sankeyGenerator = null;\n this._sankeyNodeWith = 110;\n this._sankeyNodePadding = 20;\n\n this._svgNode = null;\n this._svgLink = null;\n\n this._displayValues = 'none';\n this._highlightOnHover = false;\n\n }\n \n _init() {\n this._setBoundDimensions();\n this._setColorScale();\n this._configureSankey();\n this._calculateSankey();\n }\n\n // ---------------------------- DIMENSIONS ----------------------------\n\n _setBoundDimensions() {\n this._boundedWidth = this._width - this._marginLeft - this._marginRight;\n this._boundedHeight = this._height - this._marginTop - this._marginBottom;\n }\n\n // ------------------------------ COLOR -------------------------------\n\n _setColorScale() {\n this._colorScale = d3.scaleOrdinal(d3[`scheme${this._colorScheme}`]);\n }\n\n _color(node) {\n return this._colorScale(node.name);\n }\n\n // ------------------------------ SANKEY -------------------------------\n\n _configureSankey() {\n this._sankeyAlign = d3Sankey[`sankey${this._sankeyAlignType}`];\n\n this._sankeyGenerator = d3Sankey\n .sankey()\n .nodeId(d => d.name)\n .nodeAlign(this._sankeyAlign)\n .nodeWidth(this._sankeyNodeWith)\n .nodePadding(this._sankeyNodePadding)\n .extent([\n [0, 0],\n [this._boundedWidth, this._boundedHeight],\n ]);\n }\n\n _calculateSankey() {\n const sankeyData = this._sankeyGenerator({\n nodes: this._data.nodes.map(d => Object.assign({}, d)),\n links: this._data.links.map(d => Object.assign({}, d))\n });\n\n this._nodes = sankeyData.nodes.filter(d => d.value !== 0);\n this._links = sankeyData.links.filter(d => d.value !== 0);\n }\n\n // ---------------------------- VALIDATIONS -----------------------------\n\n _validate() {\n return this._data &&\n this._data.nodes &&\n this._data.links &&\n this._data.nodes.length > 0 &&\n this._data.links.length > 0\n }\n\n // ------------------------------ HELPERS -------------------------------\n\n _setLinkGradient() {\n const gradient = this._svgLink\n .append('linearGradient')\n .attr('id', d => (d.uid = `link-${d.index}-${Math.random()}`))\n .attr('gradientUnits', 'userSpaceOnUse')\n .attr('x1', d => d.source.x1)\n .attr('x2', d => d.target.x0);\n\n gradient\n .append('stop')\n .attr('offset', '0%')\n .attr('stop-color', d => this._color(d.source));\n\n gradient\n .append('stop')\n .attr('offset', '100%')\n .attr('stop-color', d => this._color(d.target));\n }\n\n _setLinkStroke(d) {\n switch (this._edgeColor) {\n case EDGE_COLORS.none:\n return '#aaa';\n case EDGE_COLORS.path:\n return `url(#${d.uid})`;\n case EDGE_COLORS.input:\n return this._color(d.source)\n case EDGE_COLORS.output:\n return this._color(d.target)\n default:\n return\n }\n }\n\n // NODE HOVER\n _showLinks(currentNode) {\n const linkedNodes = [];\n\n let traverse = [\n {\n linkType: 'sourceLinks',\n nodeType: 'target',\n },\n {\n linkType: 'targetLinks',\n nodeType: 'source',\n },\n ];\n\n traverse.forEach(step => {\n currentNode[step.linkType].forEach(l => {\n linkedNodes.push(l[step.nodeType]);\n });\n });\n\n // highlight linked nodes\n this._gBound\n .selectAll('.sankey-node')\n .style('opacity', node =>\n currentNode.name === node.name ||\n linkedNodes.find(linkedNode => linkedNode.name === node.name) ? \n '1' : '0.2'\n );\n\n // highlight links\n this._gBound\n .selectAll('.sankey-link')\n .style('opacity', link =>\n link && (\n link.source.name === currentNode.name || \n link.target.name === currentNode.name\n ) ? \n '1' : '0.2'\n );\n };\n\n _showAll() {\n this._gBound.selectAll('.sankey-node').style('opacity', '1');\n this._gBound.selectAll('.sankey-link').style('opacity', '1');\n };\n\n // NODE LABELING\n _formatValue(value) { return d3.format('.2~f')(value); }\n _formatPercent(percent) { return d3.format('.2~%')(percent); }\n _formatThousand(value) { return d3.format('.3~s')(value); }\n\n _labelNodeValue(currentNode) {\n const nodesAtDepth = this._nodes.filter(node => node.depth === currentNode.depth);\n const totalAtDepth = d3.sum(nodesAtDepth, node => node.value);\n const nodeValue = this._formatThousand(currentNode.value);\n const nodePercent = this._formatPercent(currentNode.value / totalAtDepth);\n\n let label = '';\n switch (this._displayValues) {\n case DISPLAY_VALUES.total:\n label = `${nodeValue}`;\n break;\n case DISPLAY_VALUES.percentage:\n label = `${nodePercent}`;\n break;\n case DISPLAY_VALUES.both:\n label = `${nodePercent} - ${nodeValue}`;\n break;\n default:\n break;\n }\n return label;\n };\n\n // ------------------------------ DRAWING -------------------------------\n\n _renderSVG() {\n // BACKGROUND\n this._container.style('background-color', this._background)\n\n // BOUNDS\n this._gBound = this._container.append('g')\n .attr('transform', `translate(${this._marginLeft}, ${this._marginTop})`);\n\n // NODES\n this._svgNode = this._gBound\n .append('g')\n .attr('stroke', '#000')\n .selectAll('.sankey-node')\n .data(this._nodes, node => node.name)\n .join('rect')\n .attr('class', 'sankey-node')\n .attr('id', d => d.name)\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('rx', 2)\n .attr('ry', 2)\n .attr('height', d => d.y1 - d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('stroke', d => {\n const colorArray = JSON.parse(this._colorArray);\n if (Object.keys(colorArray).includes(d.name)) {\n return colorArray[d.name];\n }\n return \"rgba(148, 153, 168, 1)\";\n })\n .attr('fill', d => {\n const colorArray = JSON.parse(this._colorArray);\n if (Object.keys(colorArray).includes(d.name)) {\n return colorArray[d.name];\n }\n return \"rgba(148, 153, 168, 1)\";\n })\n .on('mouseover', d => this._highlightOnHover && this._showLinks(d.target?.__data__))\n .on('mouseout', _ => this._highlightOnHover && this._showAll());\n\n // LINKS\n this._svgLink = this._gBound\n .append('g')\n .attr('fill', 'none')\n .attr('stroke-opacity', 0.3)\n .selectAll('g')\n .data(this._links, link => `${link.source.name}-${link.target.name}`)\n .join('g')\n .style('mix-blend-mode', 'multiply');\n\n if (this._edgeColor === 'path') this._setLinkGradient()\n\n this._svgLink\n .append('path')\n .attr('class', 'sankey-link')\n .attr('d', d3Sankey.sankeyLinkHorizontal())\n .attr('stroke', \"rgba(182, 185, 196, 1)\")\n .attr('stroke-width', d => Math.max(1, d.width)); \n\n // LABELS\n this._gBound\n .append('g')\n .attr('font-family', 'sans-serif')\n .attr('font-size', 10)\n .selectAll('text')\n .data(this._nodes)\n .join('text')\n .attr('x', d => d.x0 + 8)\n .attr('y', d => (d.y1 + d.y0) / 2)\n .attr('dy', '0.35em')\n .text(d => d.name);\n\n this._gBound\n .append('g')\n .attr('font-family', 'sans-serif')\n .attr('font-size', 10)\n .selectAll('text')\n .data(this._nodes)\n .join('text')\n .attr('x', d => d.x0 + 8)\n .attr('font-size', 14)\n .attr('font-weight', '700')\n .attr('y', d => ((d.y1 + d.y0) / 2) + 16)\n .attr('dy', '0.35em')\n .text(d => this._labelNodeValue(d));\n\n this._svgNode\n .append('title')\n .text(d => `${d.name}\\n${this._formatValue(d.value)}`);\n\n this._svgLink\n .append('title')\n .text(d => `${d.source.name} → ${d.target.name}\\n${this._formatValue(d.value)}`);\n }\n\n\n // ----------------------------------------------------------------------- \n // ------------------------------ API ------------------------------\n // ----------------------------------------------------------------------- \n\n data(_) {\n return arguments.length ? (this._data = _, this) : this._data;\n };\n\n width(_) {\n return arguments.length ? (this._width = +_, this) : this._width;\n };\n\n height(_) {\n return arguments.length ? (this._height = +_, this) : this._height;\n };\n\n align(_) {\n return arguments.length ? (this._sankeyAlignType = _, this) : this._sankeyAlignType;\n }\n\n colorScheme(_) {\n return arguments.length ? (this._colorScheme = _, this) : this._colorScheme;\n }\n\n colorArray(_) {\n return arguments.length ? (this._colorArray = _, this) : this._colorArray;\n }\n\n edgeColor(_) {\n return arguments.length ? (this._edgeColor = _, this) : this._edgeColor;\n }\n\n displayValues(_) {\n return arguments.length ? (this._displayValues = _, this) : this._displayValues;\n }\n\n highlightOnHover(_) {\n return arguments.length ? (this._highlightOnHover = _, this) : this._highlightOnHover;\n }\n\n render() {\n if (!this._validate()) {\n // no graph data\n }\n else {\n this._init();\n this._renderSVG()\n }\n return this;\n }\n}\n","// @ts-nocheck\nimport React from 'react';\nimport { Icon } from '@grafana/ui';\n\nexport const ErrorMessage = ({ message }) => ( \n \n
\n \n)\n\nconst panelStyles = {\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center'\n}\n\nconst containerStyles = {\n padding: '15px 20px',\n marginBottom: '4px',\n position: 'relative',\n color: 'rgb(255, 255, 255)',\n textShadow: 'rgb(0 0 0 / 20%) 0px 1px 0px',\n borderRadius: '3px',\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n background: 'linear-gradient(90deg, rgb(224, 47, 68), rgb(224, 47, 68))'\n}\n\nconst messageStyles = {\n marginLeft: 10\n}\n","const SHOULD_LOG = true;\n\nexport const logger = fnLogger();\n\nfunction fnLogger(shouldLog = SHOULD_LOG) {\n if (!shouldLog) {\n return {\n warn: (..._: any[]) => undefined,\n error: (..._: any[]) => undefined,\n log: (..._: any[]) => undefined,\n };\n }\n\n return {\n warn: console.warn,\n error: console.error,\n log: console.log,\n };\n}\n","// @ts-nocheck\nimport React, { useState, useEffect } from 'react';\nimport * as d3 from 'd3';\nimport { PanelProps } from '@grafana/data';\nimport { SankeyOptions } from 'types';\nimport { Sankey } from 'Sankey'\nimport { ErrorMessage } from 'Error'\nimport { logger } from 'fn-logger';\n\ninterface Props extends PanelProps {}\n\nexport const SankeyPanel: React.FC = ({ options, data, width, height }) => {\n // ------------------------ CHART CONSTANTS -----------------------\n const CHART_REQUIRED_FIELDS = { source: 'source', target: 'target', value: 'value' };\n\n // ------------------------ ERROR MESSAGES ------------------------\n const requiredFieldsMsg = `Required fields not present: ${Object.keys(CHART_REQUIRED_FIELDS).join(', ')}`;\n const fieldTypeMsg = `Fields should have the following types: source (string), target (string), value (numeric)`;\n\n // ------------------------- REACT HOOKS --------------------------\n const [ error, setError ] = useState({ isError: false, message: '' })\n const [ graph, setGraph ] = useState({ nodes: [], links: [] })\n\n useEffect(() => {\n if (data.error) {\n logger.warn('[FN] Sankey data error.',{data, error: data.error})\n }\n\n data.error\n ?\n setError({isError: true, message: data.error.message})\n :\n setGraph(buildGraph())\n }, [data])\n\n // ------------------------- DATA ACQUISITION -------------------------\n const validate = (sources, targets, values) => {\n let isValid = true;\n\n // REQUIRED FIELDS\n if (!(sources && targets && values)) {\n setError({ isError: true, message: requiredFieldsMsg })\n return isValid = false;\n }\n\n // FIELD TYPES\n const sourcesString = sources.every(d => typeof d === 'string')\n const targetsString = targets.every(d => typeof d === 'string')\n const valuesNumeric = values.every(d => typeof d === 'number')\n\n if (!(sourcesString && targetsString && valuesNumeric)) {\n setError({ isError: true, message: fieldTypeMsg })\n return isValid = false;\n }\n\n setError({});\n\n return isValid;\n }\n\n const buildGraph = () => {\n const frame = data.series[0];\n\n const sourceAccesor = frame.fields.find(field => field.name === CHART_REQUIRED_FIELDS.source);\n const targetAccesor = frame.fields.find(field => field.name === CHART_REQUIRED_FIELDS.target);\n const valueAccesor = frame.fields.find(field => field.name === CHART_REQUIRED_FIELDS.value);\n\n const sources = sourceAccesor?.values.toArray();\n const targets = targetAccesor?.values.toArray();\n const values = valueAccesor?.values.toArray();\n\n const isValid = validate(sources, targets, values);\n if (!isValid) {return}\n\n const zip = d3.zip(sources, targets, values);\n\n const nodes = Array.from(new Set(sources.concat(targets))).map(node => ({ name: node }));\n const links = zip.map(d => ({ source: d[0], target: d[1], value: +d[2].toFixed(2) }));\n const graph = { nodes, links };\n\n return graph\n }\n\n // ------------------------------- CHART ------------------------------\n const chart = svg => {\n const sankey = new Sankey(svg)\n .width(width)\n .height(height)\n .align(options.align)\n .edgeColor(options.edgeColor)\n .colorScheme(options.colorScheme)\n .displayValues(options.displayValues)\n .highlightOnHover(options.highlightOnHover)\n .colorArray(options.colorArray)\n .data(graph)\n\n try {\n sankey.render();\n } catch (renderError) {\n logger.warn('[FN] Sankey render error.',{renderError, graph})\n\n setError({isError: true, message: renderError.message})\n }\n };\n\n return (error.isError ?\n \n :\n {\n d3.select(node)\n .selectAll('*')\n .remove();\n d3.select(node).call(chart);\n }}\n />\n );\n};\n","// NOTE: implementation of toDataFrame: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/dataframe/processDataFrame.ts\nimport { toDataFrame, FieldType, ArrayVector, Field } from '@grafana/data';\nimport { logger } from 'fn-logger';\n\nimport { SankeyOptionsFn } from 'types-fn';\n\nexport function transformFnData(): Required['transformFn'] {\n return ({ series, ...other }) => {\n const transformedSeries = series.map((data) => {\n return toDataFrame({ ...data, fields: data.fields.map(mapField()) });\n });\n\n return {\n series: transformedSeries,\n ...other,\n };\n };\n}\n\nconst SANKEY_FIELD_NAMES = ['source', 'target', 'value'];\n\n// @ts-ignore\nfunction mapField() {\n return (field: Field
, _: number, __: Array>) => {\n const isSankeyField = SANKEY_FIELD_NAMES.includes(field.name);\n\n const isArrayVector = field.values instanceof ArrayVector || typeof field.values?.toArray === 'function';\n const isArray = Array.isArray(field.values);\n\n if (!isSankeyField || !field.values || (!isArray && !isArrayVector)) {\n return field;\n }\n\n const values = isArrayVector ? field.values.toArray() : isArray ? field.values : null;\n\n if (values === null) {\n logger.warn('[FN] Failed to transform sankey data.', 'Values are not an array.');\n\n return {\n ...field,\n values: new ArrayVector([]),\n };\n }\n\n const parsedValues = isSankeyField ? ((values as P[]).map(splitValue())[0] as unknown[]).map(mapToNumber()) : null;\n\n try {\n return {\n ...field,\n type: parsedValues?.every(isNumber()) ? FieldType.number : field.type,\n values: parsedValues ? new ArrayVector(JSON.parse(JSON.stringify(parsedValues))) : values,\n };\n } catch (err) {\n logger.warn('[FN] Failed to transform sankey data.', err instanceof Error ? err.message : String(err));\n\n return {\n ...field,\n type: field.type,\n values: new ArrayVector([]),\n };\n }\n };\n}\n\n// @ts-ignore\nfunction mapToNumber() {\n return (value: V, _: number, __: V[]) => (Number.isNaN(Number(value)) ? value : Number(value));\n}\n\n// @ts-ignore\nfunction splitValue() {\n return (value: V) => (typeof value === 'string' ? value.split('|') : value);\n}\n\n// @ts-ignore\nfunction isNumber() {\n return (value: V) => typeof value === 'number';\n}\n","import { PanelPlugin } from '@grafana/data';\nimport { SankeyOptionsFn } from 'types-fn';\nimport { SankeyPanelFn as SankeyPanel } from './SankeyPanelFn';\n\nexport const plugin = new PanelPlugin